[MERGE] from trunk-mail-concreting-tde, TODO fix bug

bzr revid: chm@openerp.com-20121029090847-27h3tmyvsv9c8vej
This commit is contained in:
Christophe Matthieu 2012-10-29 10:08:47 +01:00
commit 46a60cdac7
200 changed files with 1694 additions and 1223 deletions

View File

@ -1007,7 +1007,7 @@ class account_period(osv.osv):
'date_stop': fields.date('End of Period', required=True, states={'done':[('readonly',True)]}), 'date_stop': fields.date('End of Period', required=True, states={'done':[('readonly',True)]}),
'fiscalyear_id': fields.many2one('account.fiscalyear', 'Fiscal Year', required=True, states={'done':[('readonly',True)]}, select=True), 'fiscalyear_id': fields.many2one('account.fiscalyear', 'Fiscal Year', required=True, states={'done':[('readonly',True)]}, select=True),
'state': fields.selection([('draft','Open'), ('done','Closed')], 'Status', readonly=True, 'state': fields.selection([('draft','Open'), ('done','Closed')], 'Status', readonly=True,
help='When monthly periods are created. The state is \'Draft\'. At the end of monthly period it is in \'Done\' state.'), help='When monthly periods are created. The status is \'Draft\'. At the end of monthly period it is in \'Done\' status.'),
'company_id': fields.related('fiscalyear_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True) 'company_id': fields.related('fiscalyear_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True)
} }
_defaults = { _defaults = {
@ -1134,7 +1134,7 @@ class account_journal_period(osv.osv):
'icon': fields.function(_icon_get, string='Icon', type='char', size=32), 'icon': fields.function(_icon_get, string='Icon', type='char', size=32),
'active': fields.boolean('Active', required=True, help="If the active field is set to False, it will allow you to hide the journal period without removing it."), 'active': fields.boolean('Active', required=True, help="If the active field is set to False, it will allow you to hide the journal period without removing it."),
'state': fields.selection([('draft','Draft'), ('printed','Printed'), ('done','Done')], 'Status', required=True, readonly=True, 'state': fields.selection([('draft','Draft'), ('printed','Printed'), ('done','Done')], 'Status', required=True, readonly=True,
help='When journal period is created. The state is \'Draft\'. If a report is printed it comes to \'Printed\' state. When all transactions are done, it comes in \'Done\' state.'), help='When journal period is created. The status is \'Draft\'. If a report is printed it comes to \'Printed\' status. When all transactions are done, it comes in \'Done\' status.'),
'fiscalyear_id': fields.related('period_id', 'fiscalyear_id', string='Fiscal Year', type='many2one', relation='account.fiscalyear'), 'fiscalyear_id': fields.related('period_id', 'fiscalyear_id', string='Fiscal Year', type='many2one', relation='account.fiscalyear'),
'company_id': fields.related('journal_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True) 'company_id': fields.related('journal_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True)
} }
@ -1282,7 +1282,7 @@ class account_move(osv.osv):
'period_id': fields.many2one('account.period', 'Period', required=True, states={'posted':[('readonly',True)]}), 'period_id': fields.many2one('account.period', 'Period', required=True, states={'posted':[('readonly',True)]}),
'journal_id': fields.many2one('account.journal', 'Journal', required=True, states={'posted':[('readonly',True)]}), 'journal_id': fields.many2one('account.journal', 'Journal', required=True, states={'posted':[('readonly',True)]}),
'state': fields.selection([('draft','Unposted'), ('posted','Posted')], 'Status', required=True, readonly=True, 'state': fields.selection([('draft','Unposted'), ('posted','Posted')], 'Status', required=True, readonly=True,
help='All manually created new journal entries are usually in the state \'Unposted\', but you can set the option to skip that state on the related journal. In that case, they will behave as journal entries automatically created by the system on document validation (invoices, bank statements...) and will be created in \'Posted\' state.'), help='All manually created new journal entries are usually in the status \'Unposted\', but you can set the option to skip that status on the related journal. In that case, they will behave as journal entries automatically created by the system on document validation (invoices, bank statements...) and will be created in \'Posted\' status.'),
'line_id': fields.one2many('account.move.line', 'move_id', 'Entries', states={'posted':[('readonly',True)]}), 'line_id': fields.one2many('account.move.line', 'move_id', 'Entries', states={'posted':[('readonly',True)]}),
'to_check': fields.boolean('To Review', help='Check this box if you are unsure of that journal entry and if you want to note it as \'to be reviewed\' by an accounting expert.'), 'to_check': fields.boolean('To Review', help='Check this box if you are unsure of that journal entry and if you want to note it as \'to be reviewed\' by an accounting expert.'),
'partner_id': fields.related('line_id', 'partner_id', type="many2one", relation="res.partner", string="Partner", store=True), 'partner_id': fields.related('line_id', 'partner_id', type="many2one", relation="res.partner", string="Partner", store=True),

View File

@ -123,8 +123,8 @@ class account_bank_statement(osv.osv):
('open','Open'), # used by cash statements ('open','Open'), # used by cash statements
('confirm', 'Closed')], ('confirm', 'Closed')],
'Status', required=True, readonly="1", 'Status', required=True, readonly="1",
help='When new statement is created the state will be \'Draft\'.\n' help='When new statement is created the status will be \'Draft\'.\n'
'And after getting confirmation from the bank it will be in \'Confirmed\' state.'), 'And after getting confirmation from the bank it will be in \'Confirmed\' status.'),
'currency': fields.function(_currency, string='Currency', 'currency': fields.function(_currency, string='Currency',
type='many2one', relation='res.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.'), '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.'),

View File

@ -207,12 +207,12 @@ class account_invoice(osv.osv):
('open','Open'), ('open','Open'),
('paid','Paid'), ('paid','Paid'),
('cancel','Cancelled'), ('cancel','Cancelled'),
],'State', select=True, readonly=True, ],'Status', select=True, readonly=True,
help=' * The \'Draft\' state is used when a user is encoding a new and unconfirmed Invoice. \ help=' * The \'Draft\' status is used when a user is encoding a new and unconfirmed Invoice. \
\n* The \'Pro-forma\' when invoice is in Pro-forma state,invoice does not have an invoice number. \ \n* The \'Pro-forma\' when invoice is in Pro-forma status,invoice does not have an invoice number. \
\n* The \'Open\' state is used when user create invoice,a invoice number is generated.Its in open state till user does not pay invoice. \ \n* The \'Open\' status is used when user create invoice,a invoice number is generated.Its in open status till user does not pay invoice. \
\n* The \'Paid\' state is set automatically when the invoice is paid. Its related journal entries may or may not be reconciled. \ \n* The \'Paid\' status is set automatically when the invoice is paid. Its related journal entries may or may not be reconciled. \
\n* The \'Cancelled\' state is used when user cancel invoice.'), \n* The \'Cancelled\' status is used when user cancel invoice.'),
'sent': fields.boolean('Sent', readonly=True, help="It indicates that the invoice has been sent."), 'sent': fields.boolean('Sent', readonly=True, help="It indicates that the invoice has been sent."),
'date_invoice': fields.date('Invoice Date', readonly=True, states={'draft':[('readonly',False)]}, select=True, help="Keep empty to use the current date"), 'date_invoice': fields.date('Invoice Date', readonly=True, states={'draft':[('readonly',False)]}, select=True, help="Keep empty to use the current date"),
'date_due': fields.date('Due Date', readonly=True, states={'draft':[('readonly',False)]}, select=True, 'date_due': fields.date('Due Date', readonly=True, states={'draft':[('readonly',False)]}, select=True,
@ -1360,7 +1360,7 @@ class account_invoice_line(osv.osv):
_description = "Invoice Line" _description = "Invoice Line"
_columns = { _columns = {
'name': fields.text('Description', required=True), 'name': fields.text('Description', required=True),
'origin': fields.char('Source', size=256, help="Reference of the document that produced this invoice."), 'origin': fields.char('Source Document', size=256, help="Reference of the document that produced this invoice."),
'sequence': fields.integer('Sequence', help="Gives the sequence of this line when displaying the invoice."), 'sequence': fields.integer('Sequence', help="Gives the sequence of this line when displaying the invoice."),
'invoice_id': fields.many2one('account.invoice', 'Invoice Reference', ondelete='cascade', select=True), 'invoice_id': fields.many2one('account.invoice', 'Invoice Reference', ondelete='cascade', select=True),
'uos_id': fields.many2one('product.uom', 'Unit of Measure', ondelete='set null'), 'uos_id': fields.many2one('product.uom', 'Unit of Measure', ondelete='set null'),

View File

@ -1862,7 +1862,7 @@
<field name="model_id"/> <field name="model_id"/>
<group expand="0" string="Group By..."> <group expand="0" string="Group By...">
<filter string="Model" icon="terp-folder-orange" domain="[]" context="{'group_by':'model_id'}"/> <filter string="Model" icon="terp-folder-orange" domain="[]" context="{'group_by':'model_id'}"/>
<filter string="State" icon="terp-stock_effects-object-colorize" domain="[]" context="{'group_by':'state'}"/> <filter string="Status" icon="terp-stock_effects-object-colorize" domain="[]" context="{'group_by':'state'}"/>
</group> </group>
</search> </search>
</field> </field>
@ -2414,32 +2414,6 @@
<field name="view_mode">form</field> <field name="view_mode">form</field>
<field name="target">new</field> <field name="target">new</field>
</record> </record>
<record id="ir_actions_server_action_wizard_multi_chart" model="ir.actions.server">
<field name="type">ir.actions.server</field>
<field name="condition">True</field>
<field name="state">code</field>
<field name="model_id" ref="base.model_ir_actions_todo"/>
<field eval="5" name="sequence"/>
<field name="code">
# check for unconfigured companies
account_installer_obj = self.pool.get('account.installer')
account_installer_obj.check_unconfigured_cmp(cr, uid, context=context)
action_ids = []
# fetch the act_window actions related to chart of account configuration
# we use ir.actions.todo to enable the possibility for other modules to insert their own
# wizards during the configuration process
ref = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'account', 'action_wizard_multi_chart')
if ref:
action_ids += [ref[1]]
ref = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'account', 'action_account_configuration_installer')
if ref:
action_ids += [ref[1]]
todo_ids = pool.get('ir.actions.todo').search(cr, uid, [('action_id', 'in', action_ids)], context=context)
pool.get('ir.actions.todo').write(cr, uid, todo_ids, {'state':'open'}, context=context)
action = pool.get('res.config').next(cr, uid, [], context)
</field>
<field name="name">New Company Financial Setting</field>
</record>
<record id="account_account_graph" model="ir.ui.view"> <record id="account_account_graph" model="ir.ui.view">
<field name="name">account.account.graph</field> <field name="name">account.account.graph</field>

File diff suppressed because it is too large Load Diff

View File

@ -119,15 +119,6 @@ class account_installer(osv.osv_memory):
self.execute_simple(cr, uid, ids, context) self.execute_simple(cr, uid, ids, context)
super(account_installer, self).execute(cr, uid, ids, context=context) super(account_installer, self).execute(cr, uid, ids, context=context)
def action_next(self, cr, uid, ids, context=None):
next = self.execute(cr, uid, ids, context=context)
for installer in self.browse(cr, uid, ids, context=context):
if installer.charts == 'l10n_be':
return {'type': 'ir.actions.act_window_close'}
else :
if next : return next
return self.next(cr, uid, ids, context=context)
def execute_simple(self, cr, uid, ids, context=None): def execute_simple(self, cr, uid, ids, context=None):
if context is None: if context is None:
context = {} context = {}

View File

@ -91,7 +91,7 @@ class account_invoice_report(osv.osv):
('open','Open'), ('open','Open'),
('paid','Done'), ('paid','Done'),
('cancel','Cancelled') ('cancel','Cancelled')
], 'Invoice State', readonly=True), ], 'Invoice Status', readonly=True),
'date_due': fields.date('Due Date', readonly=True), 'date_due': fields.date('Due Date', readonly=True),
'account_id': fields.many2one('account.account', 'Account',readonly=True), 'account_id': fields.many2one('account.account', 'Account',readonly=True),
'account_line_id': fields.many2one('account.account', 'Account Line',readonly=True), 'account_line_id': fields.many2one('account.account', 'Account Line',readonly=True),

View File

@ -7,14 +7,14 @@ msgstr ""
"Project-Id-Version: OpenERP Server 6.0dev\n" "Project-Id-Version: OpenERP Server 6.0dev\n"
"Report-Msgid-Bugs-To: support@openerp.com\n" "Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-02-08 00:35+0000\n" "POT-Creation-Date: 2012-02-08 00:35+0000\n"
"PO-Revision-Date: 2011-04-15 19:38+0000\n" "PO-Revision-Date: 2012-10-25 12:32+0000\n"
"Last-Translator: Chertykov Denis <chertykov@gmail.com>\n" "Last-Translator: Chertykov Denis <chertykov@gmail.com>\n"
"Language-Team: \n" "Language-Team: \n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-10-19 05:15+0000\n" "X-Launchpad-Export-Date: 2012-10-26 04:56+0000\n"
"X-Generator: Launchpad (build 16165)\n" "X-Generator: Launchpad (build 16194)\n"
#. module: account_analytic_plans #. module: account_analytic_plans
#: view:analytic.plan.create.model:0 #: view:analytic.plan.create.model:0
@ -136,7 +136,7 @@ msgstr "Определить аналитический план счетов"
#. module: account_analytic_plans #. module: account_analytic_plans
#: constraint:account.invoice:0 #: constraint:account.invoice:0
msgid "Invalid BBA Structured Communication !" msgid "Invalid BBA Structured Communication !"
msgstr "" msgstr "Неверна структурная связь BBA!"
#. module: account_analytic_plans #. module: account_analytic_plans
#: constraint:account.bank.statement:0 #: constraint:account.bank.statement:0
@ -149,6 +149,8 @@ msgid ""
"The date of your Journal Entry is not in the defined period! You should " "The date of your Journal Entry is not in the defined period! You should "
"change the date or remove this constraint from the journal." "change the date or remove this constraint from the journal."
msgstr "" msgstr ""
"Дата проводки в журнале не в определённом периоде! Вы должны сменить дату "
"или удалить это ограничение из журнала."
#. module: account_analytic_plans #. module: account_analytic_plans
#: sql_constraint:account.journal:0 #: sql_constraint:account.journal:0
@ -251,6 +253,8 @@ msgid ""
"currency. You should remove the secondary currency on the account or select " "currency. You should remove the secondary currency on the account or select "
"a multi-currency view on the journal." "a multi-currency view on the journal."
msgstr "" msgstr ""
"Выбранный счёт проводки в журнале нуждается во вторичной валюте. Вы должны "
"удалить вторичную валюту по счёту или выбрать мульти-валютный вид по журналу."
#. module: account_analytic_plans #. module: account_analytic_plans
#: report:account.analytic.account.crossovered.analytic:0 #: report:account.analytic.account.crossovered.analytic:0
@ -429,7 +433,7 @@ msgstr "Счет 4 уровня"
#. module: account_analytic_plans #. module: account_analytic_plans
#: constraint:account.move.line:0 #: constraint:account.move.line:0
msgid "Company must be the same for its related account and period." msgid "Company must be the same for its related account and period."
msgstr "" msgstr "Для счета и периода должна быть одна компания."
#. module: account_analytic_plans #. module: account_analytic_plans
#: view:account.analytic.plan.instance.line:0 #: view:account.analytic.plan.instance.line:0
@ -515,11 +519,14 @@ msgid ""
"analytic accounts for each plan set. Then, you must attach a plan set to " "analytic accounts for each plan set. Then, you must attach a plan set to "
"your account journals." "your account journals."
msgstr "" msgstr ""
"Для настройки нескольких планов счетов аналитики, вы должны определить "
"корневые счета аналитики для каждого набора плана. Затем вы можете "
"прикрепить набор плана к вашим учётным журналам."
#. module: account_analytic_plans #. module: account_analytic_plans
#: constraint:account.move.line:0 #: constraint:account.move.line:0
msgid "You can not create journal items on closed account." msgid "You can not create journal items on closed account."
msgstr "" msgstr "Нельзя создать элемент журнала по закрытому счету ."
#. module: account_analytic_plans #. module: account_analytic_plans
#: report:account.analytic.account.crossovered.analytic:0 #: report:account.analytic.account.crossovered.analytic:0

View File

@ -226,9 +226,9 @@ class account_asset_asset(osv.osv):
'child_ids': fields.one2many('account.asset.asset', 'parent_id', 'Children Assets'), 'child_ids': fields.one2many('account.asset.asset', 'parent_id', 'Children Assets'),
'purchase_date': fields.date('Purchase Date', required=True, readonly=True, states={'draft':[('readonly',False)]}), 'purchase_date': fields.date('Purchase Date', required=True, readonly=True, states={'draft':[('readonly',False)]}),
'state': fields.selection([('draft','Draft'),('open','Running'),('close','Close')], 'Status', required=True, 'state': fields.selection([('draft','Draft'),('open','Running'),('close','Close')], 'Status', required=True,
help="When an asset is created, the state is 'Draft'.\n" \ help="When an asset is created, the status is 'Draft'.\n" \
"If the asset is confirmed, the state goes in 'Running' and the depreciation lines can be posted in the accounting.\n" \ "If the asset is confirmed, the status goes in 'Running' and the depreciation lines can be posted in the accounting.\n" \
"You can manually close an asset when the depreciation is over. If the last line of depreciation is posted, the asset automatically goes in that state."), "You can manually close an asset when the depreciation is over. If the last line of depreciation is posted, the asset automatically goes in that status."),
'active': fields.boolean('Active'), 'active': fields.boolean('Active'),
'partner_id': fields.many2one('res.partner', 'Partner', readonly=True, states={'draft':[('readonly',False)]}), 'partner_id': fields.many2one('res.partner', 'Partner', readonly=True, states={'draft':[('readonly',False)]}),
'method': fields.selection([('linear','Linear'),('degressive','Degressive')], 'Computation Method', required=True, readonly=True, states={'draft':[('readonly',False)]}, help="Choose the method to use to compute the amount of depreciation lines.\n"\ 'method': fields.selection([('linear','Linear'),('degressive','Degressive')], 'Computation Method', required=True, readonly=True, states={'draft':[('readonly',False)]}, help="Choose the method to use to compute the amount of depreciation lines.\n"\

View File

@ -0,0 +1,199 @@
# Polish translation for openobject-addons
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
# This file is distributed under the same license as the openobject-addons package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-02-08 00:35+0000\n"
"PO-Revision-Date: 2012-10-25 16:56+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Polish <pl@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-10-26 04:56+0000\n"
"X-Generator: Launchpad (build 16194)\n"
#. module: account_check_writing
#: selection:res.company,check_layout:0
msgid "Check on Top"
msgstr ""
#. module: account_check_writing
#: model:ir.actions.act_window,help:account_check_writing.action_write_check
msgid ""
"The check payment form allows you to track the payment you do to your "
"suppliers specially by check. When you select a supplier, the payment method "
"and an amount for the payment, OpenERP will propose to reconcile your "
"payment with the open supplier invoices or bills.You can print the check"
msgstr ""
#. module: account_check_writing
#: view:account.voucher:0
#: model:ir.actions.report.xml,name:account_check_writing.account_print_check_bottom
#: model:ir.actions.report.xml,name:account_check_writing.account_print_check_middle
#: model:ir.actions.report.xml,name:account_check_writing.account_print_check_top
msgid "Print Check"
msgstr ""
#. module: account_check_writing
#: selection:res.company,check_layout:0
msgid "Check in middle"
msgstr ""
#. module: account_check_writing
#: help:res.company,check_layout:0
msgid ""
"Check on top is compatible with Quicken, QuickBooks and Microsoft Money. "
"Check in middle is compatible with Peachtree, ACCPAC and DacEasy. Check on "
"bottom is compatible with Peachtree, ACCPAC and DacEasy only"
msgstr ""
#. module: account_check_writing
#: selection:res.company,check_layout:0
msgid "Check on bottom"
msgstr ""
#. module: account_check_writing
#: constraint:res.company:0
msgid "Error! You can not create recursive companies."
msgstr ""
#. module: account_check_writing
#: help:account.journal,allow_check_writing:0
msgid "Check this if the journal is to be used for writing checks."
msgstr ""
#. module: account_check_writing
#: field:account.journal,allow_check_writing:0
msgid "Allow Check writing"
msgstr ""
#. module: account_check_writing
#: report:account.print.check.bottom:0
#: report:account.print.check.middle:0
#: report:account.print.check.top:0
msgid "Description"
msgstr "Opis"
#. module: account_check_writing
#: model:ir.model,name:account_check_writing.model_account_journal
msgid "Journal"
msgstr "Dziennik"
#. module: account_check_writing
#: model:ir.actions.act_window,name:account_check_writing.action_write_check
#: model:ir.ui.menu,name:account_check_writing.menu_action_write_check
msgid "Write Checks"
msgstr ""
#. module: account_check_writing
#: report:account.print.check.bottom:0
#: report:account.print.check.middle:0
#: report:account.print.check.top:0
msgid "Discount"
msgstr ""
#. module: account_check_writing
#: report:account.print.check.bottom:0
#: report:account.print.check.middle:0
#: report:account.print.check.top:0
msgid "Original Amount"
msgstr ""
#. module: account_check_writing
#: view:res.company:0
msgid "Configuration"
msgstr "Konfiguracja"
#. module: account_check_writing
#: field:account.voucher,allow_check:0
msgid "Allow Check Writing"
msgstr ""
#. module: account_check_writing
#: report:account.print.check.bottom:0
#: report:account.print.check.middle:0
#: report:account.print.check.top:0
msgid "Payment"
msgstr ""
#. module: account_check_writing
#: field:account.journal,use_preprint_check:0
msgid "Use Preprinted Check"
msgstr ""
#. module: account_check_writing
#: sql_constraint:res.company:0
msgid "The company name must be unique !"
msgstr ""
#. module: account_check_writing
#: report:account.print.check.bottom:0
#: report:account.print.check.middle:0
#: report:account.print.check.top:0
msgid "Due Date"
msgstr ""
#. module: account_check_writing
#: model:ir.model,name:account_check_writing.model_res_company
msgid "Companies"
msgstr ""
#. module: account_check_writing
#: view:res.company:0
msgid "Default Check Layout"
msgstr ""
#. module: account_check_writing
#: constraint:account.journal:0
msgid ""
"Configuration error! The currency chosen should be shared by the default "
"accounts too."
msgstr ""
#. module: account_check_writing
#: report:account.print.check.bottom:0
#: report:account.print.check.middle:0
msgid "Balance Due"
msgstr ""
#. module: account_check_writing
#: report:account.print.check.bottom:0
#: report:account.print.check.middle:0
#: report:account.print.check.top:0
msgid "Check Amount"
msgstr ""
#. module: account_check_writing
#: model:ir.model,name:account_check_writing.model_account_voucher
msgid "Accounting Voucher"
msgstr ""
#. module: account_check_writing
#: sql_constraint:account.journal:0
msgid "The name of the journal must be unique per company !"
msgstr ""
#. module: account_check_writing
#: sql_constraint:account.journal:0
msgid "The code of the journal must be unique per company !"
msgstr ""
#. module: account_check_writing
#: field:account.voucher,amount_in_word:0
msgid "Amount in Word"
msgstr ""
#. module: account_check_writing
#: report:account.print.check.top:0
msgid "Open Balance"
msgstr ""
#. module: account_check_writing
#: field:res.company,check_layout:0
msgid "Choose Check layout"
msgstr ""

View File

@ -19,11 +19,14 @@
# #
############################################################################## ##############################################################################
import logging
import time import time
from osv import osv, fields from osv import osv, fields
import netsvc import netsvc
_logger = logging.getLogger(__name__)
class payment_mode(osv.osv): class payment_mode(osv.osv):
_name= 'payment.mode' _name= 'payment.mode'
_description= 'Payment Mode' _description= 'Payment Mode'
@ -70,9 +73,7 @@ class payment_order(osv.osv):
#dead code #dead code
def get_wizard(self, type): def get_wizard(self, type):
logger = netsvc.Logger() _logger.warning("No wizard found for the payment type '%s'.", type)
logger.notifyChannel("Warning!", netsvc.LOG_WARNING,
"No wizard is found for the payment type '%s'." % type)
return None return None
def _total(self, cursor, user, ids, name, args, context=None): def _total(self, cursor, user, ids, name, args, context=None):
@ -95,7 +96,7 @@ class payment_order(osv.osv):
('cancel', 'Cancelled'), ('cancel', 'Cancelled'),
('open', 'Confirmed'), ('open', 'Confirmed'),
('done', 'Done')], 'Status', select=True, ('done', 'Done')], 'Status', select=True,
help='When an order is placed the state is \'Draft\'.\n Once the bank is confirmed the state is set to \'Confirmed\'.\n Then the order is paid the state is \'Done\'.'), help='When an order is placed the status is \'Draft\'.\n Once the bank is confirmed the status is set to \'Confirmed\'.\n Then the order is paid the status is \'Done\'.'),
'line_ids': fields.one2many('payment.line', 'order_id', 'Payment lines', states={'done': [('readonly', True)]}), 'line_ids': fields.one2many('payment.line', 'order_id', 'Payment lines', states={'done': [('readonly', True)]}),
'total': fields.function(_total, string="Total", type='float'), 'total': fields.function(_total, string="Total", type='float'),
'user_id': fields.many2one('res.users', 'Responsible', required=True, states={'done': [('readonly', True)]}), 'user_id': fields.many2one('res.users', 'Responsible', required=True, states={'done': [('readonly', True)]}),

View File

@ -293,10 +293,10 @@ class account_voucher(osv.osv):
('proforma','Pro-forma'), ('proforma','Pro-forma'),
('posted','Posted') ('posted','Posted')
], 'Status', readonly=True, size=32, ], 'Status', readonly=True, size=32,
help=' * The \'Draft\' state is used when a user is encoding a new and unconfirmed Voucher. \ help=' * The \'Draft\' status is used when a user is encoding a new and unconfirmed Voucher. \
\n* The \'Pro-forma\' when voucher is in Pro-forma state,voucher does not have an voucher number. \ \n* The \'Pro-forma\' when voucher is in Pro-forma status,voucher does not have an voucher number. \
\n* The \'Posted\' state is used when user create voucher,a voucher number is generated and voucher entries are created in account \ \n* The \'Posted\' status is used when user create voucher,a voucher number is generated and voucher entries are created in account \
\n* The \'Cancelled\' state is used when user cancel voucher.'), \n* The \'Cancelled\' status is used when user cancel voucher.'),
'amount': fields.float('Total', digits_compute=dp.get_precision('Account'), required=True, readonly=True, states={'draft':[('readonly',False)]}), 'amount': fields.float('Total', digits_compute=dp.get_precision('Account'), required=True, readonly=True, states={'draft':[('readonly',False)]}),
'tax_amount':fields.float('Tax Amount', digits_compute=dp.get_precision('Account'), readonly=True, states={'draft':[('readonly',False)]}), 'tax_amount':fields.float('Tax Amount', digits_compute=dp.get_precision('Account'), readonly=True, states={'draft':[('readonly',False)]}),
'reference': fields.char('Ref #', size=64, readonly=True, states={'draft':[('readonly',False)]}, help="Transaction reference number."), 'reference': fields.char('Ref #', size=64, readonly=True, states={'draft':[('readonly',False)]}, help="Transaction reference number."),

View File

@ -52,7 +52,7 @@ class sale_receipt_report(osv.osv):
('proforma','Pro-forma'), ('proforma','Pro-forma'),
('posted','Posted'), ('posted','Posted'),
('cancel','Cancelled') ('cancel','Cancelled')
], 'Voucher State', readonly=True), ], 'Voucher Status', readonly=True),
'pay_now':fields.selection([ 'pay_now':fields.selection([
('pay_now','Pay Directly'), ('pay_now','Pay Directly'),
('pay_later','Pay Later or Group Funds'), ('pay_later','Pay Later or Group Funds'),

View File

@ -64,7 +64,7 @@
<button name="proforma_voucher" string="Validate" states="draft" class="oe_highlight"/> <button name="proforma_voucher" string="Validate" states="draft" class="oe_highlight"/>
<button name="%(act_pay_voucher)d" context="{'narration':narration, 'title':'Customer Payment', 'type':'receipt', 'partner_id':partner_id, 'reference':reference, 'amount':amount}" type="action" string="Pay" attrs="{'invisible':['|',('pay_now','=','pay_now'),'|',('state','=','draft'), ('paid','=',True)]}" class="oe_highlight"/> <button name="%(act_pay_voucher)d" context="{'narration':narration, 'title':'Customer Payment', 'type':'receipt', 'partner_id':partner_id, 'reference':reference, 'amount':amount}" type="action" string="Pay" attrs="{'invisible':['|',('pay_now','=','pay_now'),'|',('state','=','draft'), ('paid','=',True)]}" class="oe_highlight"/>
<button name="cancel_voucher" string="Cancel" states="draft,proforma" /> <button name="cancel_voucher" string="Cancel" states="draft,proforma" />
<button name="cancel_voucher" string="Cancel" type="object" states="posted" confirm="Are you sure to confirm this record ?"/> <button name="cancel_voucher" string="Cancel" type="object" states="posted" confirm="Are you sure you want to cancel this receipt?"/>
<button name="action_cancel_draft" type="object" states="cancel" string="Set to Draft"/> <button name="action_cancel_draft" type="object" states="cancel" string="Set to Draft"/>
<field name="state" widget="statusbar" statusbar_visible="draft,posted" statusbar_colors='{"proforma":"blue"}'/> <field name="state" widget="statusbar" statusbar_visible="draft,posted" statusbar_colors='{"proforma":"blue"}'/>
</header> </header>
@ -209,7 +209,7 @@
<button name="proforma_voucher" string="Validate" states="draft" class="oe_highlight"/> <button name="proforma_voucher" string="Validate" states="draft" class="oe_highlight"/>
<button name="%(act_pay_bills)d" context="{'narration':narration, 'title':'Bill Payment', 'type':'payment', 'partner_id': partner_id, 'reference':reference}" type="action" string="Pay Bill" attrs="{'invisible':['|',('pay_now','=','pay_now'),'|',('state','=','draft'), ('paid','=',True)]}" class="oe_highlight"/> <button name="%(act_pay_bills)d" context="{'narration':narration, 'title':'Bill Payment', 'type':'payment', 'partner_id': partner_id, 'reference':reference}" type="action" string="Pay Bill" attrs="{'invisible':['|',('pay_now','=','pay_now'),'|',('state','=','draft'), ('paid','=',True)]}" class="oe_highlight"/>
<button name="cancel_voucher" string="Cancel" states="draft,proforma" /> <button name="cancel_voucher" string="Cancel" states="draft,proforma" />
<button name="cancel_voucher" string="Cancel" type="object" states="posted" confirm="Are you sure to confirm this record ?"/> <button name="cancel_voucher" string="Cancel" type="object" states="posted" confirm="Are you sure you want to cancel this receipt?"/>
<button name="action_cancel_draft" type="object" states="cancel" string="Set to Draft"/> <button name="action_cancel_draft" type="object" states="cancel" string="Set to Draft"/>
<field name="state" widget="statusbar" statusbar_visible="draft,posted" statusbar_colors='{"proforma":"blue"}'/> <field name="state" widget="statusbar" statusbar_visible="draft,posted" statusbar_colors='{"proforma":"blue"}'/>
</header> </header>

View File

@ -255,27 +255,27 @@ class account_analytic_account(osv.osv):
if context is None: if context is None:
context={} context={}
if context.get('current_model') == 'project.project': if context.get('current_model') == 'project.project':
cr.execute("select analytic_account_id from project_project") project_obj = self.pool.get("account.analytic.account")
project_ids = [x[0] for x in cr.fetchall()] project_ids = project_obj.search(cr, uid, args)
return self.name_get(cr, uid, project_ids, context=context) return self.name_get(cr, uid, project_ids, context=context)
if name: if name:
account = self.search(cr, uid, [('code', '=', name)] + args, limit=limit, context=context) account_ids = self.search(cr, uid, [('code', '=', name)] + args, limit=limit, context=context)
if not account: if not account_ids:
names=map(lambda i : i.strip(),name.split('/')) names=map(lambda i : i.strip(),name.split('/'))
for i in range(len(names)): for i in range(len(names)):
dom=[('name', operator, names[i])] dom=[('name', operator, names[i])]
if i>0: if i>0:
dom+=[('id','child_of',account)] dom+=[('id','child_of',account_ids)]
account = self.search(cr, uid, dom, limit=limit, context=context) account_ids = self.search(cr, uid, dom, limit=limit, context=context)
newacc = account newacc = account_ids
while newacc: while newacc:
newacc = self.search(cr, uid, [('parent_id', 'in', newacc)], limit=limit, context=context) newacc = self.search(cr, uid, [('parent_id', 'in', newacc)], limit=limit, context=context)
account += newacc account_ids += newacc
if args: if args:
account = self.search(cr, uid, [('id', 'in', account)] + args, limit=limit, context=context) account_ids = self.search(cr, uid, [('id', 'in', account_ids)] + args, limit=limit, context=context)
else: else:
account = self.search(cr, uid, args, limit=limit, context=context) account_ids = self.search(cr, uid, args, limit=limit, context=context)
return self.name_get(cr, uid, account, context=context) return self.name_get(cr, uid, account_ids, context=context)
def create(self, cr, uid, vals, context=None): def create(self, cr, uid, vals, context=None):
contract = super(account_analytic_account, self).create(cr, uid, vals, context=context) contract = super(account_analytic_account, self).create(cr, uid, vals, context=context)

View File

@ -0,0 +1,112 @@
# Polish translation for openobject-addons
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
# This file is distributed under the same license as the openobject-addons package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-02-08 01:37+0100\n"
"PO-Revision-Date: 2012-10-25 17:11+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Polish <pl@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-10-26 04:56+0000\n"
"X-Generator: Launchpad (build 16194)\n"
#. #-#-#-#-# auth_openid.pot (OpenERP Server 6.1rc1) #-#-#-#-#
#. module: auth_openid
#. #-#-#-#-# auth_openid.pot.web (PROJECT VERSION) #-#-#-#-#
#. openerp-web
#: view:res.users:0
#: /home/odo/repositories/addons/trunk/auth_openid/static/src/xml/auth_openid.xml:12
msgid "OpenID"
msgstr ""
#. #-#-#-#-# auth_openid.pot (OpenERP Server 6.1rc1) #-#-#-#-#
#. module: auth_openid
#. #-#-#-#-# auth_openid.pot.web (PROJECT VERSION) #-#-#-#-#
#. openerp-web
#: field:res.users,openid_url:0
#: /home/odo/repositories/addons/trunk/auth_openid/static/src/xml/auth_openid.xml:47
msgid "OpenID URL"
msgstr ""
#. module: auth_openid
#: help:res.users,openid_email:0
msgid "Used for disambiguation in case of a shared OpenID URL"
msgstr ""
#. module: auth_openid
#: sql_constraint:res.users:0
msgid "You can not have two users with the same login !"
msgstr ""
#. module: auth_openid
#: field:res.users,openid_email:0
msgid "OpenID Email"
msgstr ""
#. module: auth_openid
#: constraint:res.users:0
msgid "The chosen company is not in the allowed companies for this user"
msgstr ""
#. module: auth_openid
#: field:res.users,openid_key:0
msgid "OpenID Key"
msgstr ""
#. module: auth_openid
#: model:ir.model,name:auth_openid.model_res_users
msgid "res.users"
msgstr ""
#. openerp-web
#: /home/odo/repositories/addons/trunk/auth_openid/static/src/xml/auth_openid.xml:8
msgid "Password"
msgstr "Hasło"
#. openerp-web
#: /home/odo/repositories/addons/trunk/auth_openid/static/src/xml/auth_openid.xml:9
#: /home/odo/repositories/addons/trunk/auth_openid/static/src/xml/auth_openid.xml:10
msgid "Google"
msgstr "Google"
#. openerp-web
#: /home/odo/repositories/addons/trunk/auth_openid/static/src/xml/auth_openid.xml:10
msgid "Google Apps"
msgstr ""
#. openerp-web
#: /home/odo/repositories/addons/trunk/auth_openid/static/src/xml/auth_openid.xml:11
msgid "Launchpad"
msgstr "Launchpad"
#. openerp-web
#: /home/odo/repositories/addons/trunk/auth_openid/static/src/xml/auth_openid.xml:20
msgid "Google Apps Domain:"
msgstr ""
#. openerp-web
#: /home/odo/repositories/addons/trunk/auth_openid/static/src/xml/auth_openid.xml:24
msgid "Username:"
msgstr ""
#. openerp-web
#: /home/odo/repositories/addons/trunk/auth_openid/static/src/xml/auth_openid.xml:28
msgid "OpenID URL:"
msgstr ""
#. openerp-web
#: /home/odo/repositories/addons/trunk/auth_openid/static/src/xml/auth_openid.xml:35
msgid "Google Apps Domain"
msgstr ""
#. openerp-web
#: /home/odo/repositories/addons/trunk/auth_openid/static/src/xml/auth_openid.xml:41
msgid "Username"
msgstr ""

View File

@ -138,7 +138,7 @@ class res_users(osv.Model):
for user in self.browse(cr, uid, ids, context)) for user in self.browse(cr, uid, ids, context))
_columns = { _columns = {
'state': fields.function(_get_state, string='State', type='selection', 'state': fields.function(_get_state, string='Status', type='selection',
selection=[('new', 'New'), ('active', 'Active'), ('reset', 'Resetting Password')]), selection=[('new', 'New'), ('active', 'Active'), ('reset', 'Resetting Password')]),
} }

View File

@ -8,14 +8,14 @@ msgstr ""
"Project-Id-Version: openobject-addons\n" "Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" "Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-02-08 00:36+0000\n" "POT-Creation-Date: 2012-02-08 00:36+0000\n"
"PO-Revision-Date: 2012-05-10 17:50+0000\n" "PO-Revision-Date: 2012-10-25 16:32+0000\n"
"Last-Translator: Wei \"oldrev\" Li <oldrev@gmail.com>\n" "Last-Translator: ccdos <Unknown>\n"
"Language-Team: Chinese (Simplified) <zh_CN@li.org>\n" "Language-Team: Chinese (Simplified) <zh_CN@li.org>\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-10-19 05:35+0000\n" "X-Launchpad-Export-Date: 2012-10-26 04:56+0000\n"
"X-Generator: Launchpad (build 16165)\n" "X-Generator: Launchpad (build 16194)\n"
#. module: base_action_rule #. module: base_action_rule
#: help:base.action.rule,act_mail_to_user:0 #: help:base.action.rule,act_mail_to_user:0
@ -315,7 +315,7 @@ msgstr "激活"
#: code:addons/base_action_rule/base_action_rule.py:329 #: code:addons/base_action_rule/base_action_rule.py:329
#, python-format #, python-format
msgid "No Email ID Found for your Company address!" msgid "No Email ID Found for your Company address!"
msgstr "" msgstr "公司地址中没有设置Email !"
#. module: base_action_rule #. module: base_action_rule
#: field:base.action.rule,act_remind_user:0 #: field:base.action.rule,act_remind_user:0

View File

@ -1023,10 +1023,10 @@ rule or repeating pattern of time to exclude from the recurring rule."),
'rrule': fields.function(_get_rulestring, type='char', size=124, \ 'rrule': fields.function(_get_rulestring, type='char', size=124, \
fnct_inv=_rrule_write, store=True, string='Recurrent Rule'), fnct_inv=_rrule_write, store=True, string='Recurrent Rule'),
'rrule_type': fields.selection([ 'rrule_type': fields.selection([
('daily', 'Daily'), ('daily', 'Day(s)'),
('weekly', 'Weekly'), ('weekly', 'Week(s)'),
('monthly', 'Monthly'), ('monthly', 'Month(s)'),
('yearly', 'Yearly') ('yearly', 'Year(s)')
], 'Recurrency', states={'done': [('readonly', True)]}, ], 'Recurrency', states={'done': [('readonly', True)]},
help="Let the event automatically repeat at that interval"), help="Let the event automatically repeat at that interval"),
'alarm_id': fields.many2one('res.alarm', 'Reminder', states={'done': [('readonly', True)]}, 'alarm_id': fields.many2one('res.alarm', 'Reminder', states={'done': [('readonly', True)]},

View File

@ -86,7 +86,7 @@
</h2> </h2>
</div> </div>
<notebook> <notebook>
<page string="Meeting Detail"> <page string="Meeting Details">
<group> <group>
<group> <group>
<field name="date" string="Starting at"/> <field name="date" string="Starting at"/>
@ -170,12 +170,7 @@
</group> </group>
</group> </group>
</page> </page>
<!-- <page string="Invitations" groups="base.group_no_one">
Temporarily removing invitation feature as the implementation
was not clean. Invitation should be trigerred automatically
based on partner_ids.
-->
<page string="Invitations">
<field name="attendee_ids" widget="one2many" mode="tree"> <field name="attendee_ids" widget="one2many" mode="tree">
<tree string="Invitation details" editable="top"> <tree string="Invitation details" editable="top">
<field name="partner_id"/> <field name="partner_id"/>

View File

@ -156,5 +156,11 @@
border-right: 1px solid #D0D0D0; border-right: 1px solid #D0D0D0;
} }
.oe_import .oe_import_error_report > p {
background: #efc9cb;
}
.oe_import .select2-results {
font-size: 12px;
}

View File

@ -11,7 +11,7 @@
<label for="vat"/> <label for="vat"/>
<div> <div>
<field name="vat" on_change="vat_change(vat)" placeholder="e.g. BE0477472701" class="oe_inline"/> <field name="vat" on_change="vat_change(vat)" placeholder="e.g. BE0477472701" class="oe_inline"/>
<button colspan="2" name="button_check_vat" string="Check VAT" type="object" icon="gtk-execute" class="oe_inline"/> <button colspan="2" name="button_check_vat" string="Check Validity" type="object" icon="gtk-execute" class="oe_inline"/>
<field name="vat_subjected" class="oe_inline"/> <field name="vat_subjected" class="oe_inline"/>
</div> </div>
</field> </field>

View File

@ -77,7 +77,7 @@ class crm_case_stage(osv.osv):
help="Link between stages and sales teams. When set, this limitate the current stage to the selected sales teams."), help="Link between stages and sales teams. When set, this limitate the current stage to the selected sales teams."),
'state': fields.selection(AVAILABLE_STATES, 'Related Status', required=True, 'state': fields.selection(AVAILABLE_STATES, 'Related Status', required=True,
help="The status of your document will automatically change regarding the selected stage. " \ help="The status of your document will automatically change regarding the selected stage. " \
"For example, if a stage is related to the state 'Close', when your document reaches this stage, it is automatically closed."), "For example, if a stage is related to the status 'Close', when your document reaches this stage, it is automatically closed."),
'case_default': fields.boolean('Common to All Teams', 'case_default': fields.boolean('Common to All Teams',
help="If you check this field, this stage will be proposed by default on each sales team. It will not assign this stage to existing teams."), help="If you check this field, this stage will be proposed by default on each sales team. It will not assign this stage to existing teams."),
'fold': fields.boolean('Hide in Views when Empty', 'fold': fields.boolean('Hide in Views when Empty',

View File

@ -223,11 +223,11 @@ class crm_lead(base_stage, format_address, osv.osv):
'day_close': fields.function(_compute_day, string='Days to Close', \ 'day_close': fields.function(_compute_day, string='Days to Close', \
multi='day_close', type="float", store=True), multi='day_close', type="float", store=True),
'state': fields.related('stage_id', 'state', type="selection", store=True, 'state': fields.related('stage_id', 'state', type="selection", store=True,
selection=crm.AVAILABLE_STATES, string="State", readonly=True, selection=crm.AVAILABLE_STATES, string="Status", readonly=True,
help='The state is set to \'Draft\', when a case is created.\ help='The Status is set to \'Draft\', when a case is created.\
If the case is in progress the state is set to \'Open\'.\ If the case is in progress the Status is set to \'Open\'.\
When the case is over, the state is set to \'Done\'.\ When the case is over, the Status is set to \'Done\'.\
If the case needs to be reviewed then the state is \ If the case needs to be reviewed then the Status is \
set to \'Pending\'.'), set to \'Pending\'.'),
# Only used for type opportunity # Only used for type opportunity

View File

@ -50,10 +50,10 @@ class crm_phonecall(base_state, osv.osv):
('cancel', 'Cancelled'), ('cancel', 'Cancelled'),
('done', 'Held'),], ('done', 'Held'),],
string='Status', size=16, readonly=True, string='Status', size=16, readonly=True,
help='The state is set to \'Todo\', when a case is created.\ help='The status is set to \'Todo\', when a case is created.\
If the case is in progress the state is set to \'Open\'.\ If the case is in progress the status is set to \'Open\'.\
When the call is over, the state is set to \'Held\'.\ When the call is over, the status is set to \'Held\'.\
If the call needs to be done then the state is set to \'Not Held\'.'), If the call needs to be done then the status is set to \'Not Held\'.'),
'email_from': fields.char('Email', size=128, help="These people will receive email."), 'email_from': fields.char('Email', size=128, help="These people will receive email."),
'date_open': fields.datetime('Opened', readonly=True), 'date_open': fields.datetime('Opened', readonly=True),
# phonecall fields # phonecall fields

View File

@ -125,7 +125,7 @@
</div> </div>
<div class="oe_title"> <div class="oe_title">
<div class="oe_edit_only"> <div class="oe_edit_only">
<label for="name" string="Title"/> <label for="name"/>
</div> </div>
<h1><field name="name" required="1"/></h1> <h1><field name="name" required="1"/></h1>
<div class="oe_edit_only"> <div class="oe_edit_only">

View File

@ -7,14 +7,14 @@ msgstr ""
"Project-Id-Version: OpenERP Server 6.0dev\n" "Project-Id-Version: OpenERP Server 6.0dev\n"
"Report-Msgid-Bugs-To: support@openerp.com\n" "Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-02-08 01:37+0100\n" "POT-Creation-Date: 2012-02-08 01:37+0100\n"
"PO-Revision-Date: 2012-03-22 16:17+0000\n" "PO-Revision-Date: 2012-10-25 16:22+0000\n"
"Last-Translator: Wei \"oldrev\" Li <oldrev@gmail.com>\n" "Last-Translator: fenshuajiang <openerp@126.com>\n"
"Language-Team: \n" "Language-Team: \n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-08-28 06:06+0000\n" "X-Launchpad-Export-Date: 2012-10-26 04:56+0000\n"
"X-Generator: Launchpad (build 15864)\n" "X-Generator: Launchpad (build 16194)\n"
#. module: crm #. module: crm
#: view:crm.lead.report:0 #: view:crm.lead.report:0
@ -172,7 +172,7 @@ msgstr "预计结束月份"
#. module: crm #. module: crm
#: view:crm.lead2opportunity.partner.mass:0 #: view:crm.lead2opportunity.partner.mass:0
msgid "Assigned Opportunities to" msgid "Assigned Opportunities to"
msgstr "" msgstr "分配商机给"
#. module: crm #. module: crm
#: view:crm.lead:0 field:crm.lead,partner_id:0 view:crm.lead.report:0 #: view:crm.lead:0 field:crm.lead,partner_id:0 view:crm.lead.report:0
@ -583,7 +583,7 @@ msgstr "结束日期"
#. module: crm #. module: crm
#: view:crm.opportunity2phonecall:0 view:crm.phonecall2phonecall:0 #: view:crm.opportunity2phonecall:0 view:crm.phonecall2phonecall:0
msgid "Schedule/Log a Call" msgid "Schedule/Log a Call"
msgstr "" msgstr "计划/记录一个电话"
#. module: crm #. module: crm
#: constraint:base.action.rule:0 #: constraint:base.action.rule:0
@ -763,7 +763,7 @@ msgstr "继续"
#. module: crm #. module: crm
#: field:crm.segmentation,som_interval:0 #: field:crm.segmentation,som_interval:0
msgid "Days per Period" msgid "Days per Period"
msgstr "" msgstr "每阶段的天数"
#. module: crm #. module: crm
#: field:crm.meeting,byday:0 #: field:crm.meeting,byday:0
@ -926,7 +926,7 @@ msgstr "开启天数"
#. module: crm #. module: crm
#: view:crm.meeting:0 #: view:crm.meeting:0
msgid "Show Time as" msgid "Show Time as"
msgstr "" msgstr "显示时间为"
#. module: crm #. module: crm
#: view:crm.phonecall2partner:0 #: view:crm.phonecall2partner:0
@ -1299,7 +1299,7 @@ msgstr "写日期"
#. module: crm #. module: crm
#: view:crm.meeting:0 #: view:crm.meeting:0
msgid "End of Recurrency" msgid "End of Recurrency"
msgstr "" msgstr "结束循环"
#. module: crm #. module: crm
#: view:crm.meeting:0 #: view:crm.meeting:0
@ -1835,7 +1835,7 @@ msgstr "回复到"
#. module: crm #. module: crm
#: view:crm.case.section:0 #: view:crm.case.section:0
msgid "Select Stages for this Sales Team" msgid "Select Stages for this Sales Team"
msgstr "" msgstr "为这个销售团队选择阶段"
#. module: crm #. module: crm
#: view:board.board:0 #: view:board.board:0
@ -2683,7 +2683,7 @@ msgstr "这联系的邮件地址"
#. module: crm #. module: crm
#: field:crm.lead,referred:0 #: field:crm.lead,referred:0
msgid "Referred by" msgid "Referred by"
msgstr "" msgstr "推荐人"
#. module: crm #. module: crm
#: view:crm.lead:0 model:ir.model,name:crm.model_crm_add_note #: view:crm.lead:0 model:ir.model,name:crm.model_crm_add_note

View File

@ -50,7 +50,7 @@ class crm_claim_stage(osv.osv):
'sequence': fields.integer('Sequence', help="Used to order stages. Lower is better."), 'sequence': fields.integer('Sequence', help="Used to order stages. Lower is better."),
'section_ids':fields.many2many('crm.case.section', 'section_claim_stage_rel', 'stage_id', 'section_id', string='Sections', 'section_ids':fields.many2many('crm.case.section', 'section_claim_stage_rel', 'stage_id', 'section_id', string='Sections',
help="Link between stages and sales teams. When set, this limitate the current stage to the selected sales teams."), help="Link between stages and sales teams. When set, this limitate the current stage to the selected sales teams."),
'state': fields.selection(crm.AVAILABLE_STATES, 'State', required=True, help="The related state for the stage. The state of your document will automatically change regarding the selected stage. For example, if a stage is related to the state 'Close', when your document reaches this stage, it will be automatically have the 'closed' state."), 'state': fields.selection(crm.AVAILABLE_STATES, 'Status', required=True, help="The related status for the stage. The status of your document will automatically change regarding the selected stage. For example, if a stage is related to the status 'Close', when your document reaches this stage, it will be automatically have the 'closed' status."),
'case_refused': fields.boolean('Refused stage', 'case_refused': fields.boolean('Refused stage',
help='Refused stages are specific stages for done.'), help='Refused stages are specific stages for done.'),
'case_default': fields.boolean('Common to All Teams', 'case_default': fields.boolean('Common to All Teams',
@ -108,11 +108,11 @@ class crm_claim(base_stage, osv.osv):
domain="['|', ('section_ids', '=', section_id), ('case_default', '=', True)]"), domain="['|', ('section_ids', '=', section_id), ('case_default', '=', True)]"),
'cause': fields.text('Root Cause'), 'cause': fields.text('Root Cause'),
'state': fields.related('stage_id', 'state', type="selection", store=True, 'state': fields.related('stage_id', 'state', type="selection", store=True,
selection=crm.AVAILABLE_STATES, string="State", readonly=True, selection=crm.AVAILABLE_STATES, string="Status", readonly=True,
help='The state is set to \'Draft\', when a case is created.\ help='The status is set to \'Draft\', when a case is created.\
If the case is in progress the state is set to \'Open\'.\ If the case is in progress the status is set to \'Open\'.\
When the case is over, the state is set to \'Done\'.\ When the case is over, the status is set to \'Done\'.\
If the case needs to be reviewed then the state is \ If the case needs to be reviewed then the status is \
set to \'Pending\'.'), set to \'Pending\'.'),
} }

View File

@ -8,14 +8,14 @@ msgstr ""
"Project-Id-Version: openobject-addons\n" "Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" "Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-02-08 00:36+0000\n" "POT-Creation-Date: 2012-02-08 00:36+0000\n"
"PO-Revision-Date: 2011-03-16 00:04+0000\n" "PO-Revision-Date: 2012-10-24 05:01+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: Chertykov Denis <chertykov@gmail.com>\n"
"Language-Team: Russian <ru@li.org>\n" "Language-Team: Russian <ru@li.org>\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-10-19 05:33+0000\n" "X-Launchpad-Export-Date: 2012-10-25 05:35+0000\n"
"X-Generator: Launchpad (build 16165)\n" "X-Generator: Launchpad (build 16179)\n"
#. module: crm_claim #. module: crm_claim
#: field:crm.claim.report,nbr:0 #: field:crm.claim.report,nbr:0
@ -85,12 +85,12 @@ msgstr ""
#: code:addons/crm_claim/crm_claim.py:132 #: code:addons/crm_claim/crm_claim.py:132
#, python-format #, python-format
msgid "The claim '%s' has been opened." msgid "The claim '%s' has been opened."
msgstr "" msgstr "Претензия '%s' была открыта"
#. module: crm_claim #. module: crm_claim
#: view:crm.claim:0 #: view:crm.claim:0
msgid "Date Closed" msgid "Date Closed"
msgstr "" msgstr "Дата закрытия"
#. module: crm_claim #. module: crm_claim
#: view:crm.claim.report:0 #: view:crm.claim.report:0
@ -151,12 +151,12 @@ msgstr "Ссылка"
#. module: crm_claim #. module: crm_claim
#: view:crm.claim.report:0 #: view:crm.claim.report:0
msgid "Date of claim" msgid "Date of claim"
msgstr "" msgstr "Дата претензии"
#. module: crm_claim #. module: crm_claim
#: view:crm.claim:0 #: view:crm.claim:0
msgid "All pending Claims" msgid "All pending Claims"
msgstr "" msgstr "Все ожидающие претензии"
#. module: crm_claim #. module: crm_claim
#: view:crm.claim.report:0 #: view:crm.claim.report:0
@ -187,7 +187,7 @@ msgstr "Контрагент"
#. module: crm_claim #. module: crm_claim
#: view:crm.claim.report:0 #: view:crm.claim.report:0
msgid "Month of claim" msgid "Month of claim"
msgstr "" msgstr "Месяц претензии"
#. module: crm_claim #. module: crm_claim
#: selection:crm.claim,type_action:0 #: selection:crm.claim,type_action:0
@ -227,7 +227,7 @@ msgstr "Отправить новое эл. письмо"
#: selection:crm.claim,state:0 #: selection:crm.claim,state:0
#: view:crm.claim.report:0 #: view:crm.claim.report:0
msgid "New" msgid "New"
msgstr "" msgstr "Новый"
#. module: crm_claim #. module: crm_claim
#: view:crm.claim:0 #: view:crm.claim:0
@ -254,7 +254,7 @@ msgstr "Следующее действие"
#. module: crm_claim #. module: crm_claim
#: view:crm.claim.report:0 #: view:crm.claim.report:0
msgid "My Sales Team(s)" msgid "My Sales Team(s)"
msgstr "" msgstr "Мои отделы продаж"
#. module: crm_claim #. module: crm_claim
#: model:crm.case.stage,name:crm_claim.stage_claim3 #: model:crm.case.stage,name:crm_claim.stage_claim3
@ -321,7 +321,7 @@ msgstr "Контакт"
#. module: crm_claim #. module: crm_claim
#: view:crm.claim.report:0 #: view:crm.claim.report:0
msgid "Month-1" msgid "Month-1"
msgstr "" msgstr "Месяц-1"
#. module: crm_claim #. module: crm_claim
#: model:ir.actions.act_window,name:crm_claim.action_report_crm_claim #: model:ir.actions.act_window,name:crm_claim.action_report_crm_claim
@ -380,7 +380,7 @@ msgstr "Дата изменения"
#. module: crm_claim #. module: crm_claim
#: view:crm.claim.report:0 #: view:crm.claim.report:0
msgid "Year of claim" msgid "Year of claim"
msgstr "" msgstr "Год претензи"
#. module: crm_claim #. module: crm_claim
#: view:crm.claim.report:0 #: view:crm.claim.report:0
@ -402,7 +402,7 @@ msgstr "Значение претензии"
#. module: crm_claim #. module: crm_claim
#: view:crm.claim:0 #: view:crm.claim:0
msgid "Responsible User" msgid "Responsible User"
msgstr "" msgstr "Ответственный пользователь"
#. module: crm_claim #. module: crm_claim
#: help:crm.claim,email_cc:0 #: help:crm.claim,email_cc:0
@ -474,7 +474,7 @@ msgstr "Июнь"
#. module: crm_claim #. module: crm_claim
#: view:res.partner:0 #: view:res.partner:0
msgid "Partners Claim" msgid "Partners Claim"
msgstr "" msgstr "Претензии партнера"
#. module: crm_claim #. module: crm_claim
#: field:crm.claim,partner_phone:0 #: field:crm.claim,partner_phone:0
@ -489,7 +489,7 @@ msgstr "Пользователь"
#. module: crm_claim #. module: crm_claim
#: field:crm.claim,active:0 #: field:crm.claim,active:0
msgid "Active" msgid "Active"
msgstr "" msgstr "Активен"
#. module: crm_claim #. module: crm_claim
#: selection:crm.claim.report,month:0 #: selection:crm.claim.report,month:0
@ -621,13 +621,13 @@ msgstr "Открыть"
#. module: crm_claim #. module: crm_claim
#: view:crm.claim:0 #: view:crm.claim:0
msgid "New Claims" msgid "New Claims"
msgstr "" msgstr "Новые претензии"
#. module: crm_claim #. module: crm_claim
#: view:crm.claim:0 #: view:crm.claim:0
#: selection:crm.claim,state:0 #: selection:crm.claim,state:0
msgid "In Progress" msgid "In Progress"
msgstr "Выполняется" msgstr "В работе"
#. module: crm_claim #. module: crm_claim
#: view:crm.claim:0 #: view:crm.claim:0
@ -638,17 +638,17 @@ msgstr "Ответственный"
#. module: crm_claim #. module: crm_claim
#: view:crm.claim.report:0 #: view:crm.claim.report:0
msgid "Claims created in current year" msgid "Claims created in current year"
msgstr "" msgstr "Претензии созданные в текущем году"
#. module: crm_claim #. module: crm_claim
#: view:crm.claim:0 #: view:crm.claim:0
msgid "Unassigned Claims" msgid "Unassigned Claims"
msgstr "" msgstr "Не назначенные претензии"
#. module: crm_claim #. module: crm_claim
#: view:crm.claim.report:0 #: view:crm.claim.report:0
msgid "Claims created in current month" msgid "Claims created in current month"
msgstr "" msgstr "Претензии созданные в текущем месяце"
#. module: crm_claim #. module: crm_claim
#: field:crm.claim.report,delay_expected:0 #: field:crm.claim.report,delay_expected:0
@ -718,7 +718,7 @@ msgstr "Выполненные действия"
#. module: crm_claim #. module: crm_claim
#: view:crm.claim.report:0 #: view:crm.claim.report:0
msgid "Claims created in last month" msgid "Claims created in last month"
msgstr "" msgstr "Претензии созданные в прошлом месяце"
#. module: crm_claim #. module: crm_claim
#: model:crm.case.stage,name:crm_claim.stage_claim5 #: model:crm.case.stage,name:crm_claim.stage_claim5
@ -760,7 +760,7 @@ msgstr "Год"
#. module: crm_claim #. module: crm_claim
#: view:crm.claim.report:0 #: view:crm.claim.report:0
msgid "My company" msgid "My company"
msgstr "" msgstr "Моя компания"
#. module: crm_claim #. module: crm_claim
#: selection:crm.claim.report,month:0 #: selection:crm.claim.report,month:0
@ -780,7 +780,7 @@ msgstr "Идентификатор"
#. module: crm_claim #. module: crm_claim
#: constraint:res.partner:0 #: constraint:res.partner:0
msgid "Error ! You cannot create recursive associated members." msgid "Error ! You cannot create recursive associated members."
msgstr "" msgstr "Ошибка! Вы не можете создавать рекурсивные ссылки на участников."
#. module: crm_claim #. module: crm_claim
#: view:crm.claim:0 #: view:crm.claim:0
@ -810,7 +810,7 @@ msgstr "Дата создания"
#. module: crm_claim #. module: crm_claim
#: view:crm.claim:0 #: view:crm.claim:0
msgid "In Progress Claims" msgid "In Progress Claims"
msgstr "" msgstr "Претензии \"В работе\""
#~ msgid "Probability" #~ msgid "Probability"
#~ msgstr "Вероятность" #~ msgstr "Вероятность"

View File

@ -73,10 +73,10 @@ class crm_helpdesk(base_state, base_stage, osv.osv):
('object_id.model', '=', 'crm.helpdesk')]"), ('object_id.model', '=', 'crm.helpdesk')]"),
'duration': fields.float('Duration', states={'done': [('readonly', True)]}), 'duration': fields.float('Duration', states={'done': [('readonly', True)]}),
'state': fields.selection(crm.AVAILABLE_STATES, 'Status', size=16, readonly=True, 'state': fields.selection(crm.AVAILABLE_STATES, 'Status', size=16, readonly=True,
help='The state is set to \'Draft\', when a case is created.\ help='The status is set to \'Draft\', when a case is created.\
\nIf the case is in progress the state is set to \'Open\'.\ \nIf the case is in progress the status is set to \'Open\'.\
\nWhen the case is over, the state is set to \'Done\'.\ \nWhen the case is over, the status is set to \'Done\'.\
\nIf the case needs to be reviewed then the state is set to \'Pending\'.'), \nIf the case needs to be reviewed then the status is set to \'Pending\'.'),
} }
_defaults = { _defaults = {

View File

@ -8,14 +8,14 @@ msgstr ""
"Project-Id-Version: openobject-addons\n" "Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" "Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-02-08 00:36+0000\n" "POT-Creation-Date: 2012-02-08 00:36+0000\n"
"PO-Revision-Date: 2010-12-20 08:54+0000\n" "PO-Revision-Date: 2012-10-24 05:08+0000\n"
"Last-Translator: Chertykov Denis <chertykov@gmail.com>\n" "Last-Translator: Chertykov Denis <chertykov@gmail.com>\n"
"Language-Team: Russian <ru@li.org>\n" "Language-Team: Russian <ru@li.org>\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-10-19 05:34+0000\n" "X-Launchpad-Export-Date: 2012-10-25 05:35+0000\n"
"X-Generator: Launchpad (build 16165)\n" "X-Generator: Launchpad (build 16179)\n"
#. module: crm_helpdesk #. module: crm_helpdesk
#: field:crm.helpdesk.report,delay_close:0 #: field:crm.helpdesk.report,delay_close:0
@ -46,7 +46,7 @@ msgstr "Март"
#. module: crm_helpdesk #. module: crm_helpdesk
#: view:crm.helpdesk.report:0 #: view:crm.helpdesk.report:0
msgid "Helpdesk requests occurred in current year" msgid "Helpdesk requests occurred in current year"
msgstr "" msgstr "Запросы на техподдержку в текущем году"
#. module: crm_helpdesk #. module: crm_helpdesk
#: field:crm.helpdesk,company_id:0 #: field:crm.helpdesk,company_id:0
@ -80,7 +80,7 @@ msgstr "Добавить внутреннею заметку"
#. module: crm_helpdesk #. module: crm_helpdesk
#: view:crm.helpdesk.report:0 #: view:crm.helpdesk.report:0
msgid "Date of helpdesk requests" msgid "Date of helpdesk requests"
msgstr "" msgstr "Дата запросов техподдержки"
#. module: crm_helpdesk #. module: crm_helpdesk
#: view:crm.helpdesk:0 #: view:crm.helpdesk:0
@ -95,7 +95,7 @@ msgstr "Сообщения"
#. module: crm_helpdesk #. module: crm_helpdesk
#: view:crm.helpdesk.report:0 #: view:crm.helpdesk.report:0
msgid "My company" msgid "My company"
msgstr "" msgstr "Моя компания"
#. module: crm_helpdesk #. module: crm_helpdesk
#: selection:crm.helpdesk,state:0 #: selection:crm.helpdesk,state:0
@ -156,7 +156,7 @@ msgstr "Раздел"
#. module: crm_helpdesk #. module: crm_helpdesk
#: view:crm.helpdesk.report:0 #: view:crm.helpdesk.report:0
msgid "Helpdesk requests occurred in last month" msgid "Helpdesk requests occurred in last month"
msgstr "" msgstr "последний месяц"
#. module: crm_helpdesk #. module: crm_helpdesk
#: view:crm.helpdesk:0 #: view:crm.helpdesk:0
@ -166,14 +166,14 @@ msgstr "Отправить новое эл. письмо"
#. module: crm_helpdesk #. module: crm_helpdesk
#: view:crm.helpdesk:0 #: view:crm.helpdesk:0
msgid "Helpdesk requests during last 7 days" msgid "Helpdesk requests during last 7 days"
msgstr "" msgstr "Запросы на техподдержку за последние 7 дней"
#. module: crm_helpdesk #. module: crm_helpdesk
#: view:crm.helpdesk:0 #: view:crm.helpdesk:0
#: selection:crm.helpdesk,state:0 #: selection:crm.helpdesk,state:0
#: view:crm.helpdesk.report:0 #: view:crm.helpdesk.report:0
msgid "New" msgid "New"
msgstr "" msgstr "Новый"
#. module: crm_helpdesk #. module: crm_helpdesk
#: model:ir.model,name:crm_helpdesk.model_crm_helpdesk_report #: model:ir.model,name:crm_helpdesk.model_crm_helpdesk_report
@ -207,7 +207,7 @@ msgstr "# Писем"
#: view:crm.helpdesk:0 #: view:crm.helpdesk:0
#: view:crm.helpdesk.report:0 #: view:crm.helpdesk.report:0
msgid "My Sales Team(s)" msgid "My Sales Team(s)"
msgstr "" msgstr "Мои отделы продаж"
#. module: crm_helpdesk #. module: crm_helpdesk
#: field:crm.helpdesk,create_date:0 #: field:crm.helpdesk,create_date:0
@ -252,7 +252,7 @@ msgstr "Категории"
#. module: crm_helpdesk #. module: crm_helpdesk
#: view:crm.helpdesk:0 #: view:crm.helpdesk:0
msgid "New Helpdesk Request" msgid "New Helpdesk Request"
msgstr "" msgstr "Новый запрос техподдержки"
#. module: crm_helpdesk #. module: crm_helpdesk
#: view:crm.helpdesk:0 #: view:crm.helpdesk:0
@ -267,13 +267,13 @@ msgstr "Даты"
#. module: crm_helpdesk #. module: crm_helpdesk
#: view:crm.helpdesk.report:0 #: view:crm.helpdesk.report:0
msgid "Month of helpdesk requests" msgid "Month of helpdesk requests"
msgstr "" msgstr "Месяц запросов техподдержки"
#. module: crm_helpdesk #. module: crm_helpdesk
#: code:addons/crm_helpdesk/crm_helpdesk.py:101 #: code:addons/crm_helpdesk/crm_helpdesk.py:101
#, python-format #, python-format
msgid "No Subject" msgid "No Subject"
msgstr "" msgstr "Без темы"
#. module: crm_helpdesk #. module: crm_helpdesk
#: view:crm.helpdesk.report:0 #: view:crm.helpdesk.report:0
@ -283,12 +283,12 @@ msgstr "№ техподдержки"
#. module: crm_helpdesk #. module: crm_helpdesk
#: view:crm.helpdesk:0 #: view:crm.helpdesk:0
msgid "All pending Helpdesk Request" msgid "All pending Helpdesk Request"
msgstr "" msgstr "Все ожидающие запросы техподдержки"
#. module: crm_helpdesk #. module: crm_helpdesk
#: view:crm.helpdesk.report:0 #: view:crm.helpdesk.report:0
msgid "Year of helpdesk requests" msgid "Year of helpdesk requests"
msgstr "" msgstr "Год запросов техподдержки"
#. module: crm_helpdesk #. module: crm_helpdesk
#: view:crm.helpdesk:0 #: view:crm.helpdesk:0
@ -324,7 +324,7 @@ msgstr "Дата изменения"
#. module: crm_helpdesk #. module: crm_helpdesk
#: view:crm.helpdesk.report:0 #: view:crm.helpdesk.report:0
msgid "Helpdesk requests occurred in current month" msgid "Helpdesk requests occurred in current month"
msgstr "" msgstr "Запросы техподдержки в текущем месяце"
#. module: crm_helpdesk #. module: crm_helpdesk
#: view:crm.helpdesk.report:0 #: view:crm.helpdesk.report:0
@ -345,7 +345,7 @@ msgstr "Категория"
#. module: crm_helpdesk #. module: crm_helpdesk
#: view:crm.helpdesk:0 #: view:crm.helpdesk:0
msgid "Responsible User" msgid "Responsible User"
msgstr "" msgstr "Ответственный пользователь"
#. module: crm_helpdesk #. module: crm_helpdesk
#: view:crm.helpdesk:0 #: view:crm.helpdesk:0
@ -361,7 +361,7 @@ msgstr "Планируемые затраты"
#. module: crm_helpdesk #. module: crm_helpdesk
#: help:crm.helpdesk,channel_id:0 #: help:crm.helpdesk,channel_id:0
msgid "Communication channel." msgid "Communication channel."
msgstr "" msgstr "Канал общения"
#. module: crm_helpdesk #. module: crm_helpdesk
#: help:crm.helpdesk,email_cc:0 #: help:crm.helpdesk,email_cc:0
@ -575,7 +575,7 @@ msgstr "Дерево поддержи"
#. module: crm_helpdesk #. module: crm_helpdesk
#: selection:crm.helpdesk,state:0 #: selection:crm.helpdesk,state:0
msgid "In Progress" msgid "In Progress"
msgstr "" msgstr "В работе"
#. module: crm_helpdesk #. module: crm_helpdesk
#: view:crm.helpdesk:0 #: view:crm.helpdesk:0
@ -660,7 +660,7 @@ msgstr "Название"
#. module: crm_helpdesk #. module: crm_helpdesk
#: view:crm.helpdesk.report:0 #: view:crm.helpdesk.report:0
msgid "Month-1" msgid "Month-1"
msgstr "" msgstr "Месяц-1"
#. module: crm_helpdesk #. module: crm_helpdesk
#: model:ir.ui.menu,name:crm_helpdesk.menu_help_support_main #: model:ir.ui.menu,name:crm_helpdesk.menu_help_support_main
@ -699,17 +699,17 @@ msgstr ""
#. module: crm_helpdesk #. module: crm_helpdesk
#: view:crm.helpdesk:0 #: view:crm.helpdesk:0
msgid "Todays's Helpdesk Requests" msgid "Todays's Helpdesk Requests"
msgstr "" msgstr "Запросы техподдержки за сегодня"
#. module: crm_helpdesk #. module: crm_helpdesk
#: view:crm.helpdesk:0 #: view:crm.helpdesk:0
msgid "Request Date" msgid "Request Date"
msgstr "" msgstr "Дата запроса"
#. module: crm_helpdesk #. module: crm_helpdesk
#: view:crm.helpdesk:0 #: view:crm.helpdesk:0
msgid "Open Helpdesk Request" msgid "Open Helpdesk Request"
msgstr "" msgstr "Открыть запрос техподдержки"
#. module: crm_helpdesk #. module: crm_helpdesk
#: selection:crm.helpdesk,priority:0 #: selection:crm.helpdesk,priority:0

View File

@ -87,7 +87,7 @@ class res_partner(osv.osv):
help="Gives the probability to assign a lead to this partner. (0 means no assignation.)"), help="Gives the probability to assign a lead to this partner. (0 means no assignation.)"),
'opportunity_assigned_ids': fields.one2many('crm.lead', 'partner_assigned_id',\ 'opportunity_assigned_ids': fields.one2many('crm.lead', 'partner_assigned_id',\
'Assigned Opportunities'), 'Assigned Opportunities'),
'grade_id': fields.many2one('res.partner.grade', 'Partner Grade'), 'grade_id': fields.many2one('res.partner.grade', 'Partner Level'),
'activation' : fields.many2one('res.partner.activation', 'Activation', select=1), 'activation' : fields.many2one('res.partner.activation', 'Activation', select=1),
'date_partnership' : fields.date('Partnership Date'), 'date_partnership' : fields.date('Partnership Date'),
'date_review' : fields.date('Latest Partner Review'), 'date_review' : fields.date('Latest Partner Review'),

View File

@ -0,0 +1,49 @@
# Polish translation for openobject-addons
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
# This file is distributed under the same license as the openobject-addons package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-02-08 00:36+0000\n"
"PO-Revision-Date: 2012-10-25 16:50+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Polish <pl@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-10-26 04:56+0000\n"
"X-Generator: Launchpad (build 16194)\n"
#. module: decimal_precision
#: field:decimal.precision,digits:0
msgid "Digits"
msgstr "Cyfry"
#. module: decimal_precision
#: model:ir.actions.act_window,name:decimal_precision.action_decimal_precision_form
#: model:ir.ui.menu,name:decimal_precision.menu_decimal_precision_form
msgid "Decimal Accuracy"
msgstr ""
#. module: decimal_precision
#: field:decimal.precision,name:0
msgid "Usage"
msgstr "Użycie"
#. module: decimal_precision
#: sql_constraint:decimal.precision:0
msgid "Only one value can be defined for each given usage!"
msgstr ""
#. module: decimal_precision
#: view:decimal.precision:0
msgid "Decimal Precision"
msgstr ""
#. module: decimal_precision
#: model:ir.model,name:decimal_precision.model_decimal_precision
msgid "decimal.precision"
msgstr ""

View File

@ -103,7 +103,7 @@ class DocIndex(indexer):
return _to_unicode(data) return _to_unicode(data)
except OSError: except OSError:
_logger.warn("Failed attempt to execute antiword (MS Word reader). Antiword is necessary to index the file %s of MIME type %s. Detailed error available at DEBUG level.", fname, self._getMimeTypes()[0]) _logger.warning("Failed attempt to execute antiword (MS Word reader). Antiword is necessary to index the file %s of MIME type %s. Detailed error available at DEBUG level.", fname, self._getMimeTypes()[0])
_logger.debug("Trace of the failed file indexing attempt.", exc_info=True) _logger.debug("Trace of the failed file indexing attempt.", exc_info=True)
return False return False

View File

@ -7,14 +7,14 @@ msgstr ""
"Project-Id-Version: OpenERP Server 6.0dev\n" "Project-Id-Version: OpenERP Server 6.0dev\n"
"Report-Msgid-Bugs-To: support@openerp.com\n" "Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-02-08 01:37+0100\n" "POT-Creation-Date: 2012-02-08 01:37+0100\n"
"PO-Revision-Date: 2012-08-13 12:11+0000\n" "PO-Revision-Date: 2012-10-24 05:09+0000\n"
"Last-Translator: Chertykov Denis <chertykov@gmail.com>\n" "Last-Translator: Chertykov Denis <chertykov@gmail.com>\n"
"Language-Team: \n" "Language-Team: \n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-10-19 05:39+0000\n" "X-Launchpad-Export-Date: 2012-10-25 05:35+0000\n"
"X-Generator: Launchpad (build 16165)\n" "X-Generator: Launchpad (build 16179)\n"
#. module: document_page #. module: document_page
#: field:document.page.type,template:0 #: field:document.page.type,template:0
@ -270,7 +270,7 @@ msgstr "История всех страниц"
#. module: document_page #. module: document_page
#: model:ir.model,name:document_page.model_wiki_wiki #: model:ir.model,name:document_page.model_wiki_wiki
msgid "document.page" msgid "document.page"
msgstr "" msgstr "document.page"
#. module: document_page #. module: document_page
#: help:document.page.type,method:0 #: help:document.page.type,method:0
@ -285,7 +285,7 @@ msgstr "Закрыть"
#. module: document_page #. module: document_page
#: model:ir.model,name:document_page.model_wizard_wiki_history_show_diff #: model:ir.model,name:document_page.model_wizard_wiki_history_show_diff
msgid "wizard.document.page.history.show_diff" msgid "wizard.document.page.history.show_diff"
msgstr "" msgstr "wizard.document.page.history.show_diff"
#. module: document_page #. module: document_page
#: field:document.page.history,wiki_id:0 #: field:document.page.history,wiki_id:0
@ -357,7 +357,7 @@ msgstr "Это существенные изменения ?"
#: model:ir.model,name:document_page.model_wiki_groups #: model:ir.model,name:document_page.model_wiki_groups
#: model:ir.ui.menu,name:document_page.menu_action_wiki_groups view:document.page.type:0 #: model:ir.ui.menu,name:document_page.menu_action_wiki_groups view:document.page.type:0
msgid "Document Types" msgid "Document Types"
msgstr "" msgstr "Типы документов"
#. module: document_page #. module: document_page
#: view:document.page:0 #: view:document.page:0
@ -374,7 +374,7 @@ msgstr "Изменено"
#: field:document.page,type:0 #: field:document.page,type:0
#, python-format #, python-format
msgid "Type" msgid "Type"
msgstr "" msgstr "Тип"
#. module: document_page #. module: document_page
#: view:document.page.type:0 view:document.page.page.open:0 #: view:document.page.type:0 view:document.page.page.open:0

View File

@ -29,7 +29,7 @@ _logger = logging.getLogger(__name__)
try: try:
import controllers import controllers
except ImportError: except ImportError:
_logger.warn( _logger.warning(
"""Could not load openerp-web section of EDI, EDI will not behave correctly """Could not load openerp-web section of EDI, EDI will not behave correctly
To fix, launch openerp-web in embedded mode""") To fix, launch openerp-web in embedded mode""")

View File

@ -165,11 +165,8 @@ class test_message_compose(test_mail.TestMailMockups):
self.assertEqual(message_pigs.body, _body_html1, 'mail.message body on Pigs incorrect') self.assertEqual(message_pigs.body, _body_html1, 'mail.message body on Pigs incorrect')
self.assertEqual(message_bird.body, _body_html2, 'mail.message body on Bird incorrect') self.assertEqual(message_bird.body, _body_html2, 'mail.message body on Bird incorrect')
# Test: partner_ids: p_a_id (default) + 3 newly created partners # Test: partner_ids: p_a_id (default) + 3 newly created partners
message_pigs_pids = [partner.id for partner in message_pigs.partner_ids] message_pigs_pids = [partner.id for partner in message_pigs.notified_partner_ids]
message_bird_pids = [partner.id for partner in message_bird.partner_ids] message_bird_pids = [partner.id for partner in message_bird.notified_partner_ids]
partner_ids = self.res_partner.search(cr, uid, [('email', 'in', ['b@b.b', 'c@c.c', 'd@d.d'])]) partner_ids = self.res_partner.search(cr, uid, [('email', 'in', ['b@b.b', 'c@c.c', 'd@d.d'])])
self.assertEqual(len(message_pigs_pids), len(partner_ids), 'mail.message on pigs incorrect number of partner_ids') self.assertEqual(set(message_pigs_pids), set(partner_ids), 'mail.message on pigs incorrect number of notified_partner_ids')
self.assertEqual(set(message_pigs_pids), set(partner_ids), 'mail.message on pigs incorrect number of partner_ids') self.assertEqual(set(message_bird_pids), set(partner_ids), 'mail.message on bird notified_partner_ids incorrect')
self.assertEqual(len(message_bird_pids), len(partner_ids), 'mail.message on bird partner_ids incorrect')
self.assertEqual(set(message_bird_pids), set(partner_ids), 'mail.message on bird partner_ids incorrect')

View File

@ -201,7 +201,7 @@ class event_event(osv.osv):
('confirm', 'Confirmed'), ('confirm', 'Confirmed'),
('done', 'Done')], ('done', 'Done')],
'Status', readonly=True, required=True, 'Status', readonly=True, required=True,
help='If event is created, the state is \'Draft\'.If event is confirmed for the particular dates the state is set to \'Confirmed\'. If the event is over, the state is set to \'Done\'.If event is cancelled the state is set to \'Cancelled\'.'), help='If event is created, the status is \'Draft\'.If event is confirmed for the particular dates the status is set to \'Confirmed\'. If the event is over, the status is set to \'Done\'.If event is cancelled the status is set to \'Cancelled\'.'),
'email_registration_id' : fields.many2one('email.template','Registration Confirmation Email', help='This field contains the template of the mail that will be automatically sent each time a registration for this event is confirmed.'), 'email_registration_id' : fields.many2one('email.template','Registration Confirmation Email', help='This field contains the template of the mail that will be automatically sent each time a registration for this event is confirmed.'),
'email_confirmation_id' : fields.many2one('email.template','Event Confirmation Email', help="If you set an email template, each participant will receive this email announcing the confirmation of the event."), 'email_confirmation_id' : fields.many2one('email.template','Event Confirmation Email', help="If you set an email template, each participant will receive this email announcing the confirmation of the event."),
'reply_to': fields.char('Reply-To Email', size=64, readonly=False, states={'done': [('readonly', True)]}, help="The email address of the organizer is likely to be put here, with the effect to be in the 'Reply-To' of the mails sent automatically at event or registrations confirmation. You can also put the email address of your mail gateway if you use one."), 'reply_to': fields.char('Reply-To Email', size=64, readonly=False, states={'done': [('readonly', True)]}, help="The email address of the organizer is likely to be put here, with the effect to be in the 'Reply-To' of the mails sent automatically at event or registrations confirmation. You can also put the email address of your mail gateway if you use one."),
@ -330,7 +330,7 @@ class event_registration(osv.osv):
_inherit = ['ir.needaction_mixin','mail.thread'] _inherit = ['ir.needaction_mixin','mail.thread']
_columns = { _columns = {
'id': fields.integer('ID'), 'id': fields.integer('ID'),
'origin': fields.char('Source', size=124,readonly=True,help="Name of the sale order which create the registration"), 'origin': fields.char('Source Document', size=124,readonly=True,help="Name of the sale order which create the registration"),
'nb_register': fields.integer('Number of Participants', required=True, readonly=True, states={'draft': [('readonly', False)]}), 'nb_register': fields.integer('Number of Participants', required=True, readonly=True, states={'draft': [('readonly', False)]}),
'event_id': fields.many2one('event.event', 'Event', required=True, readonly=True, states={'draft': [('readonly', False)]}), 'event_id': fields.many2one('event.event', 'Event', required=True, readonly=True, states={'draft': [('readonly', False)]}),
'partner_id': fields.many2one('res.partner', 'Partner', states={'done': [('readonly', True)]}), 'partner_id': fields.many2one('res.partner', 'Partner', states={'done': [('readonly', True)]}),

View File

@ -15,7 +15,7 @@
id="event_main_menu" id="event_main_menu"
groups="base.group_user" groups="base.group_user"
sequence="80"/> sequence="80"/>
<menuitem name="Events Organisation" id="base.menu_event_main" parent="event_main_menu"/> <menuitem name="Events Organization" id="base.menu_event_main" parent="event_main_menu"/>
<!-- EVENTS --> <!-- EVENTS -->
@ -219,7 +219,7 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="Events" fonts="bold:message_unread==True" colors="red:(register_min and register_min&gt;register_current) or (register_max and register_max&lt;register_current);grey:state=='cancel'"> <tree string="Events" fonts="bold:message_unread==True" colors="red:(register_min and register_min&gt;register_current) or (register_max and register_max&lt;register_current);grey:state=='cancel'">
<field name="name" string="Name"/> <field name="name" string="Name"/>
<field name="type"/> <field name="type" string="Event Category"/>
<field name="date_begin"/> <field name="date_begin"/>
<field name="date_end"/> <field name="date_end"/>
<field name="register_current"/> <field name="register_current"/>
@ -267,17 +267,17 @@
<t t-if="record.country_id.raw_value">@<field name="country_id"/><br/></t> <t t-if="record.country_id.raw_value">@<field name="country_id"/><br/></t>
<t t-if="record.user_id.raw_value">Organized by <field name="user_id"/><br/></t> <t t-if="record.user_id.raw_value">Organized by <field name="user_id"/><br/></t>
<t t-if="record.register_avail.raw_value lte 10 and record.register_avail.raw_value gt 0"><i>Only</i></t> <t t-if="record.register_avail.raw_value lte 10 and record.register_avail.raw_value gt 0"><i>Only</i></t>
<t t-if="record.register_avail.raw_value == 0"><i>No ticket available.</i></t> <t t-if="record.register_avail.raw_value == 9999"><i>No ticket available.</i></t>
<t t-if="record.register_avail.raw_value != 0"> <t t-if="record.register_avail.raw_value != 9999">
<i><b><t t-if="record.register_avail.raw_value != 9999"><field name="register_avail"/></t></b></i> <i><b><t t-if="record.register_avail.raw_value != 9999"><field name="register_avail"/></t></b></i>
<i> <i>
<t t-if="record.register_avail.raw_value > 1">tickets </t> <t t-if="record.register_avail.raw_value > 1">tickets </t>
<t t-if="record.register_avail.raw_value == 1 || !record.register_avail.raw_value > 1">ticket </t> <t t-if="record.register_avail.raw_value lte 1">ticket </t>
available. available.
</i> </i>
</t> </t>
</p> </p>
<t t-if="record.register_avail.raw_value != 0"> <t t-if="record.register_avail.raw_value gt 0 and record.register_avail.raw_value lt 9999">
<t t-if="!record.is_subscribed.raw_value"> <t t-if="!record.is_subscribed.raw_value">
<input t-att-id="record.id.raw_value" type="text" name="subscribe" class="no_of_seats" value="1" onchange="document.getElementById('btn_sub' +this.id).setAttribute('data-context',JSON.stringify({'ticket':this.value}))"/> <input t-att-id="record.id.raw_value" type="text" name="subscribe" class="no_of_seats" value="1" onchange="document.getElementById('btn_sub' +this.id).setAttribute('data-context',JSON.stringify({'ticket':this.value}))"/>
<button t-att-id="'btn_sub'+record.id.raw_value" type="object" name="subscribe_to_event" class="oe_subscribe_button"> <button t-att-id="'btn_sub'+record.id.raw_value" type="object" name="subscribe_to_event" class="oe_subscribe_button">

View File

@ -8,7 +8,7 @@
<form string="Configure Moodle" version="7.0"> <form string="Configure Moodle" version="7.0">
<header> <header>
<button type="object" name="configure_moodle" <button type="object" name="configure_moodle"
string="Configure Moodle" class="oe_highlight" /> string="Apply" class="oe_highlight" />
or or
<button string="Cancel" class="oe_link" special="cancel" /> <button string="Cancel" class="oe_link" special="cancel" />
</header> </header>
@ -16,12 +16,12 @@
<separator string="Server" colspan="4"/> <separator string="Server" colspan="4"/>
<field name="server_moodle"/> <field name="server_moodle"/>
<newline/> <newline/>
<separator string="Connexion with a Token" colspan="4"/> <separator string="Connection with a Token" colspan="4"/>
<label string="The easiest way to connect OpenERP with a moodle server is to create a 'token' in Moodle. It will be used to authenticate OpenERP as a trustable application." colspan="4"/> <label string="The easiest way to connect OpenERP with a moodle server is to create a 'token' in Moodle. It will be used to authenticate OpenERP as a trustable application." colspan="4"/>
<field name="moodle_token"/> <field name="moodle_token"/>
<newline/> <newline/>
<separator string="Connexion with Password and Username" colspan="4"/> <separator string="Connection with username and password" colspan="4"/>
<label string="Another approach is to create a user for OpenERP in Moodle. If you do so, make sure that this user has enough access rights" colspan="4"/> <label string="Another approach is to create a user for OpenERP in Moodle. If you do so, make sure that this user has appropriate access rights." colspan="4"/>
<field name="moodle_username"/> <field name="moodle_username"/>
<field name="moodle_password"/> <field name="moodle_password"/>
</group> </group>

View File

@ -112,7 +112,7 @@ class hr_job(osv.osv):
'requirements': fields.text('Requirements'), 'requirements': fields.text('Requirements'),
'department_id': fields.many2one('hr.department', 'Department'), 'department_id': fields.many2one('hr.department', 'Department'),
'company_id': fields.many2one('res.company', 'Company'), 'company_id': fields.many2one('res.company', 'Company'),
'state': fields.selection([('open', 'In Position'), ('recruit', 'In Recruitement')], 'Status', readonly=True, required=True, 'state': fields.selection([('open', 'No Recruitment'), ('recruit', 'Recruitement in Progress')], 'Status', readonly=True, required=True,
help="By default 'In position', set it to 'In Recruitment' if recruitment process is going on for this job position."), help="By default 'In position', set it to 'In Recruitment' if recruitment process is going on for this job position."),
} }
_defaults = { _defaults = {

View File

@ -330,8 +330,8 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Job" version="7.0"> <form string="Job" version="7.0">
<header> <header>
<button name="job_recruitement" string="In Recruitement" states="open" type="object" class="oe_highlight" groups="base.group_user"/> <button name="job_recruitement" string="Launch Recruitement" states="open" type="object" class="oe_highlight" groups="base.group_user"/>
<button name="job_open" string="Recruitment Done" states="recruit" type="object" class="oe_highlight" groups="base.group_user"/> <button name="job_open" string="Stop Recruitment" states="recruit" type="object" class="oe_highlight" groups="base.group_user"/>
<field name="state" widget="statusbar" statusbar_visible="recruit,open"/> <field name="state" widget="statusbar" statusbar_visible="recruit,open"/>
</header> </header>
<sheet> <sheet>

View File

@ -7,14 +7,14 @@ msgstr ""
"Project-Id-Version: OpenERP Server 6.0dev\n" "Project-Id-Version: OpenERP Server 6.0dev\n"
"Report-Msgid-Bugs-To: support@openerp.com\n" "Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-02-08 01:37+0100\n" "POT-Creation-Date: 2012-02-08 01:37+0100\n"
"PO-Revision-Date: 2012-08-18 17:32+0000\n" "PO-Revision-Date: 2012-10-25 16:29+0000\n"
"Last-Translator: Heling Yao <Unknown>\n" "Last-Translator: fenshuajiang <openerp@126.com>\n"
"Language-Team: \n" "Language-Team: \n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-10-19 05:21+0000\n" "X-Launchpad-Export-Date: 2012-10-26 04:56+0000\n"
"X-Generator: Launchpad (build 16165)\n" "X-Generator: Launchpad (build 16194)\n"
#. module: hr #. module: hr
#: model:process.node,name:hr.process_node_openerpuser0 #: model:process.node,name:hr.process_node_openerpuser0
@ -181,7 +181,7 @@ msgstr "女性"
#: help:hr.job,expected_employees:0 #: help:hr.job,expected_employees:0
msgid "" msgid ""
"Expected number of employees for this job position after new recruitment." "Expected number of employees for this job position after new recruitment."
msgstr "" msgstr "新的招聘后这个工作岗位上期望的员工人数"
#. module: hr #. module: hr
#: model:ir.ui.menu,name:hr.menu_open_view_attendance_reason_new_config #: model:ir.ui.menu,name:hr.menu_open_view_attendance_reason_new_config
@ -685,7 +685,7 @@ msgstr "下属"
#. module: hr #. module: hr
#: field:hr.job,no_of_employee:0 #: field:hr.job,no_of_employee:0
msgid "Number of employees currently occupying this job position." msgid "Number of employees currently occupying this job position."
msgstr "" msgstr "这个工作岗位上现有的员工人数"
#. module: hr #. module: hr
#: field:hr.job,no_of_recruitment:0 #: field:hr.job,no_of_recruitment:0

View File

@ -8,14 +8,14 @@ msgstr ""
"Project-Id-Version: openobject-addons\n" "Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" "Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-02-08 01:37+0100\n" "POT-Creation-Date: 2012-02-08 01:37+0100\n"
"PO-Revision-Date: 2012-05-10 17:47+0000\n" "PO-Revision-Date: 2012-10-25 17:16+0000\n"
"Last-Translator: Jeff Wang <wjfonhand@hotmail.com>\n" "Last-Translator: ccdos <Unknown>\n"
"Language-Team: Chinese (Simplified) <zh_CN@li.org>\n" "Language-Team: Chinese (Simplified) <zh_CN@li.org>\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-10-19 05:27+0000\n" "X-Launchpad-Export-Date: 2012-10-26 04:56+0000\n"
"X-Generator: Launchpad (build 16165)\n" "X-Generator: Launchpad (build 16194)\n"
#. module: hr_evaluation #. module: hr_evaluation
#: help:hr_evaluation.plan.phase,send_anonymous_manager:0 #: help:hr_evaluation.plan.phase,send_anonymous_manager:0
@ -304,7 +304,7 @@ msgstr "上个月完成的评估"
#. module: hr_evaluation #. module: hr_evaluation
#: model:ir.model,name:hr_evaluation.model_mail_compose_message #: model:ir.model,name:hr_evaluation.model_mail_compose_message
msgid "Email composition wizard" msgid "Email composition wizard"
msgstr "" msgstr "电子邮件撰写向导"
#. module: hr_evaluation #. module: hr_evaluation
#: view:hr.evaluation.report:0 #: view:hr.evaluation.report:0

View File

@ -64,15 +64,15 @@ class hr_expense_expense(osv.osv):
_description = "Expense" _description = "Expense"
_order = "id desc" _order = "id desc"
_columns = { _columns = {
'name': fields.char('Description', size=128, required=True), 'name': fields.char('Description', size=128),
'id': fields.integer('Sheet ID', readonly=True), 'id': fields.integer('Sheet ID', readonly=True),
'date': fields.date('Date', select=True), 'date': fields.date('Date', select=True),
'journal_id': fields.many2one('account.journal', 'Force Journal', help = "The journal used when the expense is done."), 'journal_id': fields.many2one('account.journal', 'Force Journal', help = "The journal used when the expense is done."),
'employee_id': fields.many2one('hr.employee', "Employee", required=True), 'employee_id': fields.many2one('hr.employee', "Employee", required=True),
'user_id': fields.many2one('res.users', 'User', required=True), 'user_id': fields.many2one('res.users', 'User', required=True),
'date_confirm': fields.date('Confirmation Date', select=True, help = "Date of the confirmation of the sheet expense. It's filled when the button Confirm is pressed."), 'date_confirm': fields.date('Confirmation Date', select=True, help="Date of the confirmation of the sheet expense. It's filled when the button Confirm is pressed."),
'date_valid': fields.date('Validation Date', select=True, help = "Date of the acceptation of the sheet expense. It's filled when the button Accept is pressed."), 'date_valid': fields.date('Validation Date', select=True, help="Date of the acceptation of the sheet expense. It's filled when the button Accept is pressed."),
'user_valid': fields.many2one('res.users', 'Validation User'), 'user_valid': fields.many2one('res.users', 'Validation By'),
'account_move_id': fields.many2one('account.move', 'Ledger Posting'), 'account_move_id': fields.many2one('account.move', 'Ledger Posting'),
'line_ids': fields.one2many('hr.expense.line', 'expense_id', 'Expense Lines', readonly=True, states={'draft':[('readonly',False)]} ), 'line_ids': fields.one2many('hr.expense.line', 'expense_id', 'Expense Lines', readonly=True, states={'draft':[('readonly',False)]} ),
'note': fields.text('Note'), 'note': fields.text('Note'),
@ -189,7 +189,7 @@ class hr_expense_expense(osv.osv):
raise osv.except_osv(_('Error!'), _('The employee must have a home address.')) raise osv.except_osv(_('Error!'), _('The employee must have a home address.'))
acc = exp.employee_id.address_home_id.property_account_payable.id acc = exp.employee_id.address_home_id.property_account_payable.id
voucher = { voucher = {
'name': exp.name, 'name': exp.name or '/',
'reference': sequence_obj.get(cr, uid, 'hr.expense.invoice'), 'reference': sequence_obj.get(cr, uid, 'hr.expense.invoice'),
'account_id': acc, 'account_id': acc,
'type': 'purchase', 'type': 'purchase',
@ -233,7 +233,7 @@ hr_expense_expense()
class product_product(osv.osv): class product_product(osv.osv):
_inherit = "product.product" _inherit = "product.product"
_columns = { _columns = {
'hr_expense_ok': fields.boolean('Can Constitute an Expense', help="Determines if the product can be visible in the list of product within a selection from an HR expense sheet line."), 'hr_expense_ok': fields.boolean('Can be Expensed', help="Determines if the product can be visible in the list of product within a selection from an HR expense sheet line."),
} }
def on_change_hr_expense_ok(self, cr, uid, id, hr_expense_ok): def on_change_hr_expense_ok(self, cr, uid, id, hr_expense_ok):

View File

@ -79,7 +79,7 @@
</group> </group>
<group> <group>
<field name="name"/> <field name="name"/>
<field name="user_valid"/> <field name="user_valid" attrs="{'invisible': [('state','=','draft')]}"/>
<field name="currency_id" groups="base.group_multi_currency" on_change="onchange_currency_id(currency_id, company_id)"/> <field name="currency_id" groups="base.group_multi_currency" on_change="onchange_currency_id(currency_id, company_id)"/>
</group> </group>
</group> </group>
@ -128,9 +128,9 @@
</group> </group>
</group> </group>
</page> </page>
<page string="Other Info"> <page string="Accounting" groups="account.group_account_user">
<group> <group>
<group string="Accounting Data" groups="account.group_account_user"> <group string="Accounting Data">
<field name="journal_id" widget="selection" domain="[('type', '=', 'purchase')]"/> <field name="journal_id" widget="selection" domain="[('type', '=', 'purchase')]"/>
<field name="voucher_id" context="{'form_view_ref': 'account_voucher.view_purchase_receipt_form'}"/> <field name="voucher_id" context="{'form_view_ref': 'account_voucher.view_purchase_receipt_form'}"/>
</group> </group>

View File

@ -115,10 +115,10 @@ class hr_holidays(osv.osv):
_columns = { _columns = {
'name': fields.char('Description', size=64), 'name': fields.char('Description', size=64),
'state': fields.selection([('draft', 'To Submit'), ('cancel', 'Cancelled'),('confirm', 'To Approve'), ('refuse', 'Refused'), ('validate1', 'Second Approval'), ('validate', 'Approved')], 'state': fields.selection([('draft', 'To Submit'), ('cancel', 'Cancelled'),('confirm', 'To Approve'), ('refuse', 'Refused'), ('validate1', 'Second Approval'), ('validate', 'Approved')],
'State', readonly=True, help='The state is set to \'To Submit\', when a holiday request is created.\ 'Status', readonly=True, help='The status is set to \'To Submit\', when a holiday request is created.\
\nThe state is \'To Approve\', when holiday request is confirmed by user.\ \nThe status is \'To Approve\', when holiday request is confirmed by user.\
\nThe state is \'Refused\', when holiday request is refused by manager.\ \nThe status is \'Refused\', when holiday request is refused by manager.\
\nThe state is \'Approved\', when holiday request is approved by manager.'), \nThe status is \'Approved\', when holiday request is approved by manager.'),
'user_id':fields.related('employee_id', 'user_id', type='many2one', relation='res.users', string='User', store=True), 'user_id':fields.related('employee_id', 'user_id', type='many2one', relation='res.users', string='User', store=True),
'date_from': fields.datetime('Start Date', readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}, select=True), 'date_from': fields.datetime('Start Date', readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}, select=True),
'date_to': fields.datetime('End Date', readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}), 'date_to': fields.datetime('End Date', readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}),

View File

@ -272,10 +272,10 @@ class hr_payslip(osv.osv):
('done', 'Done'), ('done', 'Done'),
('cancel', 'Rejected'), ('cancel', 'Rejected'),
], 'Status', select=True, readonly=True, ], 'Status', select=True, readonly=True,
help='* When the payslip is created the state is \'Draft\'.\ help='* When the payslip is created the status is \'Draft\'.\
\n* If the payslip is under verification, the state is \'Waiting\'. \ \n* If the payslip is under verification, the status is \'Waiting\'. \
\n* If the payslip is confirmed then state is set to \'Done\'.\ \n* If the payslip is confirmed then status is set to \'Done\'.\
\n* When user cancel payslip the state is \'Rejected\'.'), \n* When user cancel payslip the status is \'Rejected\'.'),
# 'line_ids': fields.one2many('hr.payslip.line', 'slip_id', 'Payslip Line', required=False, readonly=True, states={'draft': [('readonly', False)]}), # 'line_ids': fields.one2many('hr.payslip.line', 'slip_id', 'Payslip Line', required=False, readonly=True, states={'draft': [('readonly', False)]}),
'line_ids': one2many_mod2('hr.payslip.line', 'slip_id', 'Payslip Lines', readonly=True, states={'draft':[('readonly',False)]}), 'line_ids': one2many_mod2('hr.payslip.line', 'slip_id', 'Payslip Lines', readonly=True, states={'draft':[('readonly',False)]}),
'company_id': fields.many2one('res.company', 'Company', required=False, readonly=True, states={'draft': [('readonly', False)]}), 'company_id': fields.many2one('res.company', 'Company', required=False, readonly=True, states={'draft': [('readonly', False)]}),

View File

@ -62,7 +62,7 @@ class hr_recruitment_stage(osv.osv):
'name': fields.char('Name', size=64, required=True, translate=True), 'name': fields.char('Name', size=64, required=True, translate=True),
'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of stages."), 'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of stages."),
'department_id':fields.many2one('hr.department', 'Specific to a Department', help="Stages of the recruitment process may be different per department. If this stage is common to all departments, keep this field empty."), 'department_id':fields.many2one('hr.department', 'Specific to a Department', help="Stages of the recruitment process may be different per department. If this stage is common to all departments, keep this field empty."),
'state': fields.selection(AVAILABLE_STATES, 'State', required=True, help="The related state for the stage. The state of your document will automatically change according to the selected stage. Example, a stage is related to the state 'Close', when your document reach this stage, it will be automatically closed."), 'state': fields.selection(AVAILABLE_STATES, 'Status', required=True, help="The related status for the stage. The status of your document will automatically change according to the selected stage. Example, a stage is related to the status 'Close', when your document reach this stage, it will be automatically closed."),
'fold': fields.boolean('Hide in views if empty', help="This stage is not visible, for example in status bar or kanban view, when there are no records in that stage to display."), 'fold': fields.boolean('Hide in views if empty', help="This stage is not visible, for example in status bar or kanban view, when there are no records in that stage to display."),
'requirements': fields.text('Requirements'), 'requirements': fields.text('Requirements'),
} }
@ -189,11 +189,11 @@ class hr_applicant(base_stage, osv.Model):
'stage_id': fields.many2one ('hr.recruitment.stage', 'Stage', 'stage_id': fields.many2one ('hr.recruitment.stage', 'Stage',
domain="['&', ('fold', '=', False), '|', ('department_id', '=', department_id), ('department_id', '=', False)]"), domain="['&', ('fold', '=', False), '|', ('department_id', '=', department_id), ('department_id', '=', False)]"),
'state': fields.related('stage_id', 'state', type="selection", store=True, 'state': fields.related('stage_id', 'state', type="selection", store=True,
selection=AVAILABLE_STATES, string="State", readonly=True, selection=AVAILABLE_STATES, string="Status", readonly=True,
help='The state is set to \'Draft\', when a case is created.\ help='The status is set to \'Draft\', when a case is created.\
If the case is in progress the state is set to \'Open\'.\ If the case is in progress the status is set to \'Open\'.\
When the case is over, the state is set to \'Done\'.\ When the case is over, the status is set to \'Done\'.\
If the case needs to be reviewed then the state is \ If the case needs to be reviewed then the status is \
set to \'Pending\'.'), set to \'Pending\'.'),
'categ_ids': fields.many2many('hr.applicant_category', string='Tags'), 'categ_ids': fields.many2many('hr.applicant_category', string='Tags'),
'company_id': fields.many2one('res.company', 'Company'), 'company_id': fields.many2one('res.company', 'Company'),

View File

@ -107,7 +107,7 @@
<form string="Jobs - Recruitment Form" version="7.0"> <form string="Jobs - Recruitment Form" version="7.0">
<header> <header>
<button name="case_close_with_emp" string="Hire" type="object" <button name="case_close_with_emp" string="Hire" type="object"
states="draft,open,pending" class="oe_highlight"/> states="draft,open,pending,done" class="oe_highlight"/>
<button name="case_cancel" string="Refuse" type="object" <button name="case_cancel" string="Refuse" type="object"
states="draft,open,pending" class="oe_highlight"/> states="draft,open,pending" class="oe_highlight"/>
<field name="stage_id" widget="statusbar" clickable="True"/> <field name="stage_id" widget="statusbar" clickable="True"/>

View File

@ -41,7 +41,7 @@ class hr_recruitment_report(osv.osv):
_columns = { _columns = {
'user_id': fields.many2one('res.users', 'User', readonly=True), 'user_id': fields.many2one('res.users', 'User', readonly=True),
'nbr': fields.integer('# of Applications', readonly=True), 'nbr': fields.integer('# of Applications', readonly=True),
'state': fields.selection(AVAILABLE_STATES, 'State', size=16, readonly=True), 'state': fields.selection(AVAILABLE_STATES, 'Status', size=16, readonly=True),
'month':fields.selection([('01', 'January'), ('02', 'February'), \ 'month':fields.selection([('01', 'January'), ('02', 'February'), \
('03', 'March'), ('04', 'April'),\ ('03', 'March'), ('04', 'April'),\
('05', 'May'), ('06', 'June'), \ ('05', 'May'), ('06', 'June'), \

View File

@ -7,14 +7,14 @@ msgstr ""
"Project-Id-Version: OpenERP Server 6.0dev\n" "Project-Id-Version: OpenERP Server 6.0dev\n"
"Report-Msgid-Bugs-To: support@openerp.com\n" "Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-02-08 00:36+0000\n" "POT-Creation-Date: 2012-02-08 00:36+0000\n"
"PO-Revision-Date: 2012-05-10 18:19+0000\n" "PO-Revision-Date: 2012-10-25 17:20+0000\n"
"Last-Translator: Jeff Wang <wjfonhand@hotmail.com>\n" "Last-Translator: ccdos <Unknown>\n"
"Language-Team: \n" "Language-Team: \n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-10-19 05:15+0000\n" "X-Launchpad-Export-Date: 2012-10-26 04:56+0000\n"
"X-Generator: Launchpad (build 16165)\n" "X-Generator: Launchpad (build 16194)\n"
#. module: hr_timesheet #. module: hr_timesheet
#: code:addons/hr_timesheet/report/user_timesheet.py:43 #: code:addons/hr_timesheet/report/user_timesheet.py:43
@ -468,7 +468,7 @@ msgstr "一般信息"
#. module: hr_timesheet #. module: hr_timesheet
#: model:ir.actions.act_window,name:hr_timesheet.action_hr_timesheet_my #: model:ir.actions.act_window,name:hr_timesheet.action_hr_timesheet_my
msgid "My Current Timesheet" msgid "My Current Timesheet"
msgstr "" msgstr "我当前的时间表"
#. module: hr_timesheet #. module: hr_timesheet
#: code:addons/hr_timesheet/report/user_timesheet.py:40 #: code:addons/hr_timesheet/report/user_timesheet.py:40

View File

@ -33,7 +33,7 @@ class hr_so_project(osv.osv_memory):
'date': fields.datetime('Closing Date'), 'date': fields.datetime('Closing Date'),
'analytic_amount': fields.float('Minimum Analytic Amount'), 'analytic_amount': fields.float('Minimum Analytic Amount'),
'name': fields.char('Employees name', size=32, required=True, readonly=True), 'name': fields.char('Employees name', size=32, required=True, readonly=True),
'state': fields.related('emp_id', 'state', string='Current state', type='char', required=True, readonly=True), 'state': fields.related('emp_id', 'state', string='Current Status', type='char', required=True, readonly=True),
'server_date': fields.datetime('Current Date', required=True, readonly=True), 'server_date': fields.datetime('Current Date', required=True, readonly=True),
'emp_id': fields.many2one('hr.employee', 'Employee ID') 'emp_id': fields.many2one('hr.employee', 'Employee ID')
} }
@ -111,7 +111,7 @@ class hr_si_project(osv.osv_memory):
_description = 'Sign In By Project' _description = 'Sign In By Project'
_columns = { _columns = {
'name': fields.char('Employees name', size=32, readonly=True), 'name': fields.char('Employees name', size=32, readonly=True),
'state': fields.related('emp_id', 'state', string='Current state', type='char', required=True, readonly=True), 'state': fields.related('emp_id', 'state', string='Current Status', type='char', required=True, readonly=True),
'date': fields.datetime('Starting Date'), 'date': fields.datetime('Starting Date'),
'server_date': fields.datetime('Current Date', readonly=True), 'server_date': fields.datetime('Current Date', readonly=True),
'emp_id': fields.many2one('hr.employee', 'Employee ID') 'emp_id': fields.many2one('hr.employee', 'Employee ID')

View File

@ -206,9 +206,9 @@ class hr_timesheet_sheet(osv.osv):
('draft','Open'), ('draft','Open'),
('confirm','Waiting Approval'), ('confirm','Waiting Approval'),
('done','Approved')], 'Status', select=True, required=True, readonly=True, ('done','Approved')], 'Status', select=True, required=True, readonly=True,
help=' * The \'Draft\' state is used when a user is encoding a new and unconfirmed timesheet. \ help=' * The \'Draft\' status is used when a user is encoding a new and unconfirmed timesheet. \
\n* The \'Confirmed\' state is used for to confirm the timesheet by user. \ \n* The \'Confirmed\' status is used for to confirm the timesheet by user. \
\n* The \'Done\' state is used when users timesheet is accepted by his/her senior.'), \n* The \'Done\' status is used when users timesheet is accepted by his/her senior.'),
'state_attendance' : fields.related('employee_id', 'state', type='selection', selection=[('absent', 'Absent'), ('present', 'Present')], string='Current Status', readonly=True), 'state_attendance' : fields.related('employee_id', 'state', type='selection', selection=[('absent', 'Absent'), ('present', 'Present')], string='Current Status', readonly=True),
'total_attendance': fields.function(_total, method=True, string='Total Attendance', multi="_total"), 'total_attendance': fields.function(_total, method=True, string='Total Attendance', multi="_total"),
'total_timesheet': fields.function(_total, method=True, string='Total Timesheet', multi="_total"), 'total_timesheet': fields.function(_total, method=True, string='Total Timesheet', multi="_total"),

View File

@ -54,18 +54,18 @@
</header> </header>
<sheet> <sheet>
<label for="employee_id" class="oe_edit_only"/> <label for="employee_id" class="oe_edit_only"/>
<h1><field name="employee_id" on_change="onchange_employee_id(employee_id)"/></h1> <h1><field name="employee_id" on_change="onchange_employee_id(employee_id)" class="oe_inline"/></h1>
<group> <group>
<group> <group>
<label for="date_from" string="Timesheet Period"/> <label for="date_from" string="Timesheet Period"/>
<div><field name="date_from"/> to <field name="date_to"/></div> <div><field name="date_from" class="oe_inline"/> to <field name="date_to" class="oe_inline"/></div>
<field name="name" invisible="1"/> <field name="name" invisible="1"/>
<field name="department_id"/> <field name="department_id" invisible="1"/>
<field name="company_id" groups="base.group_multi_company"/> <field name="company_id" groups="base.group_multi_company"/>
</group> </group>
<group> <group>
<field name="total_attendance" widget="float_time" groups="base.group_hr_attendance"/> <field name="total_attendance" widget="float_time" groups="base.group_hr_attendance"/>
<field name="total_timesheet" widget="float_time"/> <field name="total_timesheet" widget="float_time" groups="base.group_hr_attendance"/>
<field name="total_difference" widget="float_time" groups="base.group_hr_attendance"/> <field name="total_difference" widget="float_time" groups="base.group_hr_attendance"/>
<field name="user_id" invisible="1"/> <field name="user_id" invisible="1"/>
</group> </group>
@ -76,8 +76,8 @@
</widget> </widget>
</page> </page>
<page string="Daily"> <page string="Daily">
<group colspan="4" col="3"> <group groups="base.group_hr_attendance">
<field context="{'user_id':user_id}" name="attendances_ids" nolabel="1" groups="base.group_hr_attendance"> <field context="{'user_id':user_id}" name="attendances_ids" nolabel="1">
<tree string="Attendances" editable="bottom"> <tree string="Attendances" editable="bottom">
<field name="name"/> <field name="name"/>
<field name="action"/> <field name="action"/>
@ -85,21 +85,19 @@
</tree> </tree>
</field> </field>
<group> <group>
<div align="right" groups="base.group_hr_manager,base.group_hr_attendance"> <field name="state_attendance" nolabel="1"/>
<button name="attendance_action_change" attrs="{'invisible': [('state_attendance', '=', 'present')]}" type="object" string="Sign In" groups="base.group_hr_attendance"/> <div align="right" groups="base.group_hr_manager">
<button name="attendance_action_change" attrs="{'invisible': ['|', ('state_attendance','=',False), ('state_attendance', '=', 'absent')]}" type="object" string="Sign Out" groups="base.group_hr_attendance"/> <button name="attendance_action_change" attrs="{'invisible': [('state_attendance', '=', 'present')]}" type="object" string="Sign In"/>
<button name="attendance_action_change" attrs="{'invisible': ['|', ('state_attendance','=',False), ('state_attendance', '=', 'absent')]}" type="object" string="Sign Out"/>
</div> </div>
</group> </group>
</group> </group>
<group col="4"> <field context="{'user_id':user_id}" name="timesheet_ids" nolabel="1">
<field name="state_attendance" groups="base.group_hr_attendance"/>
</group>
<field colspan="4" context="{'user_id':user_id}" name="timesheet_ids" nolabel="1">
<tree editable="top" string="Timesheet Lines"> <tree editable="top" string="Timesheet Lines">
<field name="date"/> <field name="date"/>
<field domain="[('type','in',['normal', 'contract']), ('state', '&lt;&gt;', 'close'),('use_timesheets','=',1)]" name="account_id" on_change="on_change_account_id(account_id, user_id)" context="{'default_use_timesheets': 1}"/> <field domain="[('type','in',['normal', 'contract']), ('state', '&lt;&gt;', 'close'),('use_timesheets','=',1)]" name="account_id" on_change="on_change_account_id(account_id, user_id)" context="{'default_use_timesheets': 1}"/>
<field name="name"/> <field name="name"/>
<field name="unit_amount" on_change="on_change_unit_amount(product_id, unit_amount, False, product_uom_id,journal_id)" widget="float_time"/> <field name="unit_amount" on_change="on_change_unit_amount(product_id, unit_amount, False, product_uom_id,journal_id)" widget="float_time" string="Hours"/>
<field name="to_invoice" widget="selection"/> <field name="to_invoice" widget="selection"/>
<field invisible="1" name="journal_id"/> <field invisible="1" name="journal_id"/>
<field invisible="1" name="product_id" domain="[('type','=','service')]" on_change="on_change_unit_amount(product_id, unit_amount, False, product_uom_id,journal_id)"/> <field invisible="1" name="product_id" domain="[('type','=','service')]" on_change="on_change_unit_amount(product_id, unit_amount, False, product_uom_id,journal_id)"/>
@ -123,13 +121,13 @@
</form> </form>
</field> </field>
</page> </page>
<page string="Summary"> <page string="Summary" groups="base.group_hr_attendance">
<field colspan="4" name="period_ids" nolabel="1"> <field name="period_ids">
<tree colors="red:total_difference&lt;0.1;blue:total_difference&gt;=0.1" string="Period"> <tree colors="red:total_difference&lt;0.1;blue:total_difference&gt;=0.1" string="Period">
<field name="name"/> <field name="name"/>
<field name="total_attendance" widget="float_time" groups="base.group_hr_attendance"/> <field name="total_attendance" widget="float_time"/>
<field name="total_timesheet" widget="float_time"/> <field name="total_timesheet" widget="float_time"/>
<field name="total_difference" widget="float_time" groups="base.group_hr_attendance"/> <field name="total_difference" widget="float_time"/>
</tree> </tree>
</field> </field>
</page> </page>

View File

@ -12,7 +12,7 @@
<t t-esc="date.toString('MMM d')"/> <t t-esc="date.toString('MMM d')"/>
</th> </th>
</t> </t>
<th class="oe_timesheet_weekly_date_head">TOTAL</th> <th class="oe_timesheet_weekly_date_head">Total</th>
</tr> </tr>
<tr t-foreach="widget.accounts" t-as="account"> <tr t-foreach="widget.accounts" t-as="account">
<td class="oe_timesheet_weekly_account"><t t-esc="widget.account_names[account.account]"/></td> <td class="oe_timesheet_weekly_account"><t t-esc="widget.account_names[account.account]"/></td>
@ -36,8 +36,8 @@
<tr> <tr>
<td> <td>
<div class="oe_timesheet_weekly_adding_tot"> <div class="oe_timesheet_weekly_adding_tot">
<div class="oe_timesheet_weekly_adding"><button>Add Row</button></div> <div class="oe_timesheet_weekly_adding"><button>Add a Project</button></div>
<div class="oe_timesheet_weekly_tottot"><span>TOTAL</span></div> <div class="oe_timesheet_weekly_tottot"><span>Total</span></div>
</div> </div>
</td> </td>
<t t-set="day_count" t-value="0"/> <t t-set="day_count" t-value="0"/>
@ -53,4 +53,4 @@
</table> </table>
</div> </div>
</t> </t>
</templates> </templates>

View File

@ -2,13 +2,9 @@
<openerp> <openerp>
<data> <data>
<record id="config_call_account_template_ar" model="ir.actions.todo"> <record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="name">Generate Chart of Accounts from a Chart Template</field> <field name="state">open</field>
<field name="note">Generate Chart of Accounts from a Chart Template. You will be asked to pass the name of the company, the chart template to follow, the no. of digits to generate the code for your accounts and Bank account, currency to create Journals. Thus,the pure copy of chart Template is generated. </record>
This is the same wizard that runs from Financial Management/Configuration/Financial Accounting/Financial Accounts/Generate Chart of Accounts from a Chart Template.</field>
<field name="action_id" ref="account.action_wizard_multi_chart"/>
<field name="type">automatic</field>
</record>
</data> </data>
</openerp> </openerp>

View File

@ -1,12 +1,8 @@
<openerp> <openerp>
<data> <data>
<record id="config_call_account_template_at" model="ir.actions.todo"> <record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="name">Generate Chart of Accounts from a Chart Template</field> <field name="state">open</field>
<field name="note">Generate Chart of Accounts from a Chart Template. You will be asked to pass the name of the company, the chart template to follow, the no. of digits to generate the code for your accounts and Bank account, currency to create Journals. Thus,the pure copy of chart Template is generated.
This is the same wizard that runs from Financial Management/Configuration/Financial Accounting/Financial Accounts/Generate Chart of Accounts from a Chart Template.</field>
<field name="action_id" ref="account.action_wizard_multi_chart"/>
<field name="type">automatic</field>
</record> </record>
</data> </data>

View File

@ -1,10 +1,6 @@
-
!record {model: ir.actions.todo, id: config_call_account_template}:
action_id: account.action_wizard_multi_chart
type: automatic
- -
!python {model: ir.actions.todo}: | !python {model: ir.actions.todo}: |
install_todo = self.browse(cr, uid, ref('l10n_be.config_call_account_template')) install_todo = self.browse(cr, uid, ref('account.action_wizard_multi_chart_todo'))
if install_todo.state == 'open': if install_todo.state == 'open':
wiz = self.pool.get('wizard.multi.charts.accounts') wiz = self.pool.get('wizard.multi.charts.accounts')
values = { values = {

View File

@ -1,13 +1,9 @@
<openerp> <openerp>
<data> <data>
<record id="config_call_account_template_ca" model="ir.actions.todo"> <record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="name">Generate Chart of Accounts from a Chart Template</field> <field name="state">open</field>
<field name="note">Generate Chart of Accounts from a Chart Template. You will be asked to pass the name of the company, the chart template to follow, the no. of digits to generate the code for your accounts and Bank account, currency to create Journals. Thus,the pure copy of chart Template is generated. </record>
This is the same wizard that runs from Financial Management/Configuration/Financial Accounting/Financial Accounts/Generate Chart of Accounts from a Chart Template.</field>
<field name="action_id" ref="account.action_wizard_multi_chart"/>
<field name="type">automatic</field>
</record>
</data> </data>
</openerp> </openerp>

View File

@ -1,13 +1,7 @@
<openerp> <openerp>
<data> <data>
<record id="config_call_account_template_l10n_ch" model="ir.actions.todo"> <record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="name">Generate Chart of Accounts for l10n_ch</field> <field name="state">open</field>
<field name="note">Generate Chart of Accounts from a Chart Template. Please let the nuber to 0 for Swiss charts.
This is the same wizard that runs from Financial Management/Configuration/Financial Accounting/Financial
Accounts/Generate Chart of Accounts from a Chart Template.</field>
<field name="action_id" ref="account.action_wizard_multi_chart"/>
<field name="sequence">4</field>
<field name="type">automatic</field>
</record> </record>
</data> </data>
</openerp> </openerp>

View File

@ -1,14 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<openerp> <openerp>
<data> <data>
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<record id="config_call_account_template_cl" model="ir.actions.todo"> <field name="state">open</field>
<field name="name">Generate Chart of Accounts from a Chart Template</field> </record>
<field name="note">Generate Chart of Accounts from a Chart Template. You will be asked to pass the name of the company, the chart template to follow, the no. of digits to generate the code for your accounts and Bank account, currency to create Journals. Thus,the pure copy of chart Template is generated.
This is the same wizard that runs from Financial Management/Configuration/Financial Accounting/Financial Accounts/Generate Chart of Accounts from a Chart Template.</field>
<field name="action_id" ref="account.action_wizard_multi_chart"/>
<field name="type">automatic</field>
</record>
</data> </data>
</openerp> </openerp>

View File

@ -1,12 +1,7 @@
<openerp> <openerp>
<data> <data>
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<record id="config_call_account_template_cn_chart" model="ir.actions.todo"> <field name="state">open</field>
<field name="name">Generate Chart of Accounts from a Chart Template</field>
<field name="note">Generate Chart of Accounts from a Chart Template. You will be asked to pass the name of the company, the chart template to follow, the no. of digits to generate the code for your accounts and Bank account, currency to create Journals. Thus,the pure copy of chart Template is generated.
This is the same wizard that runs from Financial Management/Configuration/Financial Accounting/Financial Accounts/Generate Chart of Accounts from a Chart Template.</field>
<field name="action_id" ref="account.action_wizard_multi_chart"/>
<field name="type">automatic</field>
</record> </record>
</data> </data>

View File

@ -1,10 +1,8 @@
<openerp> <openerp>
<data> <data>
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<record id="config_call_account_template" model="ir.actions.todo"> <field name="state">open</field>
<field name="action_id" ref="account.action_wizard_multi_chart"/> </record>
<field name="type">automatic</field>
</record>
</data> </data>
</openerp> </openerp>

View File

@ -1,12 +1,9 @@
<openerp> <openerp>
<data> <data>
<record id="config_call_account_template_de" model="ir.actions.todo"> <record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="name">Generiert Kontenplan aus Vorlage</field> <field name="state">open</field>
<field name="note">Der Assistent generiert einen Kontenplan auf Basis eines Templates (Vorlage). Sie werden aufgefordert den Namen der Firma einzugeben, sowie die entsprechende Kontenvorlage zu wählen. Ausserdem können Sie für die Initialisierung der Journale die gewünschte Stellenanzahl der Konten, sowie die Hauptwährung Ihres Betriebes auswählen. Dieser Assistent ist identisch mit dem Open ERP Menü Finanzen/Konfiguration/Finanzkonten/Erzeuge Konten aus Vorlage.</field> </record>
<field name="action_id" ref="account.action_wizard_multi_chart"/>
<field name="type">automatic</field>
</record>
</data> </data>
</openerp> </openerp>

View File

@ -1,13 +1,8 @@
<openerp> <openerp>
<data> <data>
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<record id="config_call_account_template_ec" model="ir.actions.todo"> <field name="state">open</field>
<field name="name">Generate Chart of Accounts from a Chart Template</field> </record>
<field name="note">Generate Chart of Accounts from a Chart Template. You will be asked to pass the name of the company, the chart template to follow, the no. of digits to generate the code for your accounts and Bank account, currency to create Journals. Thus,the pure copy of chart Template is generated.
This is the same wizard that runs from Financial Management/Configuration/Financial Accounting/Financial Accounts/Generate Chart of Accounts from a Chart Template.</field>
<field name="action_id" ref="account.action_wizard_multi_chart"/>
<field name="type">automatic</field>
</record>
</data> </data>
</openerp> </openerp>

View File

@ -1,9 +1,7 @@
<openerp> <openerp>
<data noupdate="1"> <data noupdate="1">
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<record id="config_call_account_template" model="ir.actions.todo"> <field name="state">open</field>
<field name="action_id" ref="account.action_wizard_multi_chart"/>
<field name="type">automatic</field>
</record> </record>
</data> </data>

View File

@ -1,12 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<openerp> <openerp>
<data> <data>
<!-- This ir.actions.todo triggers the screen "Generate your chart of account <record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
from a chart template" in the install wizard of the l10n_fr module --> <field name="state">open</field>
<record id="config_call_account_template_fr" model="ir.actions.todo"> </record>
<field name="action_id" ref="account.action_wizard_multi_chart"/>
<field name="type">automatic</field>
</record>
</data> </data>
</openerp> </openerp>

View File

@ -1,12 +1,7 @@
<openerp> <openerp>
<data> <data>
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<record id="config_call_account_template_gr" model="ir.actions.todo"> <field name="state">open</field>
<field name="name">Generate Chart of Accounts from a Chart Template</field>
<field name="note">Generate Chart of Accounts from a Chart Template. You will be asked to pass the name of the company, the chart template to follow, the no. of digits to generate the code for your accounts and Bank account, currency to create Journals. Thus,the pure copy of chart Template is generated.
This is the same wizard that runs from Financial Management/Configuration/Financial Accounting/Financial Accounts/Generate Chart of Accounts from a Chart Template.</field>
<field name="action_id" ref="account.action_wizard_multi_chart"/>
<field name="type">automatic</field>
</record> </record>
</data> </data>

View File

@ -1,14 +1,8 @@
<openerp> <openerp>
<data noupdate="1"> <data noupdate="1">
<record id="config_call_account_template_gt_minimal" model="ir.actions.todo"> <record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="name">Generar la nomenclatura contable a partir de un modelo</field> <field name="state">open</field>
<field name="note">Generar la nomenclatura contable a partir de un modelo. Deberá seleccionar una compañía, el modelo a utilizar, el número de digitos a usar en la nomenclatura, la moneda para crear los diarios.</field>
<!--<field name="name">Generate Chart of Accounts from a Chart Template</field>
<field name="note">Generate Chart of Accounts from a Chart Template. You will be asked to pass the name of the company, the chart template to follow, the no. of digits to generate the code for your accounts and Bank account, currency to create Journals. Thus, the pure copy of chart Template is generated.
This is the same wizard that runs from Financial Management/Configuration/Financial Accounting/Financial Accounts/Generate Chart of Accounts from a Chart Template.</field>-->
<field name="action_id" ref="account.action_wizard_multi_chart"/>
<field name="type">automatic</field>
</record> </record>
<!-- Moneda Quetzal --> <!-- Moneda Quetzal -->

View File

@ -2,13 +2,7 @@
<openerp> <openerp>
<data noupdate="1"> <data noupdate="1">
<record id="config_call_account_template_hn_minimal" model="ir.actions.todo"> <record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="name">Generar la nomenclatura contable a partir de un modelo</field>
<field name="note">Generar la nomenclatura contable a partir de un modelo. Deberá seleccionar una compañía, el modelo a utilizar, el número de digitos a usar en la nomenclatura, la moneda para crear los diarios.</field>
<!--<field name="name">Generate Chart of Accounts from a Chart Template</field>
<field name="note">Generate Chart of Accounts from a Chart Template. You will be asked to pass the name of the company, the chart template to follow, the no. of digits to generate the code for your accounts and Bank account, currency to create Journals. Thus, the pure copy of chart Template is generated.
This is the same wizard that runs from Financial Management/Configuration/Financial Accounting/Financial Accounts/Generate Chart of Accounts from a Chart Template.</field>-->
<field name="action_id" ref="account.action_wizard_multi_chart"/>
<field name="state">open</field> <field name="state">open</field>
</record> </record>

View File

@ -1,13 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<openerp> <openerp>
<data> <data>
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<record id="config_call_account_template_in_minimal" model="ir.actions.todo"> <field name="state">open</field>
<field name="name">Generate Chart of Accounts from a Chart Template</field>
<field name="note">Generate Chart of Accounts from a Chart Template. You will be asked to pass the name of the company, the chart template to follow, the no. of digits to generate the code for your accounts and Bank account, currency to create Journals. Thus,the pure copy of chart Template is generated.
This is the same wizard that runs from Financial Management/Configuration/Financial Accounting/Financial Accounts/Generate Chart of Accounts from a Chart Template.</field>
<field name="action_id" ref="account.action_wizard_multi_chart"/>
<field name="type">automatic</field>
</record> </record>
</data> </data>

View File

@ -65,7 +65,7 @@ class payroll_advice(osv.osv):
('draft', 'Draft'), ('draft', 'Draft'),
('confirm', 'Confirmed'), ('confirm', 'Confirmed'),
('cancel', 'Cancelled'), ('cancel', 'Cancelled'),
], 'State', select=True, readonly=True), ], 'Status', select=True, readonly=True),
'number':fields.char('Reference', size=16, readonly=True), 'number':fields.char('Reference', size=16, readonly=True),
'line_ids':fields.one2many('hr.payroll.advice.line', 'advice_id', 'Employee Salary', states={'draft': [('readonly', False)]}, readonly=True), 'line_ids':fields.one2many('hr.payroll.advice.line', 'advice_id', 'Employee Salary', states={'draft': [('readonly', False)]}, readonly=True),
'chaque_nos':fields.char('Cheque Numbers', size=256), 'chaque_nos':fields.char('Cheque Numbers', size=256),

View File

@ -38,7 +38,7 @@ class payment_advice_report(osv.osv):
('draft', 'Draft'), ('draft', 'Draft'),
('confirm', 'Confirmed'), ('confirm', 'Confirmed'),
('cancel', 'Cancelled'), ('cancel', 'Cancelled'),
], 'State', select=True, readonly=True), ], 'Status', select=True, readonly=True),
'employee_id': fields.many2one('hr.employee', 'Employee', readonly=True), 'employee_id': fields.many2one('hr.employee', 'Employee', readonly=True),
'nbr': fields.integer('# Payment Lines', readonly=True), 'nbr': fields.integer('# Payment Lines', readonly=True),
'number':fields.char('Number', size=16, readonly=True), 'number':fields.char('Number', size=16, readonly=True),

View File

@ -39,7 +39,7 @@ class payslip_report(osv.osv):
('draft', 'Draft'), ('draft', 'Draft'),
('done', 'Done'), ('done', 'Done'),
('cancel', 'Rejected'), ('cancel', 'Rejected'),
], 'State', readonly=True), ], 'Status', readonly=True),
'employee_id': fields.many2one('hr.employee', 'Employee', readonly=True), 'employee_id': fields.many2one('hr.employee', 'Employee', readonly=True),
'nbr': fields.integer('# Payslip lines', readonly=True), 'nbr': fields.integer('# Payslip lines', readonly=True),
'number': fields.char('Number', size=16, readonly=True), 'number': fields.char('Number', size=16, readonly=True),

View File

@ -1,12 +1,7 @@
<openerp> <openerp>
<data> <data>
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<record id="config_call_account_template_generic" model="ir.actions.todo"> <field name="state">open</field>
<field name="name">Generate Chart of Accounts from a Chart Template</field>
<field name="note">Generate Chart of Accounts from a Chart Template. You will be asked to pass the name of the company, the chart template to follow, the no. of digits to generate the code for your accounts and Bank account, currency to create Journals. Thus,the pure copy of chart Template is generated.
This is the same wizard that runs from Financial Management/Configuration/Financial Accounting/Financial Accounts/Generate Chart of Accounts from a Chart Template.</field>
<field name="action_id" ref="account.action_wizard_multi_chart"/>
<field name="type">automatic</field>
</record> </record>
</data> </data>
</openerp> </openerp>

View File

@ -1,10 +1,8 @@
<openerp> <openerp>
<data> <data>
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<record id="config_call_account_template_lu" model="ir.actions.todo"> <field name="state">open</field>
<field name="action_id" ref="account.action_wizard_multi_chart"/> </record>
<field name="type">automatic</field>
</record>
</data> </data>
</openerp> </openerp>

View File

@ -1,10 +1,8 @@
<openerp> <openerp>
<data> <data>
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<record id="config_call_account_template_ma" model="ir.actions.todo"> <field name="state">open</field>
<field name="action_id" ref="account.action_wizard_multi_chart"/> </record>
<field name="type">automatic</field>
</record>
</data> </data>
</openerp> </openerp>

View File

@ -14,7 +14,7 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-10-23 04:48+0000\n" "X-Launchpad-Export-Date: 2012-10-24 04:55+0000\n"
"X-Generator: Launchpad (build 16179)\n" "X-Generator: Launchpad (build 16179)\n"
#. module: l10n_mx #. module: l10n_mx

View File

@ -1,12 +1,7 @@
<openerp> <openerp>
<data> <data>
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<record id="config_call_account_template_mx_chart" model="ir.actions.todo"> <field name="state">open</field>
<field name="name">Generate Chart of Accounts from a Chart Template</field>
<field name="note">Generate Chart of Accounts from a Chart Template. You will be asked to pass the name of the company, the chart template to follow, the no. of digits to generate the code for your accounts and Bank account, currency to create Journals. Thus,the pure copy of chart Template is generated.
This is the same wizard that runs from Financial Management/Configuration/Financial Accounting/Financial Accounts/Generate Chart of Accounts from a Chart Template.</field>
<field name="action_id" ref="account.action_wizard_multi_chart"/>
<field name="type">automatic</field>
</record> </record>
</data> </data>

View File

@ -1,19 +1,8 @@
<openerp> <openerp>
<data> <data>
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<record id="config_call_account_template" model="ir.actions.todo"> <field name="state">open</field>
<field name="name">Genereer Grootboekrekingschema vanuit het Nederlandse Grootboek Template</field> </record>
<field name="note">Na installatie van deze module word de configuratie wizard voor "Accounting" aangeroepen.
* U krijgt een lijst met grootboektemplates aangeboden waarin zich ook het Nederlandse grootboekschema bevind.
* Als de configuratie wizard start, wordt u gevraagd om de naam van uw bedrijf in te voeren, welke grootboekschema te installeren, uit hoeveel cijfers een grootboekrekening mag bestaan, het rekeningnummer van uw bank en de currency om Journalen te creeren.
Let op!! -&gt; De template van het Nederlandse rekeningschema is opgebouwd uit 4 cijfers. Dit is het minimale aantal welk u moet invullen, u mag het aantal verhogen. De extra cijfers worden dan achter het rekeningnummer aangevult met "nullen"
* Dit is dezelfe configuratie wizard welke aangeroepen kan worden via Financial Management/Configuration/Financial Accounting/Financial Accounts/Generate Chart of Accounts from a Chart Template.
</field>
<field name="action_id" ref="account.action_wizard_multi_chart"/>
<field name="type">automatic</field>
</record>
</data> </data>
</openerp> </openerp>

View File

@ -2,12 +2,8 @@
<openerp> <openerp>
<data> <data>
<record id="config_call_account_template_pe" model="ir.actions.todo"> <record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="name">Generate Chart of Accounts from a Chart Template</field> <field name="state">open</field>
<field name="note">Generate Chart of Accounts from a Chart Template. You will be asked to pass the name of the company, the chart template to follow, the no. of digits to generate the code for your accounts and Bank account, currency to create Journals. Thus,the pure copy of chart Template is generated.
This is the same wizard that runs from Financial Management/Configuration/Financial Accounting/Financial Accounts/Generate Chart of Accounts from a Chart Template.</field>
<field name="action_id" ref="account.action_wizard_multi_chart"/>
<field name="type">automatic</field>
</record> </record>
</data> </data>

View File

@ -1,12 +1,7 @@
<openerp> <openerp>
<data> <data>
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<record id="config_call_account_template_pl_chart" model="ir.actions.todo"> <field name="state">open</field>
<field name="name">Generate Chart of Accounts from a Chart Template</field>
<field name="note">Generate Chart of Accounts from a Chart Template. You will be asked to pass the name of the company, the chart template to follow, the no. of digits to generate the code for your accounts and Bank account, currency to create Journals. Thus,the pure copy of chart Template is generated.
This is the same wizard that runs from Financial Management/Configuration/Financial Accounting/Financial Accounts/Generate Chart of Accounts from a Chart Template.</field>
<field name="action_id" ref="account.action_wizard_multi_chart"/>
<field name="type">automatic</field>
</record> </record>
</data> </data>

View File

@ -1,12 +1,7 @@
<openerp> <openerp>
<data> <data>
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<record id="config_call_account_template_ro" model="ir.actions.todo"> <field name="state">open</field>
<field name="name">Generate Chart of Accounts from a Chart Template</field>
<field name="note">Generate Chart of Accounts from a Chart Template. You will be asked to pass the name of the company, the chart template to follow, the no. of digits to generate the code for your accounts and Bank account, currency to create Journals. Thus,the pure copy of chart Template is generated.
This is the same wizard that runs from Financial Management/Configuration/Financial Accounting/Financial Accounts/Generate Chart of Accounts from a Chart Template.</field>
<field name="action_id" ref="account.action_wizard_multi_chart"/>
<field name="type">automatic</field>
</record> </record>
</data> </data>

View File

@ -1,11 +1,7 @@
<openerp> <openerp>
<data> <data>
<record id="config_call_account_template_syscohada" model="ir.actions.todo"> <record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="name">Generate Chart of Accounts from a Chart Template</field> <field name="state">open</field>
<field name="note">Generate Chart of Accounts from a SYSCOHADA Chart Template. You will be asked to pass the name of the company, the chart template to follow, the no. of digits to generate the code for your accounts and Bank account, currency to create Journals. Thus,the pure copy of chart Template is generated. </record>
This is the same wizard that runs from Financial Management/Configuration/Financial Accounting/Financial Accounts/Generate Chart of Accounts from a Chart Template.</field>
<field name="action_id" ref="account.action_wizard_multi_chart"/>
<field name="type">automatic</field>
</record>
</data> </data>
</openerp> </openerp>

View File

@ -643,14 +643,9 @@
</record> </record>
<!-- INSTALL ACTION --> <!-- INSTALL ACTION -->
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<record id="config_call_account_template_th" model="ir.actions.todo"> <field name="state">open</field>
<field name="name">Generate Chart of Accounts from a Chart Template</field> </record>
<field name="note">Generate Chart of Accounts from a Chart Template. You will be asked to pass the name of the company, the chart template to follow, the no. of digits to generate the code for your accounts and Bank account, currency to create Journals. Thus,the pure copy of chart Template is generated.
This is the same wizard that runs from Financial Management/Configuration/Financial Accounting/Financial Accounts/Generate Chart of Accounts from a Chart Template.</field>
<field name="action_id" ref="account.action_wizard_multi_chart"/>
<field name="type">automatic</field>
</record>
</data> </data>
</openerp><!-- vim: set fdm=marker : --> </openerp><!-- vim: set fdm=marker : -->

View File

@ -1,16 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<openerp> <openerp>
<data> <data>
<record id="config_call_account_template_tr_chart" model="ir.actions.todo"> <record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="name">Generate Chart of Accounts from a Chart Template</field> <field name="state">open</field>
<field name="note">Generate Chart of Accounts from a Chart Template. You will be
asked to pass the name of the company, the chart template to follow, the no. of digits to generate
the code for your accounts and Bank account, currency to create Journals. Thus,the pure copy of
chart Template is generated.
This is the same wizard that runs from Financial Management/Configuration/Financial
Accounting/Financial Accounts/Generate Chart of Accounts from a Chart Template.</field>
<field name="action_id" ref="account.action_wizard_multi_chart"/>
<field name="type">automatic</field>
</record> </record>
</data> </data>
</openerp> </openerp>

View File

@ -1,41 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<openerp> <openerp>
<data> <data>
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<record id="view_wizard_multi_chart_uk" model="ir.ui.view">
<field name="name">Generate Chart of Accounts from a Chart Template</field>
<field name="model">wizard.multi.charts.accounts</field>
<field name="inherit_id" ref="account.view_wizard_multi_chart"/>
<field name="arch" type="xml">
<data>
<!--
<xpath expr="//group[@string='res_config_contents']/separator" position="attributes">
<attribute name="string">
Generate Your UK Accounting Chart from a Chart Template
</attribute>
</xpath>
<xpath expr="//group[@string='res_config_contents']/label" position="attributes">
<attribute name="string">SELECT 4 DIGIT ACCOUNTS. This is the same wizard that runs from Financial Management/Configuration/Financial Accounting/ Financial Accounts/Generate Chart of Accounts from a Chart Template.</attribute>
</xpath>
-->
</data>
</field>
</record>
<record id="action_wizard_multi_chart_uk" model="ir.actions.act_window">
<field name="name">Generate UK Chart of Accounts from a Chart Template</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">wizard.multi.charts.accounts</field>
<field name="view_id" ref="view_wizard_multi_chart_uk"/>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<record id="l10n_uk_latest_wizard_id" model="ir.actions.todo">
<field name="action_id" ref="action_wizard_multi_chart_uk"/>
<field name="sequence">10</field>
<field name="type">once</field>
<field name="state">open</field> <field name="state">open</field>
</record> </record>

View File

@ -1,12 +1,7 @@
<openerp> <openerp>
<data> <data>
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<record id="config_call_account_template" model="ir.actions.todo"> <field name="state">open</field>
<field name="name">Generate Chart of Accounts from a Chart Template</field>
<field name="note">Generate Chart of Accounts from a Chart Template. You will be asked to pass the name of the company, the chart template to follow, the no. of digits to generate the code for your accounts and Bank account, currency to create Journals. Thus,the pure copy of chart Template is generated.
This is the same wizard that runs from Financial Management/Configuration/Financial Accounting/Financial Accounts/Generate Chart of Accounts from a Chart Template.</field>
<field name="action_id" ref="account.action_wizard_multi_chart"/>
<field name="type">automatic</field>
</record> </record>
</data> </data>

View File

@ -1,9 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<openerp> <openerp>
<data> <data>
<record id="config_call_account_template_uy" model="ir.actions.todo"> <record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="action_id" ref="account.action_wizard_multi_chart"/> <field name="state">open</field>
<field name="type">automatic</field>
</record> </record>
</data> </data>
</openerp> </openerp>

View File

@ -1,15 +1,7 @@
<openerp> <openerp>
<data> <data>
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<record id="config_call_account_template_ve_chart" model="ir.actions.todo"> <field name="state">open</field>
<field name="name">Generate Chart of Accounts from a Chart Template</field>
<field name="note">Generate Chart of Accounts from a Chart Template. You will be asked to pass the name of the company, the chart template to follow, the no. of digits to generate the code for your accounts and Bank account, currency to create Journals. Thus,the pure copy of chart Template is generated.
This is the same wizard that runs from Financial Management/Configuration/Financial Accounting/Financial Accounts/Generate Chart of Accounts from a Chart Template.
Genere el Plan de cuentas de una Plantilla de Carta. Le pedirán pasar el nombre de la compania, la plantilla de carta para seguir, el no. de digitos para generar el codigo para sus cuentas y cuenta Bancaria, dinero para crear Diarios. Asi, la copia pura de la carta la Plantilla es generada.
Esto es el mismo wizard que corre de la Financial Management/Configuration/Financial Accounting/Financial Accounts/Generate Chart of Accounts from a Chart Template.
</field>
<field name="action_id" ref="account.action_wizard_multi_chart"/>
<field name="type">automatic</field>
</record> </record>
</data> </data>

View File

@ -8,6 +8,7 @@
<field name="body">Your monthly meal vouchers arrived. You can get them at Christine's office. <field name="body">Your monthly meal vouchers arrived. You can get them at Christine's office.
This month you also get 250 EUR of eco-vouchers if you have been in the company for more than a year.</field> This month you also get 250 EUR of eco-vouchers if you have been in the company for more than a year.</field>
<field name="type">comment</field> <field name="type">comment</field>
<field name="subtype_id" ref="mt_comment"/>
</record> </record>
<record id="message_blogpost0_comment0" model="mail.message"> <record id="message_blogpost0_comment0" model="mail.message">
@ -16,6 +17,7 @@ This month you also get 250 EUR of eco-vouchers if you have been in the company
<field name="body"><![CDATA[Great.]]></field> <field name="body"><![CDATA[Great.]]></field>
<field name="parent_id" ref="message_blogpost0"/> <field name="parent_id" ref="message_blogpost0"/>
<field name="type">comment</field> <field name="type">comment</field>
<field name="subtype_id" ref="mt_comment"/>
</record> </record>
<record id="message_blogpost0_comment1" model="mail.message"> <record id="message_blogpost0_comment1" model="mail.message">
@ -24,22 +26,25 @@ This month you also get 250 EUR of eco-vouchers if you have been in the company
<field name="body">Thanks, but where is Christine's office, if I may ask? (I'm new here)</field> <field name="body">Thanks, but where is Christine's office, if I may ask? (I'm new here)</field>
<field name="parent_id" ref="message_blogpost0"/> <field name="parent_id" ref="message_blogpost0"/>
<field name="type">comment</field> <field name="type">comment</field>
<field name="subtype_id" ref="mt_comment"/>
</record> </record>
<record id="message_blogpost0_comment2" model="mail.message"> <record id="message_blogpost0_comment2" model="mail.message">
<field name="model">mail.group</field>
<field name="res_id" ref="group_all_employees"/>
<field name="body">Building B3, second floor on the right :-)</field>
<field name="parent_id" ref="message_blogpost0"/>
<field name="type">comment</field>
<field name="subtype_id" ref="mt_comment"/>
</record>
<record id="message_blogpost0_comment3" model="mail.message">
<field name="model">mail.group</field> <field name="model">mail.group</field>
<field name="res_id" ref="group_all_employees"/> <field name="res_id" ref="group_all_employees"/>
<field name="body">Great news, I need to buy a new fridge, I think I can pay it with the eco-vouchers!</field> <field name="body">Great news, I need to buy a new fridge, I think I can pay it with the eco-vouchers!</field>
<field name="parent_id" ref="message_blogpost0"/> <field name="parent_id" ref="message_blogpost0"/>
<field name="type">comment</field> <field name="type">comment</field>
</record> <field name="subtype_id" ref="mt_comment"/>
<record id="message_blogpost0_comment1_2" model="mail.message">
<field name="model">mail.group</field>
<field name="res_id" ref="group_all_employees"/>
<field name="body">Building B3, second floor on the right :-)</field>
<field name="parent_id" ref="message_blogpost0_comment1"/>
<field name="type">comment</field>
</record> </record>
</data> </data>

View File

@ -131,7 +131,8 @@ class mail_notification(osv.Model):
def _notify(self, cr, uid, msg_id, context=None): def _notify(self, cr, uid, msg_id, context=None):
""" Send by email the notification depending on the user preferences """ """ Send by email the notification depending on the user preferences """
context = context or {} if context is None:
context = {}
# mail_noemail (do not send email) or no partner_ids: do not send, return # mail_noemail (do not send email) or no partner_ids: do not send, return
if context.get('mail_noemail'): if context.get('mail_noemail'):
return True return True
@ -141,9 +142,15 @@ class mail_notification(osv.Model):
if not notify_partner_ids: if not notify_partner_ids:
return True return True
# add the context in the email
# TDE FIXME: commented, to be improved in a future branch
# quote_context = self.pool.get('mail.message').message_quote_context(cr, uid, msg_id, context=context)
mail_mail = self.pool.get('mail.mail') mail_mail = self.pool.get('mail.mail')
# add signature # add signature
body_html = msg.body body_html = msg.body
# if quote_context:
# body_html = tools.append_content_to_html(body_html, quote_context, plaintext=False)
signature = msg.author_id and msg.author_id.user_ids[0].signature or '' signature = msg.author_id and msg.author_id.user_ids[0].signature or ''
if signature: if signature:
body_html = tools.append_content_to_html(body_html, signature) body_html = tools.append_content_to_html(body_html, signature)

View File

@ -24,11 +24,17 @@ import tools
from email.header import decode_header from email.header import decode_header
from openerp import SUPERUSER_ID from openerp import SUPERUSER_ID
from osv import osv, orm, fields from openerp.osv import osv, orm, fields
from tools.translate import _ from openerp.tools.translate import _
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
try:
from mako.template import Template as MakoTemplate
except ImportError:
_logger.warning("payment_acquirer: mako templates not available, payment acquirer will not work!")
""" Some tools for parsing / creating email fields """ """ Some tools for parsing / creating email fields """
def decode(text): def decode(text):
"""Returns unicode() string conversion of the the given encoded smtp header text""" """Returns unicode() string conversion of the the given encoded smtp header text"""
@ -45,8 +51,8 @@ class mail_message(osv.Model):
_inherit = ['ir.needaction_mixin'] _inherit = ['ir.needaction_mixin']
_order = 'id desc' _order = 'id desc'
_message_read_limit = 15 _message_read_limit = 10
_message_read_fields = ['id', 'parent_id', 'model', 'res_id', 'body', 'subject', 'date', 'to_read', _message_read_fields = ['id', 'parent_id', 'model', 'res_id', 'body', 'subject', 'date', 'to_read', 'email_from',
'type', 'vote_user_ids', 'attachment_ids', 'author_id', 'partner_ids', 'record_name', 'favorite_user_ids'] 'type', 'vote_user_ids', 'attachment_ids', 'author_id', 'partner_ids', 'record_name', 'favorite_user_ids']
_message_record_name_length = 18 _message_record_name_length = 18
_message_read_more_limit = 1024 _message_read_more_limit = 1024
@ -57,17 +63,13 @@ class mail_message(osv.Model):
return name[:self._message_record_name_length] + '...' return name[:self._message_record_name_length] + '...'
def _get_record_name(self, cr, uid, ids, name, arg, context=None): def _get_record_name(self, cr, uid, ids, name, arg, context=None):
""" Return the related document name, using name_get. It is included in """ Return the related document name, using name_get. It is done using
a try/except statement, because if uid cannot read the related SUPERUSER_ID, to be sure to have the record name correctly stored. """
document, he should see a void string instead of crashing. """
result = dict.fromkeys(ids, False) result = dict.fromkeys(ids, False)
for message in self.read(cr, uid, ids, ['model', 'res_id'], context=context): for message in self.read(cr, uid, ids, ['model', 'res_id'], context=context):
if not message['model'] or not message['res_id']: if not message.get('model') or not message.get('res_id'):
continue continue
try: result[message['id']] = self._shorten_name(self.pool.get(message['model']).name_get(cr, SUPERUSER_ID, [message['res_id']], context=context)[0][1])
result[message['id']] = self._shorten_name(self.pool.get(message['model']).name_get(cr, uid, [message['res_id']], context=context)[0][1])
except (orm.except_orm, osv.except_osv):
pass
return result return result
def _get_to_read(self, cr, uid, ids, name, arg, context=None): def _get_to_read(self, cr, uid, ids, name, arg, context=None):
@ -114,16 +116,21 @@ class mail_message(osv.Model):
], 'Type', ], 'Type',
help="Message type: email for email message, notification for system "\ help="Message type: email for email message, notification for system "\
"message, comment for other messages such as user replies"), "message, comment for other messages such as user replies"),
'author_id': fields.many2one('res.partner', 'Author', required=True), 'email_from': fields.char('From',
'partner_ids': fields.many2many('res.partner', 'mail_notification', 'message_id', 'partner_id', 'Recipients'), help="Email address of the sender, to use if it does not match any partner."),
'author_id': fields.many2one('res.partner', 'Author',
help="Partner that did write the message. If not set, try to use the From field instead."),
'partner_ids': fields.many2many('res.partner', string='Recipients'),
'notified_partner_ids': fields.many2many('res.partner', 'mail_notification',
'message_id', 'partner_id', 'Recipients'),
'attachment_ids': fields.many2many('ir.attachment', 'message_attachment_rel', 'attachment_ids': fields.many2many('ir.attachment', 'message_attachment_rel',
'message_id', 'attachment_id', 'Attachments'), 'message_id', 'attachment_id', 'Attachments'),
'parent_id': fields.many2one('mail.message', 'Parent Message', select=True, ondelete='set null', help="Initial thread message."), 'parent_id': fields.many2one('mail.message', 'Parent Message', select=True, ondelete='set null', help="Initial thread message."),
'child_ids': fields.one2many('mail.message', 'parent_id', 'Child Messages'), 'child_ids': fields.one2many('mail.message', 'parent_id', 'Child Messages'),
'model': fields.char('Related Document Model', size=128, select=1), 'model': fields.char('Related Document Model', size=128, select=1),
'res_id': fields.integer('Related Document ID', select=1), 'res_id': fields.integer('Related Document ID', select=1),
'record_name': fields.function(_get_record_name, type='string', 'record_name': fields.function(_get_record_name, type='char',
string='Message Record Name', store=True, string='Message Record Name',
help="Name get of the related document."), help="Name get of the related document."),
'notification_ids': fields.one2many('mail.notification', 'message_id', 'Notifications'), 'notification_ids': fields.one2many('mail.notification', 'message_id', 'Notifications'),
'subject': fields.char('Subject'), 'subject': fields.char('Subject'),
@ -200,6 +207,9 @@ class mail_message(osv.Model):
is_author = False is_author = False
if message['author_id']: if message['author_id']:
is_author = message['author_id'][0] == self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=None)['partner_id'][0] is_author = message['author_id'][0] == self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=None)['partner_id'][0]
author_id = message['author_id']
elif message['email_from']:
author_id = (0, message['email_from'])
has_voted = False has_voted = False
if uid in message.get('vote_user_ids'): if uid in message.get('vote_user_ids'):
@ -209,9 +219,9 @@ class mail_message(osv.Model):
if uid in message.get('favorite_user_ids'): if uid in message.get('favorite_user_ids'):
is_favorite = True is_favorite = True
is_private = False is_private = True
if message.get('model') and message.get('res_id'): if message.get('model') and message.get('res_id'):
is_private = True is_private = False
try: try:
attachment_ids = [{'id': attach[0], 'name': attach[1]} for attach in self.pool.get('ir.attachment').name_get(cr, uid, message['attachment_ids'], context=context)] attachment_ids = [{'id': attach[0], 'name': attach[1]} for attach in self.pool.get('ir.attachment').name_get(cr, uid, message['attachment_ids'], context=context)]
@ -235,11 +245,10 @@ class mail_message(osv.Model):
'record_name': message['record_name'], 'record_name': message['record_name'],
'subject': message['subject'], 'subject': message['subject'],
'date': message['date'], 'date': message['date'],
'author_id': message['author_id'], 'author_id': author_id,
'is_author': is_author, 'is_author': is_author,
# TDE note: is this useful ? to check
'partner_ids': partner_ids, 'partner_ids': partner_ids,
'ancestor_id': False, 'parent_id': False,
'vote_nb': len(message['vote_user_ids']), 'vote_nb': len(message['vote_user_ids']),
'has_voted': has_voted, 'has_voted': has_voted,
'is_private': is_private, 'is_private': is_private,
@ -269,12 +278,12 @@ class mail_message(osv.Model):
easily have access to their values, given their ID easily have access to their values, given their ID
:return bool: True :return bool: True
""" """
def _get_expandable(domain, message_nb, ancestor_id, id, model): def _get_expandable(domain, message_nb, parent_id, id, model):
return { return {
'domain': domain, 'domain': domain,
'nb_messages': message_nb, 'nb_messages': message_nb,
'type': 'expandable', 'type': 'expandable',
'ancestor_id': ancestor_id, 'parent_id': parent_id,
'id': id, 'id': id,
# TDE note: why do we need model sometimes, and sometimes not ??? # TDE note: why do we need model sometimes, and sometimes not ???
'model': model, 'model': model,
@ -282,6 +291,8 @@ class mail_message(osv.Model):
# all_not_loaded_ids = [] # all_not_loaded_ids = []
id_list = sorted(read_messages.keys()) id_list = sorted(read_messages.keys())
if not id_list:
return message_list
# 1. get the expandable for new threads # 1. get the expandable for new threads
if thread_level == 0: if thread_level == 0:
@ -351,7 +362,7 @@ class mail_message(osv.Model):
except (orm.except_orm, osv.except_osv): except (orm.except_orm, osv.except_osv):
return False return False
def message_read(self, cr, uid, ids=False, domain=None, message_unload_ids=None, thread_level=0, context=None, parent_id=False, limit=None): def message_read(self, cr, uid, ids=None, domain=None, message_unload_ids=None, thread_level=0, context=None, parent_id=False, limit=None):
""" Read messages from mail.message, and get back a list of structured """ Read messages from mail.message, and get back a list of structured
messages to be displayed as discussion threads. If IDs is set, messages to be displayed as discussion threads. If IDs is set,
fetch these records. Otherwise use the domain to fetch messages. fetch these records. Otherwise use the domain to fetch messages.
@ -375,6 +386,13 @@ class mail_message(osv.Model):
ancestors and expandables ancestors and expandables
:return list: list of message structure for the Chatter widget :return list: list of message structure for the Chatter widget
""" """
print domain
print message_unload_ids
print thread_level
print context
print parent_id
print limit
assert thread_level in [0, 1], 'message_read() thread_level should be 0 (flat) or 1 (1 level of thread); given %s.' % thread_level assert thread_level in [0, 1], 'message_read() thread_level should be 0 (flat) or 1 (1 level of thread); given %s.' % thread_level
domain = domain if domain is not None else [] domain = domain if domain is not None else []
message_unload_ids = message_unload_ids if message_unload_ids is not None else [] message_unload_ids = message_unload_ids if message_unload_ids is not None else []
@ -384,34 +402,29 @@ class mail_message(osv.Model):
read_messages = {} read_messages = {}
message_list = [] message_list = []
# specific IDs given: fetch those ids and return directly the message list # no specific IDS given: fetch messages according to the domain, add their parents if uid has access to
if ids: if ids is None:
for message in self.read(cr, uid, ids, self._message_read_fields, context=context): ids = self.search(cr, uid, domain, context=context, limit=limit)
message_list.append(self._message_get_dict(cr, uid, message, context=context))
message_list = sorted(message_list, key=lambda k: k['id'])
return message_list
# TDE FIXME: check access rights on search are implemented for mail.message
# fetch messages according to the domain, add their parents if uid has access to
ids = self.search(cr, uid, domain, context=context, limit=limit)
for message in self.read(cr, uid, ids, self._message_read_fields, context=context): for message in self.read(cr, uid, ids, self._message_read_fields, context=context):
message_id = message['id']
# if not in tree and not in message_loaded list # if not in tree and not in message_loaded list
if not read_messages.get(message.get('id')) and message.get('id') not in message_unload_ids: if not message_id in read_messages and not message_id in message_unload_ids:
read_messages[message.get('id')] = message read_messages[message_id] = message
message_list.append(self._message_get_dict(cr, uid, message, context=context)) message_list.append(self._message_get_dict(cr, uid, message, context=context))
# get the older ancestor the user can read, update its ancestor field # get the older ancestor the user can read, update its ancestor field
if not thread_level: if not thread_level:
message_list[-1]['ancestor_id'] = parent_id message_list[-1]['parent_id'] = parent_id
continue continue
parent = self._get_parent(cr, uid, message, context=context) parent = self._get_parent(cr, uid, message, context=context)
while parent and parent.get('id') != parent_id: while parent and parent.get('id') != parent_id:
message_list[-1]['ancestor_id'] = parent.get('id') message_list[-1]['parent_id'] = parent.get('id')
message = parent message = parent
parent = self._get_parent(cr, uid, message, context=context) parent = self._get_parent(cr, uid, message, context=context)
# if in thread: add its ancestor to the list of messages # if in thread: add its ancestor to the list of messages
if not read_messages.get(message.get('id')) and message.get('id') not in message_unload_ids: if not message['id'] in read_messages and not message['id'] in message_unload_ids:
read_messages[message.get('id')] = message read_messages[message['id']] = message
message_list.append(self._message_get_dict(cr, uid, message, context=context)) message_list.append(self._message_get_dict(cr, uid, message, context=context))
# get the child expandable messages for the tree # get the child expandable messages for the tree
@ -419,6 +432,8 @@ class mail_message(osv.Model):
self._message_read_add_expandables(cr, uid, message_list, read_messages, thread_level=thread_level, self._message_read_add_expandables(cr, uid, message_list, read_messages, thread_level=thread_level,
message_loaded_ids=message_unload_ids, domain=domain, parent_id=parent_id, context=context, limit=limit) message_loaded_ids=message_unload_ids, domain=domain, parent_id=parent_id, context=context, limit=limit)
print message_list
return message_list return message_list
# TDE Note: do we need this ? # TDE Note: do we need this ?
@ -431,7 +446,7 @@ class mail_message(osv.Model):
# return attachment_list # return attachment_list
#------------------------------------------------------ #------------------------------------------------------
# Email api # mail_message internals
#------------------------------------------------------ #------------------------------------------------------
def init(self, cr): def init(self, cr):
@ -439,23 +454,74 @@ class mail_message(osv.Model):
if not cr.fetchone(): if not cr.fetchone():
cr.execute("""CREATE INDEX mail_message_model_res_id_idx ON mail_message (model, res_id)""") cr.execute("""CREATE INDEX mail_message_model_res_id_idx ON mail_message (model, res_id)""")
def _search(self, cr, uid, args, offset=0, limit=None, order=None,
context=None, count=False, access_rights_uid=None):
""" Override that adds specific access rights of mail.message, to remove
ids uid could not see according to our custom rules. Please refer
to check_access_rule for more details about those rules.
After having received ids of a classic search, keep only:
- if author_id == pid, uid is the author, OR
- a notification (id, pid) exists, uid has been notified, OR
- uid have read access to the related document is model, res_id
- otherwise: remove the id
"""
# Rules do not apply to administrator
if uid == SUPERUSER_ID:
return super(mail_message, self)._search(cr, uid, args, offset=offset, limit=limit, order=order,
context=context, count=count, access_rights_uid=access_rights_uid)
# Perform a super with count as False, to have the ids, not a counter
ids = super(mail_message, self)._search(cr, uid, args, offset=offset, limit=limit, order=order,
context=context, count=False, access_rights_uid=access_rights_uid)
if not ids and count:
return 0
elif not ids:
return ids
pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'])['partner_id'][0]
author_ids, partner_ids, allowed_ids = set([]), set([]), set([])
model_ids = {}
messages = super(mail_message, self).read(cr, uid, ids, ['author_id', 'model', 'res_id', 'notified_partner_ids'], context=context)
for message in messages:
if message.get('author_id') and message.get('author_id')[0] == pid:
author_ids.add(message.get('id'))
elif pid in message.get('notified_partner_ids'):
partner_ids.add(message.get('id'))
elif message.get('model') and message.get('res_id'):
model_ids.setdefault(message.get('model'), {}).setdefault(message.get('res_id'), set()).add(message.get('id'))
model_access_obj = self.pool.get('ir.model.access')
for doc_model, doc_dict in model_ids.iteritems():
if not model_access_obj.check(cr, uid, doc_model, 'read', False):
continue
doc_ids = doc_dict.keys()
allowed_doc_ids = self.pool.get(doc_model).search(cr, uid, [('id', 'in', doc_ids)], context=context)
allowed_ids |= set([message_id for allowed_doc_id in allowed_doc_ids for message_id in doc_dict[allowed_doc_id]])
final_ids = author_ids | partner_ids | allowed_ids
if count:
return len(final_ids)
else:
return list(final_ids)
def check_access_rule(self, cr, uid, ids, operation, context=None): def check_access_rule(self, cr, uid, ids, operation, context=None):
""" Access rules of mail.message: """ Access rules of mail.message:
- read: if - read: if
- notification exist (I receive pushed message) OR - author_id == pid, uid is the author, OR
- author_id = pid (I am the author) OR - mail_notification (id, pid) exists, uid has been notified, OR
- I can read the related document if res_model, res_id - uid have read access to the related document if model, res_id
- Otherwise: raise - otherwise: raise
- create: if - create: if
- I am in the document message_follower_ids OR - no model, no res_id, I create a private message
- I can write on the related document if res_model, res_id OR - pid in message_follower_ids if model, res_id OR
- I create a private message (no model, no res_id) - uid have write access on the related document if model, res_id, OR
- Otherwise: raise - otherwise: raise
- write: if - write: if
- I can write on the related document if res_model, res_id - uid has write access on the related document if model, res_id
- Otherwise: raise - Otherwise: raise
- unlink: if - unlink: if
- I can write on the related document if res_model, res_id - uid has write access on the related document if model, res_id
- Otherwise: raise - Otherwise: raise
""" """
if uid == SUPERUSER_ID: if uid == SUPERUSER_ID:
@ -465,15 +531,25 @@ class mail_message(osv.Model):
partner_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=None)['partner_id'][0] partner_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=None)['partner_id'][0]
# Read mail_message.ids to have their values # Read mail_message.ids to have their values
model_record_ids = {}
message_values = dict.fromkeys(ids) message_values = dict.fromkeys(ids)
model_record_ids = {}
cr.execute('SELECT DISTINCT id, model, res_id, author_id FROM "%s" WHERE id = ANY (%%s)' % self._table, (ids,)) cr.execute('SELECT DISTINCT id, model, res_id, author_id FROM "%s" WHERE id = ANY (%%s)' % self._table, (ids,))
for id, rmod, rid, author_id in cr.fetchall(): for id, rmod, rid, author_id in cr.fetchall():
message_values[id] = {'res_model': rmod, 'res_id': rid, 'author_id': author_id} message_values[id] = {'res_model': rmod, 'res_id': rid, 'author_id': author_id}
if rmod: if rmod:
model_record_ids.setdefault(rmod, set()).add(rid) model_record_ids.setdefault(rmod, dict()).setdefault(rid, set()).add(id)
# Read: Check for received notifications -> could become an ir.rule, but not till we do not have a many2one variable field # Author condition, for read and create (private message) -> could become an ir.rule, but not till we do not have a many2one variable field
if operation == 'read':
author_ids = [mid for mid, message in message_values.iteritems()
if message.get('author_id') and message.get('author_id') == partner_id]
elif operation == 'create':
author_ids = [mid for mid, message in message_values.iteritems()
if not message.get('model') and not message.get('res_id')]
else:
author_ids = []
# Notification condition, for read (check for received notifications and create (in message_follower_ids)) -> could become an ir.rule, but not till we do not have a many2one variable field
if operation == 'read': if operation == 'read':
not_obj = self.pool.get('mail.notification') not_obj = self.pool.get('mail.notification')
not_ids = not_obj.search(cr, SUPERUSER_ID, [ not_ids = not_obj.search(cr, SUPERUSER_ID, [
@ -481,38 +557,24 @@ class mail_message(osv.Model):
('message_id', 'in', ids), ('message_id', 'in', ids),
], context=context) ], context=context)
notified_ids = [notification.message_id.id for notification in not_obj.browse(cr, SUPERUSER_ID, not_ids, context=context)] notified_ids = [notification.message_id.id for notification in not_obj.browse(cr, SUPERUSER_ID, not_ids, context=context)]
else:
notified_ids = []
# Read: Check messages you are author -> could become an ir.rule, but not till we do not have a many2one variable field
if operation == 'read':
author_ids = [mid for mid, message in message_values.iteritems()
if message.get('author_id') and message.get('author_id') == partner_id]
# Create: Check messages you create that are private messages -> ir.rule ?
elif operation == 'create': elif operation == 'create':
author_ids = [mid for mid, message in message_values.iteritems() notified_ids = []
if not message.get('model') and not message.get('res_id')] for doc_model, doc_dict in model_record_ids.items():
else:
author_ids = []
# Create: Check message_follower_ids
if operation == 'create':
doc_follower_ids = []
for model, mids in model_record_ids.items():
fol_obj = self.pool.get('mail.followers') fol_obj = self.pool.get('mail.followers')
fol_ids = fol_obj.search(cr, SUPERUSER_ID, [ fol_ids = fol_obj.search(cr, SUPERUSER_ID, [
('res_model', '=', model), ('res_model', '=', doc_model),
('res_id', 'in', list(mids)), ('res_id', 'in', list(doc_dict.keys())),
('partner_id', '=', partner_id), ('partner_id', '=', partner_id),
], context=context) ], context=context)
fol_mids = [follower.res_id for follower in fol_obj.browse(cr, SUPERUSER_ID, fol_ids, context=context)] fol_mids = [follower.res_id for follower in fol_obj.browse(cr, SUPERUSER_ID, fol_ids, context=context)]
doc_follower_ids += [mid for mid, message in message_values.iteritems() notified_ids += [mid for mid, message in message_values.iteritems()
if message.get('res_model') == model and message.get('res_id') in fol_mids] if message.get('res_model') == doc_model and message.get('res_id') in fol_mids]
else: else:
doc_follower_ids = [] notified_ids = []
# Calculate remaining ids, and related model/res_ids # Calculate remaining ids, and related model/res_ids
model_record_ids = {} model_record_ids = {}
other_ids = set(ids).difference(set(notified_ids), set(author_ids), set(doc_follower_ids)) other_ids = set(ids).difference(set(author_ids), set(notified_ids))
for id in other_ids: for id in other_ids:
if message_values[id]['res_model']: if message_values[id]['res_model']:
model_record_ids.setdefault(message_values[id]['res_model'], set()).add(message_values[id]['res_id']) model_record_ids.setdefault(message_values[id]['res_model'], set()).add(message_values[id]['res_id'])
@ -532,7 +594,7 @@ class mail_message(osv.Model):
if message.get('res_model') == model and message.get('res_id') in mids] if message.get('res_model') == model and message.get('res_id') in mids]
# Calculate remaining ids: if not void, raise an error # Calculate remaining ids: if not void, raise an error
other_ids = set(ids).difference(set(notified_ids), set(author_ids), set(doc_follower_ids), set(document_related_ids)) other_ids = other_ids - set(document_related_ids)
if not other_ids: if not other_ids:
return return
raise orm.except_orm(_('Access Denied'), raise orm.except_orm(_('Access Denied'),
@ -566,50 +628,121 @@ class mail_message(osv.Model):
self.pool.get('ir.attachment').unlink(cr, uid, attachments_to_delete, context=context) self.pool.get('ir.attachment').unlink(cr, uid, attachments_to_delete, context=context)
return super(mail_message, self).unlink(cr, uid, ids, context=context) return super(mail_message, self).unlink(cr, uid, ids, context=context)
def _notify_followers(self, cr, uid, newid, message, context=None): def copy(self, cr, uid, id, default=None, context=None):
""" Add the related record followers to the destination partner_ids. """ Overridden to avoid duplicating fields that are unique to each email """
if default is None:
default = {}
default.update(message_id=False, headers=False)
return super(mail_message, self).copy(cr, uid, id, default=default, context=context)
#------------------------------------------------------
# Messaging API
#------------------------------------------------------
MAIL_TEMPLATE = """<div>
% if message:
${display_message(message)}
% endif
% for ctx_msg in context_messages:
${display_message(ctx_msg)}
% endfor
% if add_expandable:
${display_expandable()}
% endif
${display_message(header_message)}
</div>
<%def name="display_message(message)">
<div>
Subject: ${message.subject}<br />
Body: ${message.body}
</div>
</%def>
<%def name="display_expandable()">
<div>This is an expandable.</div>
</%def>
"""
def message_quote_context(self, cr, uid, id, context=None, limit=3, add_original=False):
""" """
partners_to_notify = set([]) 1. message.parent_id = False: new thread, no quote_context
# message has no subtype_id: pure log message -> no partners, no one notified 2. get the lasts messages in the thread before message
if not message.subtype_id: 3. get the message header
message.write({'partner_ids': [5]}) 4. add an expandable between them
return True
# all partner_ids of the mail.message have to be notified :param dict quote_context: options for quoting
if message.partner_ids: :return string: html quote
partners_to_notify |= set(partner.id for partner in message.partner_ids) """
# all followers of the mail.message document have to be added as partners and notified add_expandable = False
if message.model and message.res_id:
fol_obj = self.pool.get("mail.followers") message = self.browse(cr, uid, id, context=context)
fol_ids = fol_obj.search(cr, uid, [('res_model', '=', message.model), ('res_id', '=', message.res_id), ('subtype_ids', 'in', message.subtype_id.id)], context=context) if not message.parent_id:
fol_objs = fol_obj.browse(cr, uid, fol_ids, context=context) return ''
extra_notified = set(fol.partner_id.id for fol in fol_objs) context_ids = self.search(cr, uid, [
missing_notified = extra_notified - partners_to_notify ('parent_id', '=', message.parent_id.id),
if missing_notified: ('id', '<', message.id),
self.write(cr, SUPERUSER_ID, [newid], {'partner_ids': [(4, p_id) for p_id in missing_notified]}, context=context) ], limit=limit, context=context)
if len(context_ids) >= limit:
add_expandable = True
context_ids = context_ids[0:-1]
context_ids.append(message.parent_id.id)
context_messages = self.browse(cr, uid, context_ids, context=context)
header_message = context_messages.pop()
try:
if not add_original:
message = False
result = MakoTemplate(self.MAIL_TEMPLATE).render_unicode(message=message,
context_messages=context_messages,
header_message=header_message,
add_expandable=add_expandable,
# context kw would clash with mako internals
ctx=context,
format_exceptions=True)
result = result.strip()
return result
except Exception:
_logger.exception("failed to render mako template for quoting message")
return ''
return result
def _notify(self, cr, uid, newid, context=None): def _notify(self, cr, uid, newid, context=None):
""" Add the related record followers to the destination partner_ids if is not a private message. """ Add the related record followers to the destination partner_ids if is not a private message.
Call mail_notification.notify to manage the email sending Call mail_notification.notify to manage the email sending
""" """
message = self.browse(cr, uid, newid, context=context) message = self.read(cr, uid, newid, ['model', 'res_id', 'author_id', 'subtype_id', 'partner_ids'], context=context)
if message.model and message.res_id:
self._notify_followers(cr, uid, newid, message, context=context)
# add myself if I wrote on my wall, otherwise remove myself author partners_to_notify = set([])
if ((message.model == "res.partner" and message.res_id == message.author_id.id)): # message has no subtype_id: pure log message -> no partners, no one notified
self.write(cr, SUPERUSER_ID, [newid], {'partner_ids': [(4, message.author_id.id)]}, context=context) if not message.get('subtype_id'):
else: return True
self.write(cr, SUPERUSER_ID, [newid], {'partner_ids': [(3, message.author_id.id)]}, context=context) # all partner_ids of the mail.message have to be notified
if message.get('partner_ids'):
partners_to_notify |= set(message.get('partner_ids'))
# all followers of the mail.message document have to be added as partners and notified
if message.get('model') and message.get('res_id'):
fol_obj = self.pool.get("mail.followers")
fol_ids = fol_obj.search(cr, uid, [
('res_model', '=', message.get('model')),
('res_id', '=', message.get('res_id')),
('subtype_ids', 'in', message.get('subtype_id')[0])
], context=context)
fol_objs = fol_obj.read(cr, uid, fol_ids, ['partner_id'], context=context)
partners_to_notify |= set(fol['partner_id'][0] for fol in fol_objs)
# when writing to a wall
if message.get('author_id') and message.get('model') == "res.partner" and message.get('res_id') == message.get('author_id')[0]:
partners_to_notify |= set([message.get('author_id')[0]])
elif message.get('author_id'):
partners_to_notify = partners_to_notify - set([message.get('author_id')[0]])
if partners_to_notify:
self.write(cr, SUPERUSER_ID, [newid], {'notified_partner_ids': [(4, p_id) for p_id in partners_to_notify]}, context=context)
self.pool.get('mail.notification')._notify(cr, uid, newid, context=context) self.pool.get('mail.notification')._notify(cr, uid, newid, context=context)
def copy(self, cr, uid, id, default=None, context=None):
"""Overridden to avoid duplicating fields that are unique to each email"""
if default is None:
default = {}
default.update(message_id=False, headers=False)
return super(mail_message, self).copy(cr, uid, id, default=default, context=context)
#------------------------------------------------------ #------------------------------------------------------
# Tools # Tools
#------------------------------------------------------ #------------------------------------------------------

View File

@ -29,6 +29,7 @@
<group> <group>
<field name="subject"/> <field name="subject"/>
<field name="author_id"/> <field name="author_id"/>
<field name="email_from"/>
<field name="date"/> <field name="date"/>
<field name="type"/> <field name="type"/>
<field name="subtype_id"/> <field name="subtype_id"/>
@ -38,6 +39,7 @@
<field name="res_id"/> <field name="res_id"/>
<field name="parent_id"/> <field name="parent_id"/>
<field name="partner_ids" widget="many2many_tags"/> <field name="partner_ids" widget="many2many_tags"/>
<field name="notified_partner_ids" widget="many2many_tags"/>
</group> </group>
</group> </group>
<field name="body"/> <field name="body"/>

View File

@ -554,7 +554,11 @@ class mail_thread(osv.AbstractModel):
('file2', 'bytes')} ('file2', 'bytes')}
} }
""" """
msg_dict = {} msg_dict = {
'type': 'email',
'subtype': 'mail.mt_comment',
'author_id': False,
}
if not isinstance(message, Message): if not isinstance(message, Message):
if isinstance(message, unicode): if isinstance(message, unicode):
# Warning: message_from_string doesn't always work correctly on unicode, # Warning: message_from_string doesn't always work correctly on unicode,
@ -572,7 +576,7 @@ class mail_thread(osv.AbstractModel):
if 'Subject' in message: if 'Subject' in message:
msg_dict['subject'] = decode(message.get('Subject')) msg_dict['subject'] = decode(message.get('Subject'))
# Envelope fields not stored in mail.message but made available for message_new() # Envelope fields not stored in mail.message but made available for message_new()
msg_dict['from'] = decode(message.get('from')) msg_dict['from'] = decode(message.get('from'))
msg_dict['to'] = decode(message.get('to')) msg_dict['to'] = decode(message.get('to'))
msg_dict['cc'] = decode(message.get('cc')) msg_dict['cc'] = decode(message.get('cc'))
@ -581,6 +585,8 @@ class mail_thread(osv.AbstractModel):
author_ids = self._message_find_partners(cr, uid, message, ['From'], context=context) author_ids = self._message_find_partners(cr, uid, message, ['From'], context=context)
if author_ids: if author_ids:
msg_dict['author_id'] = author_ids[0] msg_dict['author_id'] = author_ids[0]
else:
msg_dict['email_from'] = message.get('from')
partner_ids = self._message_find_partners(cr, uid, message, ['From', 'To', 'Cc'], context=context) partner_ids = self._message_find_partners(cr, uid, message, ['From', 'To', 'Cc'], context=context)
msg_dict['partner_ids'] = partner_ids msg_dict['partner_ids'] = partner_ids
@ -670,6 +676,18 @@ class mail_thread(osv.AbstractModel):
if self._mail_flat_thread and not parent_id and thread_id: if self._mail_flat_thread and not parent_id and thread_id:
message_ids = mail_message.search(cr, uid, ['&', ('res_id', '=', thread_id), ('model', '=', model)], context=context, order="id ASC", limit=1) message_ids = mail_message.search(cr, uid, ['&', ('res_id', '=', thread_id), ('model', '=', model)], context=context, order="id ASC", limit=1)
parent_id = message_ids and message_ids[0] or False parent_id = message_ids and message_ids[0] or False
# we want to set a parent: force to set the parent_id to the oldest ancestor, to avoid having more than 1 level of thread
elif parent_id:
message_ids = mail_message.search(cr, SUPERUSER_ID, [('id', '=', parent_id), ('parent_id', '!=', False)], context=context)
# avoid loops when finding ancestors
processed_list = []
if message_ids:
_counter, _counter_max = 0, 200
message = mail_message.browse(cr, SUPERUSER_ID, message_ids[0], context=context)
while (message.parent_id and message.parent_id.id not in processed_list):
processed_list.append(message.parent_id.id)
message = message.parent_id
parent_id = message.id
values = kwargs values = kwargs
values.update({ values.update({
@ -690,32 +708,28 @@ class mail_thread(osv.AbstractModel):
return mail_message.create(cr, uid, values, context=context) return mail_message.create(cr, uid, values, context=context)
def message_post_api(self, cr, uid, thread_id, body='', subject=False, type='notification', def message_post_api(self, cr, uid, thread_id, body='', subject=False, type='notification',
subtype=None, parent_id=False, attachments=None, context=None, **kwargs): parent_id=False, attachment_ids=None, context=None):
# TDE FIXME: body is plaintext: convert it into html """ Wrapper on message_post, used only in Chatter (JS). The purpose is
# when writing on res.partner, without specific thread_id -> redirect to the user's partner to handle attachments.
if self._name == 'res.partner' and not thread_id: # TDE FIXME: body is plaintext: convert it into html
thread_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id', 'subject'], context=context)['partner_id'][0] """
mail_message = self.pool.get('mail.message')
if not subject and parent_id:
parent = mail_message.read(cr, uid, parent_id, ['subject'], context=context)
if parent['subject'] and not parent['subject'].startswith('Re:'):
subject = 'Re: %s' % parent['subject']
new_message_id = self.message_post(cr, uid, thread_id=thread_id, body=body, subject=subject, type=type, new_message_id = self.message_post(cr, uid, thread_id=thread_id, body=body, subject=subject, type=type,
subtype=subtype, parent_id=parent_id, context=context) subtype='mail.mt_comment', parent_id=parent_id, context=context)
# Chatter: attachments linked to the document (not done JS-side), load the message # HACK FIXME: Chatter: attachments linked to the document (not done JS-side), load the message
if attachments: if attachment_ids:
ir_attachment = self.pool.get('ir.attachment') ir_attachment = self.pool.get('ir.attachment')
attachment_ids = ir_attachment.search(cr, SUPERUSER_ID, [('res_model', '=', 'mail.compose.message'), ('res_id', '=', 0), ('create_uid', '=', uid), ('id', 'in', attachments)], context=context) mail_message = self.pool.get('mail.message')
if attachment_ids: filtered_attachment_ids = ir_attachment.search(cr, SUPERUSER_ID, [
('res_model', '=', 'mail.message'),
('res_id', '=', 0),
('create_uid', '=', uid),
('id', 'in', attachment_ids)], context=context)
if filtered_attachment_ids:
ir_attachment.write(cr, SUPERUSER_ID, attachment_ids, {'res_model': self._name, 'res_id': thread_id}, context=context) ir_attachment.write(cr, SUPERUSER_ID, attachment_ids, {'res_model': self._name, 'res_id': thread_id}, context=context)
mail_message.write(cr, SUPERUSER_ID, [new_message_id], {'attachment_ids': [(6, 0, [pid for pid in attachment_ids])]}, context=context) mail_message.write(cr, SUPERUSER_ID, [new_message_id], {'attachment_ids': [(6, 0, [pid for pid in attachment_ids])]}, context=context)
new_message = self.pool.get('mail.message').message_read(cr, uid, [new_message_id], context=context) return new_message_id
return new_message
#------------------------------------------------------ #------------------------------------------------------
# Followers API # Followers API

View File

@ -45,7 +45,7 @@
sequence="10"/> sequence="10"/>
<!-- Left-side menu: Feeds --> <!-- Left-side menu: Feeds -->
<menuitem id="mail.mail_feeds" name="Feeds &amp; Mailbox" parent="mail.mail_feeds_main" groups="base.group_user" sequence="10"/> <menuitem id="mail.mail_feeds" name="Messages" parent="mail.mail_feeds_main" groups="base.group_user" sequence="10"/>
<menuitem id="mail_my_stuff" name="Organizer" parent="mail.mail_feeds_main"/> <menuitem id="mail_my_stuff" name="Organizer" parent="mail.mail_feeds_main"/>
<record id="mail_inboxfeeds" model="ir.ui.menu"> <record id="mail_inboxfeeds" model="ir.ui.menu">
@ -79,4 +79,4 @@
<field name="parent_id" ref="mail.mail_feeds"/> <field name="parent_id" ref="mail.mail_feeds"/>
</record> </record>
</data> </data>
</openerp> </openerp>

View File

@ -2,6 +2,7 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_mail_message_all,mail.message.all,model_mail_message,,1,0,1,0 access_mail_message_all,mail.message.all,model_mail_message,,1,0,1,0
access_mail_message_group_user,mail.message.group.user,model_mail_message,base.group_user,1,1,1,1 access_mail_message_group_user,mail.message.group.user,model_mail_message,base.group_user,1,1,1,1
access_mail_mail_all,mail.mail.all,model_mail_mail,,0,0,1,0 access_mail_mail_all,mail.mail.all,model_mail_mail,,0,0,1,0
access_mail_mail_user,mail.mail,model_mail_mail,base.group_user,1,1,1,0
access_mail_mail_system,mail.mail.system,model_mail_mail,base.group_system,1,1,1,1 access_mail_mail_system,mail.mail.system,model_mail_mail,base.group_system,1,1,1,1
access_mail_followers_all,mail.followers.all,model_mail_followers,,1,0,0,0 access_mail_followers_all,mail.followers.all,model_mail_followers,,1,0,0,0
access_mail_followers_system,mail.followers.system,model_mail_followers,base.group_system,1,1,1,1 access_mail_followers_system,mail.followers.system,model_mail_followers,base.group_system,1,1,1,1
@ -12,6 +13,6 @@ access_mail_group_user,mail.group.user,model_mail_group,base.group_user,1,1,1,1
access_mail_alias_all,mail.alias.all,model_mail_alias,,1,0,0,0 access_mail_alias_all,mail.alias.all,model_mail_alias,,1,0,0,0
access_mail_alias_user,mail.alias,model_mail_alias,base.group_user,1,1,1,0 access_mail_alias_user,mail.alias,model_mail_alias,base.group_user,1,1,1,0
access_mail_alias_system,mail.alias,model_mail_alias,base.group_system,1,1,1,1 access_mail_alias_system,mail.alias,model_mail_alias,base.group_system,1,1,1,1
access_mail_message_subtype,mail.message.subtype,model_mail_message_subtype,,1,1,1,1 access_mail_message_subtype_all,mail.message.subtype.all,model_mail_message_subtype,,1,0,0,0
access_mail_mail_user,mail.mail,model_mail_mail,base.group_user,1,1,1,0
access_mail_vote_all,mail.vote.all,model_mail_vote,,1,1,1,1 access_mail_vote_all,mail.vote.all,model_mail_vote,,1,1,1,1
access_mail_favorite_all,mail.favorite.all,model_mail_favorite,,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_mail_message_all mail.message.all model_mail_message 1 0 1 0
3 access_mail_message_group_user mail.message.group.user model_mail_message base.group_user 1 1 1 1
4 access_mail_mail_all mail.mail.all model_mail_mail 0 0 1 0
5 access_mail_mail_user mail.mail model_mail_mail base.group_user 1 1 1 0
6 access_mail_mail_system mail.mail.system model_mail_mail base.group_system 1 1 1 1
7 access_mail_followers_all mail.followers.all model_mail_followers 1 0 0 0
8 access_mail_followers_system mail.followers.system model_mail_followers base.group_system 1 1 1 1
13 access_mail_alias_all mail.alias.all model_mail_alias 1 0 0 0
14 access_mail_alias_user mail.alias model_mail_alias base.group_user 1 1 1 0
15 access_mail_alias_system mail.alias model_mail_alias base.group_system 1 1 1 1
16 access_mail_message_subtype access_mail_message_subtype_all mail.message.subtype mail.message.subtype.all model_mail_message_subtype 1 1 0 1 0 1 0
access_mail_mail_user mail.mail model_mail_mail base.group_user 1 1 1 0
17 access_mail_vote_all mail.vote.all model_mail_vote 1 1 1 1
18 access_mail_favorite_all mail.favorite.all model_mail_favorite 1 1 1 1

View File

@ -359,7 +359,6 @@ openerp.mail = function (session) {
mail.ChatterUtils.get_text2html(body), mail.ChatterUtils.get_text2html(body),
false, false,
'comment', 'comment',
'mail.mt_comment',
this.context.default_parent_id, this.context.default_parent_id,
attachments, attachments,
this.parent_thread.context this.parent_thread.context
@ -438,7 +437,7 @@ openerp.mail = function (session) {
// data of this expandable message // data of this expandable message
this.id = datasets.id || -1, this.id = datasets.id || -1,
this.model = datasets.model || false, this.model = datasets.model || false,
this.ancestor_id = datasets.ancestor_id || false, this.parent_id = datasets.parent_id || false,
this.nb_messages = datasets.nb_messages || 0, this.nb_messages = datasets.nb_messages || 0,
this.thread_level = datasets.thread_level || 0, this.thread_level = datasets.thread_level || 0,
this.type = 'expandable', this.type = 'expandable',
@ -512,10 +511,10 @@ openerp.mail = function (session) {
* - record.attachment_ids[].url: url of each attachmentThe * - record.attachment_ids[].url: url of each attachmentThe
* thread view : * thread view :
* - root thread * - root thread
* - - sub message (ancestor_id = root message) * - - sub message (parent_id = root message)
* - - - sub thread * - - - sub thread
* - - - - sub sub message (parent id = sub thread) * - - - - sub sub message (parent id = sub thread)
* - - sub message (ancestor_id = root message) * - - sub message (parent_id = root message)
* - - - sub thread * - - - sub thread
*/ */
mail.ThreadMessage = session.web.Widget.extend({ mail.ThreadMessage = session.web.Widget.extend({
@ -553,7 +552,7 @@ openerp.mail = function (session) {
// data of this message // data of this message
this.id = datasets.id || -1, this.id = datasets.id || -1,
this.model = datasets.model || false, this.model = datasets.model || false,
this.ancestor_id = datasets.ancestor_id || false, this.parent_id = datasets.parent_id || false,
this.res_id = datasets.res_id || false, this.res_id = datasets.res_id || false,
this.type = datasets.type || false, this.type = datasets.type || false,
this.is_author = datasets.is_author || false, this.is_author = datasets.is_author || false,
@ -864,10 +863,10 @@ openerp.mail = function (session) {
* This widget handles the display of a thread of messages. The * This widget handles the display of a thread of messages. The
* thread view: * thread view:
* - root thread * - root thread
* - - sub message (ancestor_id = root message) * - - sub message (parent_id = root message)
* - - - sub thread * - - - sub thread
* - - - - sub sub message (parent id = sub thread) * - - - - sub sub message (parent id = sub thread)
* - - sub message (ancestor_id = root message) * - - sub message (parent_id = root message)
* - - - sub thread * - - - sub thread
*/ */
mail.Thread = session.web.Widget.extend({ mail.Thread = session.web.Widget.extend({
@ -907,7 +906,7 @@ openerp.mail = function (session) {
// data of this thread // data of this thread
this.id = datasets.id || false, this.id = datasets.id || false,
this.model = datasets.model || false, this.model = datasets.model || false,
this.ancestor_id = datasets.ancestor_id || false, this.parent_id = datasets.parent_id || false,
this.is_private = datasets.is_private || false, this.is_private = datasets.is_private || false,
this.author_id = datasets.author_id || false, this.author_id = datasets.author_id || false,
this.thread_level = (datasets.thread_level+1) || 0, this.thread_level = (datasets.thread_level+1) || 0,
@ -1119,8 +1118,8 @@ openerp.mail = function (session) {
// CHM note : option for sending in flat mode by server // CHM note : option for sending in flat mode by server
var nb_indented_thread = this.options.display_indented_thread > this.thread_level ? this.options.display_indented_thread - this.thread_level : 0; var nb_indented_thread = this.options.display_indented_thread > this.thread_level ? this.options.display_indented_thread - this.thread_level : 0;
return this.ds_message.call('message_read', [ids, fetch_domain, message_loaded_ids, nb_indented_thread, fetch_context, this.context.default_parent_id || undefined] return this.ds_message.call('message_read', [ids, fetch_domain, message_loaded_ids, nb_indented_thread, fetch_context, this.context.default_parent_id || undefined])
).then(this.proxy('switch_new_message')); .then(this.proxy('switch_new_message'));
}, },
/** /**
@ -1254,7 +1253,7 @@ openerp.mail = function (session) {
var self=this; var self=this;
_(records).each(function (record) { _(records).each(function (record) {
var thread = self.browse_thread({ var thread = self.browse_thread({
'id': record.ancestor_id, 'id': record.parent_id,
'default_return_top_thread':true 'default_return_top_thread':true
}); });
// create object and attach to the thread object // create object and attach to the thread object
@ -1334,10 +1333,10 @@ openerp.mail = function (session) {
var expandable = new mail.ThreadExpandable(this, { var expandable = new mail.ThreadExpandable(this, {
'id': message.id, 'id': message.id,
'model': message.model, 'model': message.model,
'ancestor_id': message.ancestor_id, 'parent_id': message.parent_id,
'nb_messages': 1, 'nb_messages': 1,
'thread_level': message.thread_level, 'thread_level': message.thread_level,
'ancestor_id': message.ancestor_id, 'parent_id': message.parent_id,
'domain': message_dom, 'domain': message_dom,
'options': message.options, 'options': message.options,
}, { }, {

View File

@ -94,6 +94,8 @@ class TestMailMockups(common.TransactionCase):
self._build_email_kwargs_list = [] self._build_email_kwargs_list = []
def _mock_build_email(self, *args, **kwargs): def _mock_build_email(self, *args, **kwargs):
""" Mock build_email to be able to test its values. Store them into
some internal variable for latter processing. """
self._build_email_args_list.append(args) self._build_email_args_list.append(args)
self._build_email_kwargs_list.append(kwargs) self._build_email_kwargs_list.append(kwargs)
return self._build_email(*args, **kwargs) return self._build_email(*args, **kwargs)
@ -140,7 +142,9 @@ class test_mail(TestMailMockups):
group_employee_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'base', 'group_user') group_employee_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'base', 'group_user')
group_employee_id = group_employee_ref and group_employee_ref[1] or False group_employee_id = group_employee_ref and group_employee_ref[1] or False
# Test users # Test users
self.user_raoul_id = self.res_users.create(cr, uid, {'name': 'Raoul Grosbedon', 'login': 'raoul', 'groups_id': [(6, 0, [group_employee_id])]}) self.user_raoul_id = self.res_users.create(cr, uid,
{'name': 'Raoul Grosbedon', 'email': 'raoul@raoul.fr', 'login': 'raoul', 'groups_id': [(6, 0, [group_employee_id])]})
self.user_raoul = self.res_users.browse(cr, uid, self.user_raoul_id)
self.user_admin = self.res_users.browse(cr, uid, uid) self.user_admin = self.res_users.browse(cr, uid, uid)
# Mock send_get_mail_body to test its functionality without other addons override # Mock send_get_mail_body to test its functionality without other addons override
@ -163,7 +167,7 @@ class test_mail(TestMailMockups):
def test_00_message_process(self): def test_00_message_process(self):
""" Testing incoming emails processing. """ """ Testing incoming emails processing. """
cr, uid = self.cr, self.uid cr, uid, user_raoul = self.cr, self.uid, self.user_raoul
# Incoming mail creates a new mail_group "frogs" # Incoming mail creates a new mail_group "frogs"
self.assertEqual(self.mail_group.search(cr, uid, [('name', '=', 'frogs')]), []) self.assertEqual(self.mail_group.search(cr, uid, [('name', '=', 'frogs')]), [])
mail_frogs = MAIL_TEMPLATE.format(to='groups@example.com, other@gmail.com', subject='frogs', extra='') mail_frogs = MAIL_TEMPLATE.format(to='groups@example.com, other@gmail.com', subject='frogs', extra='')
@ -201,6 +205,26 @@ class test_mail(TestMailMockups):
self.assertEqual(new_mail.body, '\n<pre>\nPlease call me as soon as possible this afternoon!\n\n--\nSylvie\n</pre>\n', self.assertEqual(new_mail.body, '\n<pre>\nPlease call me as soon as possible this afternoon!\n\n--\nSylvie\n</pre>\n',
'plaintext mail incorrectly parsed') 'plaintext mail incorrectly parsed')
# Do: post a new message, with a known partner
test_msg_id = '<deadcafe.1337-2@smtp.agrolait.com>'
TEMPLATE_MOD = MAIL_TEMPLATE_PLAINTEXT.replace('Sylvie Lelitre <sylvie.lelitre@agrolait.com>', user_raoul.email)
mail_new = TEMPLATE_MOD.format(to='Friendly Frogs <group+frogs@example.com>', subject='extra news', extra='', msg_id=test_msg_id)
self.mail_thread.message_process(cr, uid, None, mail_new)
new_mail = self.mail_message.browse(cr, uid, self.mail_message.search(cr, uid, [('message_id', '=', test_msg_id)])[0])
# Test: author_id set, not email_from
self.assertEqual(new_mail.author_id, user_raoul.partner_id, 'message process wrong author found')
self.assertFalse(new_mail.email_from, 'message process should not set the email_from when an author is found')
# Do: post a new message, with a unknown partner
test_msg_id = '<deadcafe.1337-3@smtp.agrolait.com>'
TEMPLATE_MOD = MAIL_TEMPLATE_PLAINTEXT.replace('Sylvie Lelitre <sylvie.lelitre@agrolait.com>', '_abcd_')
mail_new = TEMPLATE_MOD.format(to='Friendly Frogs <group+frogs@example.com>', subject='super news', extra='', msg_id=test_msg_id)
self.mail_thread.message_process(cr, uid, None, mail_new)
new_mail = self.mail_message.browse(cr, uid, self.mail_message.search(cr, uid, [('message_id', '=', test_msg_id)])[0])
# Test: author_id set, not email_from
self.assertFalse(new_mail.author_id, 'message process shnould not have found a partner for _abcd_ email address')
self.assertIn('_abcd_', new_mail.email_from, 'message process should set en email_from when not finding a partner_id')
def test_10_followers_function_field(self): def test_10_followers_function_field(self):
""" Tests designed for the many2many function field 'follower_ids'. """ Tests designed for the many2many function field 'follower_ids'.
We will test to perform writes using the many2many commands 0, 3, 4, We will test to perform writes using the many2many commands 0, 3, 4,
@ -315,7 +339,25 @@ class test_mail(TestMailMockups):
self.assertTrue(subtype_data['mt_mg_nodef']['followed'], 'Admin should follow mt_mg_nodef in pigs') self.assertTrue(subtype_data['mt_mg_nodef']['followed'], 'Admin should follow mt_mg_nodef in pigs')
self.assertTrue(subtype_data['mt_all_nodef']['followed'], 'Admin should follow mt_all_nodef in pigs') self.assertTrue(subtype_data['mt_all_nodef']['followed'], 'Admin should follow mt_all_nodef in pigs')
def test_20_message_post(self): def test_20_message_quote_context(self):
""" Tests designed for message_post. """
cr, uid, user_admin, group_pigs = self.cr, self.uid, self.user_admin, self.group_pigs
msg1_id = self.mail_message.create(cr, uid, {'body': 'Thread header about Zap Brannigan', 'subject': 'My subject'})
msg2_id = self.mail_message.create(cr, uid, {'body': 'First answer, should not be displayed', 'subject': 'Re: My subject', 'parent_id': msg1_id})
msg3_id = self.mail_message.create(cr, uid, {'body': 'Second answer', 'subject': 'Re: My subject', 'parent_id': msg1_id})
msg4_id = self.mail_message.create(cr, uid, {'body': 'Third answer', 'subject': 'Re: My subject', 'parent_id': msg1_id})
msg_new_id = self.mail_message.create(cr, uid, {'body': 'My answer I am propagating', 'subject': 'Re: My subject', 'parent_id': msg1_id})
result = self.mail_message.message_quote_context(cr, uid, msg_new_id, limit=3)
self.assertIn('Thread header about Zap Brannigan', result, 'Thread header content should be in quote.')
self.assertIn('Second answer', result, 'Answer should be in quote.')
self.assertIn('Third answer', result, 'Answer should be in quote.')
self.assertIn('expandable', result, 'Expandable should be present.')
self.assertNotIn('First answer, should not be displayed', result, 'Old answer should not be in quote.')
self.assertNotIn('My answer I am propagating', result, 'Thread header content should be in quote.')
def test_21_message_post(self):
""" Tests designed for message_post. """ """ Tests designed for message_post. """
cr, uid, user_admin, group_pigs = self.cr, self.uid, self.user_admin, self.group_pigs cr, uid, user_admin, group_pigs = self.cr, self.uid, self.user_admin, self.group_pigs
self.res_users.write(cr, uid, [uid], {'signature': 'Admin', 'email': 'a@a'}) self.res_users.write(cr, uid, [uid], {'signature': 'Admin', 'email': 'a@a'})
@ -361,11 +403,11 @@ class test_mail(TestMailMockups):
# the html2plaintext uses etree or beautiful soup, so the result may be slighly different # the html2plaintext uses etree or beautiful soup, so the result may be slighly different
# depending if you have installed beautiful soup. # depending if you have installed beautiful soup.
self.assertIn(sent_email['body_alternative'], _mail_bodyalt1 + '\nBert Tartopoils\n', 'sent_email body_alternative is incorrect') self.assertIn(sent_email['body_alternative'], _mail_bodyalt1 + '\nBert Tartopoils\n', 'sent_email body_alternative is incorrect')
# Test: mail_message: partner_ids = group followers # Test: mail_message: notified_partner_ids = group followers
message_pids = set([partner.id for partner in message.partner_ids]) message_pids = set([partner.id for partner in message.notified_partner_ids])
test_pids = set([p_b_id, p_c_id]) test_pids = set([p_b_id, p_c_id])
self.assertEqual(test_pids, message_pids, 'mail.message partners incorrect') self.assertEqual(test_pids, message_pids, 'mail.message partners incorrect')
# Test: notification linked to this message = group followers = partner_ids # Test: notification linked to this message = group followers = notified_partner_ids
notif_ids = self.mail_notification.search(cr, uid, [('message_id', '=', message.id)]) notif_ids = self.mail_notification.search(cr, uid, [('message_id', '=', message.id)])
notif_pids = set([notif.partner_id.id for notif in self.mail_notification.browse(cr, uid, notif_ids)]) notif_pids = set([notif.partner_id.id for notif in self.mail_notification.browse(cr, uid, notif_ids)])
self.assertEqual(notif_pids, test_pids, 'mail.message notification partners incorrect') self.assertEqual(notif_pids, test_pids, 'mail.message notification partners incorrect')
@ -394,11 +436,11 @@ class test_mail(TestMailMockups):
self.assertEqual(sent_email['subject'], _mail_subject, 'sent_email subject incorrect') self.assertEqual(sent_email['subject'], _mail_subject, 'sent_email subject incorrect')
self.assertIn(_mail_body2, sent_email['body'], 'sent_email body incorrect') self.assertIn(_mail_body2, sent_email['body'], 'sent_email body incorrect')
self.assertIn(_mail_bodyalt2, sent_email['body_alternative'], 'sent_email body_alternative incorrect') self.assertIn(_mail_bodyalt2, sent_email['body_alternative'], 'sent_email body_alternative incorrect')
# Test: mail_message: partner_ids = group followers # Test: mail_message: notified_partner_ids = group followers
message_pids = set([partner.id for partner in message.partner_ids]) message_pids = set([partner.id for partner in message.notified_partner_ids])
test_pids = set([p_b_id, p_c_id, p_d_id]) test_pids = set([p_b_id, p_c_id, p_d_id])
self.assertEqual(message_pids, test_pids, 'mail.message partners incorrect') self.assertEqual(message_pids, test_pids, 'mail.message partners incorrect')
# Test: notifications linked to this message = group followers = partner_ids # Test: notifications linked to this message = group followers = notified_partner_ids
notif_ids = self.mail_notification.search(cr, uid, [('message_id', '=', message.id)]) notif_ids = self.mail_notification.search(cr, uid, [('message_id', '=', message.id)])
notif_pids = set([notif.partner_id.id for notif in self.mail_notification.browse(cr, uid, notif_ids)]) notif_pids = set([notif.partner_id.id for notif in self.mail_notification.browse(cr, uid, notif_ids)])
self.assertEqual(notif_pids, test_pids, 'mail.message notification partners incorrect') self.assertEqual(notif_pids, test_pids, 'mail.message notification partners incorrect')
@ -412,6 +454,11 @@ class test_mail(TestMailMockups):
self.assertIn((attach.name, attach.datas.decode('base64')), _attachments, self.assertIn((attach.name, attach.datas.decode('base64')), _attachments,
'mail.message attachment name / data incorrect') 'mail.message attachment name / data incorrect')
# 3. Reply to the last message, check that its parent will be the first message
msg_id3 = self.mail_group.message_post(cr, uid, self.group_pigs_id, body='Test', parent_id=msg_id2)
message = self.mail_message.browse(cr, uid, msg_id3)
self.assertEqual(message.parent_id.id, msg_id, 'message_post did not flatten the thread structure')
def test_25_message_compose_wizard(self): def test_25_message_compose_wizard(self):
""" Tests designed for the mail.compose.message wizard. """ """ Tests designed for the mail.compose.message wizard. """
cr, uid, user_admin, group_pigs = self.cr, self.uid, self.user_admin, self.group_pigs cr, uid, user_admin, group_pigs = self.cr, self.uid, self.user_admin, self.group_pigs
@ -462,12 +509,12 @@ class test_mail(TestMailMockups):
# Test: mail.message: subject, body inside pre # Test: mail.message: subject, body inside pre
self.assertEqual(message.subject, False, 'mail.message incorrect subject') self.assertEqual(message.subject, False, 'mail.message incorrect subject')
self.assertEqual(message.body, _msg_body, 'mail.message incorrect body') self.assertEqual(message.body, _msg_body, 'mail.message incorrect body')
# Test: mail.message: partner_ids = entries in mail.notification: group_pigs fans (a, b) + mail.compose.message partner_ids (c, d) # Test: mail.message: notified_partner_ids = entries in mail.notification: group_pigs fans (a, b) + mail.compose.message partner_ids (c, d)
msg_pids = [partner.id for partner in message.partner_ids] msg_pids = [partner.id for partner in message.notified_partner_ids]
test_pids = [p_b_id, p_c_id, p_d_id] test_pids = [p_b_id, p_c_id, p_d_id]
notif_ids = self.mail_notification.search(cr, uid, [('message_id', '=', message.id)]) notif_ids = self.mail_notification.search(cr, uid, [('message_id', '=', message.id)])
self.assertEqual(len(notif_ids), 3, 'mail.message: too much notifications created') self.assertEqual(len(notif_ids), 3, 'mail.message: too much notifications created')
self.assertEqual(set(msg_pids), set(test_pids), 'mail.message partner_ids incorrect') self.assertEqual(set(msg_pids), set(test_pids), 'mail.message notified_partner_ids incorrect')
# ---------------------------------------- # ----------------------------------------
# CASE2: reply to last comment with attachments # CASE2: reply to last comment with attachments
@ -526,20 +573,6 @@ class test_mail(TestMailMockups):
def test_30_message_read(self): def test_30_message_read(self):
""" Tests for message_read and expandables. """ """ Tests for message_read and expandables. """
def _print_debug(message, debug=True, prefix=''):
if debug:
print prefix, message
def _print_msg(message, debug=True, prefix=''):
if not debug:
return
if message.get('type') == 'expandable':
print prefix, 'expandable', message
else:
print prefix, 'message', message.get('body'), message.get('id'), message.get('ancestor_id')
_debug = False
cr, uid, user_admin, group_pigs = self.cr, self.uid, self.user_admin, self.group_pigs cr, uid, user_admin, group_pigs = self.cr, self.uid, self.user_admin, self.group_pigs
pigs_domain = [('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)] pigs_domain = [('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)]
@ -574,7 +607,6 @@ class test_mail(TestMailMockups):
# CASE1: message_read with domain, threaded # CASE1: message_read with domain, threaded
# We simulate an entire flow, using the expandables to test them # We simulate an entire flow, using the expandables to test them
# ---------------------------------------- # ----------------------------------------
_print_debug('\nCASE1: message_read with domain, threaded\n', _debug)
# Do: read last message, threaded # Do: read last message, threaded
read_msg_list = self.mail_message.message_read(cr, uid, domain=pigs_domain, limit=1, thread_level=1) read_msg_list = self.mail_message.message_read(cr, uid, domain=pigs_domain, limit=1, thread_level=1)
@ -582,11 +614,10 @@ class test_mail(TestMailMockups):
# Test: structure content, ancestor is added to the read messages, ordered by id, ancestor is set, 2 expandables # Test: structure content, ancestor is added to the read messages, ordered by id, ancestor is set, 2 expandables
self.assertEqual(len(read_msg_list), 4, 'message_read on last Pigs message should return 2 messages and 2 expandables') self.assertEqual(len(read_msg_list), 4, 'message_read on last Pigs message should return 2 messages and 2 expandables')
self.assertEqual(set([msg_id2, msg_id10]), set(read_msg_ids), 'message_read on the last Pigs message should also get its parent') self.assertEqual(set([msg_id2, msg_id10]), set(read_msg_ids), 'message_read on the last Pigs message should also get its parent')
self.assertEqual(read_msg_list[1].get('ancestor_id'), read_msg_list[0].get('id'), 'message_read should set the ancestor to the thread header') self.assertEqual(read_msg_list[1].get('parent_id'), read_msg_list[0].get('id'), 'message_read should set the ancestor to the thread header')
# Data: get expandables # Data: get expandables
new_threads_exp, new_msg_exp = None, None new_threads_exp, new_msg_exp = None, None
for msg in read_msg_list: for msg in read_msg_list:
_print_msg(msg, _debug)
if msg.get('type') == 'expandable' and msg.get('nb_messages') == -1 and msg.get('id') == -1: if msg.get('type') == 'expandable' and msg.get('nb_messages') == -1 and msg.get('id') == -1:
new_threads_exp = msg new_threads_exp = msg
elif msg.get('type') == 'expandable': elif msg.get('type') == 'expandable':
@ -596,15 +627,12 @@ class test_mail(TestMailMockups):
self.assertIsNotNone(new_msg_exp, 'message_read on last Pigs message should have returned a new messages expandable') self.assertIsNotNone(new_msg_exp, 'message_read on last Pigs message should have returned a new messages expandable')
domain = new_msg_exp.get('domain', []) domain = new_msg_exp.get('domain', [])
# Test: expandable, conditions in domain # Test: expandable, conditions in domain
_print_debug('Executing %s' % domain, _debug)
self.assertIn(('id', 'child_of', msg_id2), domain, 'new messages expandable domain should contain a child_of condition') self.assertIn(('id', 'child_of', msg_id2), domain, 'new messages expandable domain should contain a child_of condition')
self.assertIn(('id', '>=', msg_id4), domain, 'new messages expandable domain should contain an id greater than condition') self.assertIn(('id', '>=', msg_id4), domain, 'new messages expandable domain should contain an id greater than condition')
self.assertIn(('id', '<=', msg_id8), domain, 'new messages expandable domain should contain an id less than condition') self.assertIn(('id', '<=', msg_id8), domain, 'new messages expandable domain should contain an id less than condition')
self.assertEqual(new_msg_exp.get('ancestor_id'), msg_id2, 'new messages expandable should have ancestor_id set to the thread header') self.assertEqual(new_msg_exp.get('parent_id'), msg_id2, 'new messages expandable should have ancestor_id set to the thread header')
# Do: message_read with domain, thread_level=0, parent_id=msg_id2 (should be imposed by JS) # Do: message_read with domain, thread_level=0, parent_id=msg_id2 (should be imposed by JS)
read_msg_list = self.mail_message.message_read(cr, uid, domain=domain, limit=200, thread_level=0, parent_id=msg_id2) read_msg_list = self.mail_message.message_read(cr, uid, domain=domain, limit=200, thread_level=0, parent_id=msg_id2)
for msg in read_msg_list:
_print_msg(msg, _debug)
read_msg_ids = [msg.get('id') for msg in read_msg_list if msg.get('type') != 'expandable'] read_msg_ids = [msg.get('id') for msg in read_msg_list if msg.get('type') != 'expandable']
# Test: other message in thread have been fetch # Test: other message in thread have been fetch
self.assertEqual(set([msg_id4, msg_id6, msg_id8]), set(read_msg_ids), 'message_read in Pigs thread should return all the previous messages') self.assertEqual(set([msg_id4, msg_id6, msg_id8]), set(read_msg_ids), 'message_read in Pigs thread should return all the previous messages')
@ -613,21 +641,19 @@ class test_mail(TestMailMockups):
self.assertIsNotNone(new_threads_exp, 'message_read on last Pigs message should have returned a new threads expandable') self.assertIsNotNone(new_threads_exp, 'message_read on last Pigs message should have returned a new threads expandable')
domain = new_threads_exp.get('domain', []) domain = new_threads_exp.get('domain', [])
# Test: expandable, conditions in domain # Test: expandable, conditions in domain
_print_debug('Executing %s' % domain, _debug)
for condition in pigs_domain: for condition in pigs_domain:
self.assertIn(condition, domain, 'new threads expandable domain should contain the message_read domain parameter') self.assertIn(condition, domain, 'new threads expandable domain should contain the message_read domain parameter')
self.assertFalse(new_threads_exp.get('ancestor_id'), 'new threads expandable should not have an ancestor_id') self.assertFalse(new_threads_exp.get('parent_id'), 'new threads expandable should not have an ancestor_id')
# Do: message_read with domain, thread_level=1 (should be imposed by JS) # Do: message_read with domain, thread_level=1 (should be imposed by JS)
read_msg_list = self.mail_message.message_read(cr, uid, domain=domain, limit=1, thread_level=1) read_msg_list = self.mail_message.message_read(cr, uid, domain=domain, limit=1, thread_level=1)
read_msg_ids = [msg.get('id') for msg in read_msg_list if msg.get('type') != 'expandable'] read_msg_ids = [msg.get('id') for msg in read_msg_list if msg.get('type') != 'expandable']
# Test: structure content, ancestor is added to the read messages, ordered by id, ancestor is set, 2 expandables # Test: structure content, ancestor is added to the read messages, ordered by id, ancestor is set, 2 expandables
self.assertEqual(len(read_msg_list), 4, 'message_read on Pigs should return 2 messages and 2 expandables') self.assertEqual(len(read_msg_list), 4, 'message_read on Pigs should return 2 messages and 2 expandables')
self.assertEqual(set([msg_id1, msg_id9]), set(read_msg_ids), 'message_read on a Pigs message should also get its parent') self.assertEqual(set([msg_id1, msg_id9]), set(read_msg_ids), 'message_read on a Pigs message should also get its parent')
self.assertEqual(read_msg_list[1].get('ancestor_id'), read_msg_list[0].get('id'), 'message_read should set the ancestor to the thread header') self.assertEqual(read_msg_list[1].get('parent_id'), read_msg_list[0].get('id'), 'message_read should set the ancestor to the thread header')
# Data: get expandables # Data: get expandables
new_threads_exp, new_msg_exp = None, None new_threads_exp, new_msg_exp = None, None
for msg in read_msg_list: for msg in read_msg_list:
_print_msg(msg, _debug)
if msg.get('type') == 'expandable' and msg.get('nb_messages') == -1 and msg.get('id') == -1: if msg.get('type') == 'expandable' and msg.get('nb_messages') == -1 and msg.get('id') == -1:
new_threads_exp = msg new_threads_exp = msg
elif msg.get('type') == 'expandable': elif msg.get('type') == 'expandable':
@ -637,15 +663,12 @@ class test_mail(TestMailMockups):
self.assertIsNotNone(new_msg_exp, 'message_read on Pigs message should have returned a new messages expandable') self.assertIsNotNone(new_msg_exp, 'message_read on Pigs message should have returned a new messages expandable')
domain = new_msg_exp.get('domain', []) domain = new_msg_exp.get('domain', [])
# Test: expandable, conditions in domain # Test: expandable, conditions in domain
_print_debug('Executing %s' % domain, _debug)
self.assertIn(('id', 'child_of', msg_id1), domain, 'new messages expandable domain should contain a child_of condition') self.assertIn(('id', 'child_of', msg_id1), domain, 'new messages expandable domain should contain a child_of condition')
self.assertIn(('id', '>=', msg_id3), domain, 'new messages expandable domain should contain an id greater than condition') self.assertIn(('id', '>=', msg_id3), domain, 'new messages expandable domain should contain an id greater than condition')
self.assertIn(('id', '<=', msg_id7), domain, 'new messages expandable domain should contain an id less than condition') self.assertIn(('id', '<=', msg_id7), domain, 'new messages expandable domain should contain an id less than condition')
self.assertEqual(new_msg_exp.get('ancestor_id'), msg_id1, 'new messages expandable should have ancestor_id set to the thread header') self.assertEqual(new_msg_exp.get('parent_id'), msg_id1, 'new messages expandable should have ancestor_id set to the thread header')
# Do: message_read with domain, thread_level=0, parent_id=msg_id1 (should be imposed by JS) # Do: message_read with domain, thread_level=0, parent_id=msg_id1 (should be imposed by JS)
read_msg_list = self.mail_message.message_read(cr, uid, domain=domain, limit=200, thread_level=0, parent_id=msg_id1) read_msg_list = self.mail_message.message_read(cr, uid, domain=domain, limit=200, thread_level=0, parent_id=msg_id1)
for msg in read_msg_list:
_print_msg(msg, _debug)
read_msg_ids = [msg.get('id') for msg in read_msg_list if msg.get('type') != 'expandable'] read_msg_ids = [msg.get('id') for msg in read_msg_list if msg.get('type') != 'expandable']
# Test: other message in thread have been fetch # Test: other message in thread have been fetch
self.assertEqual(set([msg_id3, msg_id5, msg_id7]), set(read_msg_ids), 'message_read on the last Pigs message should also get its parent') self.assertEqual(set([msg_id3, msg_id5, msg_id7]), set(read_msg_ids), 'message_read on the last Pigs message should also get its parent')
@ -654,7 +677,6 @@ class test_mail(TestMailMockups):
self.assertIsNotNone(new_threads_exp, 'message_read should have returned a new threads expandable') self.assertIsNotNone(new_threads_exp, 'message_read should have returned a new threads expandable')
domain = new_threads_exp.get('domain', []) domain = new_threads_exp.get('domain', [])
# Test: expandable, conditions in domain # Test: expandable, conditions in domain
_print_debug('Executing %s' % domain, _debug)
for condition in pigs_domain: for condition in pigs_domain:
self.assertIn(condition, domain, 'general expandable domain should contain the message_read domain parameter') self.assertIn(condition, domain, 'general expandable domain should contain the message_read domain parameter')
# Do: message_read with domain, thread_level=1 (should be imposed by JS) # Do: message_read with domain, thread_level=1 (should be imposed by JS)
@ -663,13 +685,10 @@ class test_mail(TestMailMockups):
# Test: structure content, ancestor is added to the read messages, ordered by id, ancestor is set, 2 expandables # Test: structure content, ancestor is added to the read messages, ordered by id, ancestor is set, 2 expandables
self.assertEqual(len(read_msg_list), 1, 'message_read on Pigs should return 1 message because everything else has been fetched') self.assertEqual(len(read_msg_list), 1, 'message_read on Pigs should return 1 message because everything else has been fetched')
self.assertEqual([msg_id0], read_msg_ids, 'message_read after 2 More should return only 1 last message') self.assertEqual([msg_id0], read_msg_ids, 'message_read after 2 More should return only 1 last message')
for msg in read_msg_list:
_print_msg(msg, _debug)
# ---------------------------------------- # ----------------------------------------
# CASE2: message_read with domain, flat # CASE2: message_read with domain, flat
# ---------------------------------------- # ----------------------------------------
_print_debug('\nCASE2: message_read with domain, flat\n', _debug)
# Do: read 2 lasts message, flat # Do: read 2 lasts message, flat
read_msg_list = self.mail_message.message_read(cr, uid, domain=pigs_domain, limit=2, thread_level=0) read_msg_list = self.mail_message.message_read(cr, uid, domain=pigs_domain, limit=2, thread_level=0)
@ -677,12 +696,11 @@ class test_mail(TestMailMockups):
# Test: structure content, ancestor is added to the read messages, ordered by id, ancestor is not set, 1 expandable # Test: structure content, ancestor is added to the read messages, ordered by id, ancestor is not set, 1 expandable
self.assertEqual(len(read_msg_list), 3, 'message_read on last Pigs message should return 2 messages and 1 expandable') self.assertEqual(len(read_msg_list), 3, 'message_read on last Pigs message should return 2 messages and 1 expandable')
self.assertEqual(set([msg_id9, msg_id10]), set(read_msg_ids), 'message_read flat on Pigs last messages should only return those messages') self.assertEqual(set([msg_id9, msg_id10]), set(read_msg_ids), 'message_read flat on Pigs last messages should only return those messages')
self.assertFalse(read_msg_list[0].get('ancestor_id'), 'message_read flat should set the ancestor as False') self.assertFalse(read_msg_list[0].get('parent_id'), 'message_read flat should set the ancestor as False')
self.assertFalse(read_msg_list[1].get('ancestor_id'), 'message_read flat should set the ancestor as False') self.assertFalse(read_msg_list[1].get('parent_id'), 'message_read flat should set the ancestor as False')
# Data: get expandables # Data: get expandables
new_threads_exp, new_msg_exp = None, None new_threads_exp, new_msg_exp = None, None
for msg in read_msg_list: for msg in read_msg_list:
_print_msg(msg, _debug)
if msg.get('type') == 'expandable' and msg.get('nb_messages') == -1 and msg.get('id') == -1: if msg.get('type') == 'expandable' and msg.get('nb_messages') == -1 and msg.get('id') == -1:
new_threads_exp = msg new_threads_exp = msg
@ -690,7 +708,6 @@ class test_mail(TestMailMockups):
self.assertIsNotNone(new_threads_exp, 'message_read flat on the 2 last Pigs messages should have returns a new threads expandable') self.assertIsNotNone(new_threads_exp, 'message_read flat on the 2 last Pigs messages should have returns a new threads expandable')
domain = new_threads_exp.get('domain', []) domain = new_threads_exp.get('domain', [])
# Test: expandable, conditions in domain # Test: expandable, conditions in domain
_print_debug('Executing %s' % domain, _debug)
for condition in pigs_domain: for condition in pigs_domain:
self.assertIn(condition, domain, 'new threads expandable domain should contain the message_read domain parameter') self.assertIn(condition, domain, 'new threads expandable domain should contain the message_read domain parameter')
# Do: message_read with domain, thread_level=0 (should be imposed by JS) # Do: message_read with domain, thread_level=0 (should be imposed by JS)
@ -700,8 +717,6 @@ class test_mail(TestMailMockups):
self.assertEqual(len(read_msg_list), 9, 'message_read on Pigs should return 9 messages and 0 expandable') self.assertEqual(len(read_msg_list), 9, 'message_read on Pigs should return 9 messages and 0 expandable')
self.assertEqual([msg_id0, msg_id1, msg_id2, msg_id3, msg_id4, msg_id5, msg_id6, msg_id7, msg_id8], read_msg_ids, self.assertEqual([msg_id0, msg_id1, msg_id2, msg_id3, msg_id4, msg_id5, msg_id6, msg_id7, msg_id8], read_msg_ids,
'message_read, More on flat, should return all remaning messages') 'message_read, More on flat, should return all remaning messages')
for msg in read_msg_list:
_print_msg(msg, _debug)
def test_40_needaction(self): def test_40_needaction(self):
""" Tests for mail.message needaction. """ """ Tests for mail.message needaction. """
@ -760,22 +775,11 @@ class test_mail(TestMailMockups):
reply_msg = MAIL_TEMPLATE.format(to='Pretty Pigs <group+pigs@example.com>, other@gmail.com', subject='Re: 1', reply_msg = MAIL_TEMPLATE.format(to='Pretty Pigs <group+pigs@example.com>, other@gmail.com', subject='Re: 1',
extra='In-Reply-To: %s' % msg1.message_id) extra='In-Reply-To: %s' % msg1.message_id)
self.mail_group.message_process(cr, uid, None, reply_msg) self.mail_group.message_process(cr, uid, None, reply_msg)
# TDE note: temp various asserts because of the random bug about msg1.child_ids
msg_ids = self.mail_message.search(cr, uid, [('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)], limit=1)
new_msg = self.mail_message.browse(cr, uid, msg_ids[0])
# if new_msg.parent_id.id != msg1.id:
# import pdb
# pdb.set_trace()
self.assertEqual(new_msg.parent_id, msg1, 'Newly processed mail_message (%d) should have msg1 as parent (msg2 is %d)' % (new_msg.id, msg2.id))
# 2. References header # 2. References header
reply_msg2 = MAIL_TEMPLATE.format(to='Pretty Pigs <group+pigs@example.com>, other@gmail.com', subject='Re: Re: 1', reply_msg2 = MAIL_TEMPLATE.format(to='Pretty Pigs <group+pigs@example.com>, other@gmail.com', subject='Re: Re: 1',
extra='References: <2233@a.com>\r\n\t<3edss_dsa@b.com> %s' % msg1.message_id) extra='References: <2233@a.com>\r\n\t<3edss_dsa@b.com> %s' % msg1.message_id)
self.mail_group.message_process(cr, uid, None, reply_msg2) self.mail_group.message_process(cr, uid, None, reply_msg2)
# TDE note: temp various asserts because of the random bug about msg1.child_ids
msg_ids = self.mail_message.search(cr, uid, [('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)], limit=1)
new_msg = self.mail_message.browse(cr, uid, msg_ids[0])
self.assertEqual(new_msg.parent_id, msg1, 'Newly processed mail_message should have msg1 as parent')
# 3. Subject contains [<ID>] + model passed to message+process -> only attached to group, not to mail # 3. Subject contains [<ID>] + model passed to message+process -> only attached to group, not to mail
reply_msg3 = MAIL_TEMPLATE.format(to='Pretty Pigs <group+pigs@example.com>, other@gmail.com', reply_msg3 = MAIL_TEMPLATE.format(to='Pretty Pigs <group+pigs@example.com>, other@gmail.com',
@ -795,34 +799,46 @@ class test_mail(TestMailMockups):
def test_60_message_vote(self): def test_60_message_vote(self):
""" Test designed for the vote/unvote feature. """ """ Test designed for the vote/unvote feature. """
cr, uid = self.cr, self.uid cr, uid, user_admin, user_raoul, group_pigs = self.cr, self.uid, self.user_admin, self.user_raoul, self.group_pigs
user_admin = self.res_users.browse(cr, uid, uid) # Data: post a message on Pigs
group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id) msg_id = group_pigs.message_post(body='My Body', subject='1')
msg1 = group_pigs.message_post(body='My Body', subject='1') msg = self.mail_message.browse(cr, uid, msg_id)
msg1 = self.mail_message.browse(cr, uid, msg1)
# Create user Bert Tartopoils # Do: Admin vote for msg
user_bert_id = self.res_users.create(cr, uid, {'name': 'Bert', 'login': 'bert'}) self.mail_message.vote_toggle(cr, uid, [msg.id])
user_bert = self.res_users.browse(cr, uid, user_bert_id) msg.refresh()
# Test: msg has Admin as voter
# Test: msg1 and msg2 have void vote_user_ids self.assertEqual(set(msg.vote_user_ids), set([user_admin]), 'mail_message vote: after voting, Admin should be in the voter')
self.assertFalse(msg1.vote_user_ids, 'newly created message msg1 has not void vote_user_ids') # Do: Bert vote for msg
# Do: Admin vote for msg1 self.mail_message.vote_toggle(cr, user_raoul.id, [msg.id])
self.mail_message.vote_toggle(cr, uid, [msg1.id]) msg.refresh()
msg1.refresh() # Test: msg has Admin and Bert as voters
# Test: msg1 has Admin as voter self.assertEqual(set(msg.vote_user_ids), set([user_admin, user_raoul]), 'mail_message vote: after voting, Admin and Bert should be in the voters')
self.assertEqual(set(msg1.vote_user_ids), set([user_admin]), 'after voting, Admin is not the voter') # Do: Admin unvote for msg
# Do: Bert vote for msg1 self.mail_message.vote_toggle(cr, uid, [msg.id])
self.mail_message.vote_toggle(cr, user_bert_id, [msg1.id]) msg.refresh()
msg1.refresh() # Test: msg has Bert as voter
# Test: msg1 has Admin and Bert as voters self.assertEqual(set(msg.vote_user_ids), set([user_raoul]), 'mail_message vote: after unvoting, Bert should be in the voter')
self.assertEqual(set(msg1.vote_user_ids), set([user_admin, user_bert]), 'after voting, Admin and Bert are not the voters')
# Do: Admin unvote for msg1
self.mail_message.vote_toggle(cr, uid, [msg1.id])
msg1.refresh()
# Test: msg1 has Bert as voter
self.assertEqual(set(msg1.vote_user_ids), set([user_bert]), 'after unvoting for Admin, Bert is not the voter')
def test_70_message_favorite(self): def test_70_message_favorite(self):
""" Tests for favorites. """ """ Tests for favorites. """
self.assertTrue(1 == 1, 'Test not implemented, do not replace by return True') cr, uid, user_admin, user_raoul, group_pigs = self.cr, self.uid, self.user_admin, self.user_raoul, self.group_pigs
# Data: post a message on Pigs
msg_id = group_pigs.message_post(body='My Body', subject='1')
msg = self.mail_message.browse(cr, uid, msg_id)
# Do: Admin stars msg
self.mail_message.favorite_toggle(cr, uid, [msg.id])
msg.refresh()
# Test: msg starred by Admin
self.assertEqual(set(msg.favorite_user_ids), set([user_admin]), 'mail_message favorite: after starring, Admin should be in favorite_user_ids')
# Do: Bert stars msg
self.mail_message.favorite_toggle(cr, user_raoul.id, [msg.id])
msg.refresh()
# Test: msg starred by Admin and Raoul
self.assertEqual(set(msg.favorite_user_ids), set([user_admin, user_raoul]), 'mail_message favorite: after starring, Admin and Raoul should be in favorite_user_ids')
# Do: Admin unvote for msg
self.mail_message.favorite_toggle(cr, uid, [msg.id])
msg.refresh()
# Test: msg starred by Raoul
self.assertEqual(set(msg.favorite_user_ids), set([user_raoul]), 'mail_message favorite: after unstarring, Raoul should be in favorite_user_ids')

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