[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)]}),
'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,
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)
}
_defaults = {
@ -1134,7 +1134,7 @@ class account_journal_period(osv.osv):
'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."),
'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'),
'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)]}),
'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,
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)]}),
'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),

View File

@ -123,8 +123,8 @@ class account_bank_statement(osv.osv):
('open','Open'), # used by cash statements
('confirm', 'Closed')],
'Status', required=True, readonly="1",
help='When new statement is created the state will be \'Draft\'.\n'
'And after getting confirmation from the bank it will be in \'Confirmed\' state.'),
help='When new statement is created the status will be \'Draft\'.\n'
'And after getting confirmation from the bank it will be in \'Confirmed\' status.'),
'currency': fields.function(_currency, string='Currency',
type='many2one', relation='res.currency'),
'account_id': fields.related('journal_id', 'default_debit_account_id', type='many2one', relation='account.account', string='Account used in this journal', readonly=True, help='used in statement reconciliation domain, but shouldn\'t be used elswhere.'),

View File

@ -207,12 +207,12 @@ class account_invoice(osv.osv):
('open','Open'),
('paid','Paid'),
('cancel','Cancelled'),
],'State', select=True, readonly=True,
help=' * The \'Draft\' state 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 \'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 \'Paid\' state 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.'),
],'Status', select=True, readonly=True,
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 status,invoice does not have an invoice number. \
\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\' status is set automatically when the invoice is paid. Its related journal entries may or may not be reconciled. \
\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."),
'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,
@ -1360,7 +1360,7 @@ class account_invoice_line(osv.osv):
_description = "Invoice Line"
_columns = {
'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."),
'invoice_id': fields.many2one('account.invoice', 'Invoice Reference', ondelete='cascade', select=True),
'uos_id': fields.many2one('product.uom', 'Unit of Measure', ondelete='set null'),

View File

@ -1862,7 +1862,7 @@
<field name="model_id"/>
<group expand="0" string="Group By...">
<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>
</search>
</field>
@ -2414,32 +2414,6 @@
<field name="view_mode">form</field>
<field name="target">new</field>
</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">
<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)
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):
if context is None:
context = {}

View File

@ -91,7 +91,7 @@ class account_invoice_report(osv.osv):
('open','Open'),
('paid','Done'),
('cancel','Cancelled')
], 'Invoice State', readonly=True),
], 'Invoice Status', readonly=True),
'date_due': fields.date('Due Date', readonly=True),
'account_id': fields.many2one('account.account', 'Account',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"
"Report-Msgid-Bugs-To: support@openerp.com\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"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-10-19 05:15+0000\n"
"X-Generator: Launchpad (build 16165)\n"
"X-Launchpad-Export-Date: 2012-10-26 04:56+0000\n"
"X-Generator: Launchpad (build 16194)\n"
#. module: account_analytic_plans
#: view:analytic.plan.create.model:0
@ -136,7 +136,7 @@ msgstr "Определить аналитический план счетов"
#. module: account_analytic_plans
#: constraint:account.invoice:0
msgid "Invalid BBA Structured Communication !"
msgstr ""
msgstr "Неверна структурная связь BBA!"
#. module: account_analytic_plans
#: constraint:account.bank.statement:0
@ -149,6 +149,8 @@ msgid ""
"The date of your Journal Entry is not in the defined period! You should "
"change the date or remove this constraint from the journal."
msgstr ""
"Дата проводки в журнале не в определённом периоде! Вы должны сменить дату "
"или удалить это ограничение из журнала."
#. module: account_analytic_plans
#: sql_constraint:account.journal:0
@ -251,6 +253,8 @@ msgid ""
"currency. You should remove the secondary currency on the account or select "
"a multi-currency view on the journal."
msgstr ""
"Выбранный счёт проводки в журнале нуждается во вторичной валюте. Вы должны "
"удалить вторичную валюту по счёту или выбрать мульти-валютный вид по журналу."
#. module: account_analytic_plans
#: report:account.analytic.account.crossovered.analytic:0
@ -429,7 +433,7 @@ msgstr "Счет 4 уровня"
#. module: account_analytic_plans
#: constraint:account.move.line:0
msgid "Company must be the same for its related account and period."
msgstr ""
msgstr "Для счета и периода должна быть одна компания."
#. module: account_analytic_plans
#: 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 "
"your account journals."
msgstr ""
"Для настройки нескольких планов счетов аналитики, вы должны определить "
"корневые счета аналитики для каждого набора плана. Затем вы можете "
"прикрепить набор плана к вашим учётным журналам."
#. module: account_analytic_plans
#: constraint:account.move.line:0
msgid "You can not create journal items on closed account."
msgstr ""
msgstr "Нельзя создать элемент журнала по закрытому счету ."
#. module: account_analytic_plans
#: 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'),
'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,
help="When an asset is created, the state is 'Draft'.\n" \
"If the asset is confirmed, the state 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."),
help="When an asset is created, the status is 'Draft'.\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 status."),
'active': fields.boolean('Active'),
'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"\

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
from osv import osv, fields
import netsvc
_logger = logging.getLogger(__name__)
class payment_mode(osv.osv):
_name= 'payment.mode'
_description= 'Payment Mode'
@ -70,9 +73,7 @@ class payment_order(osv.osv):
#dead code
def get_wizard(self, type):
logger = netsvc.Logger()
logger.notifyChannel("Warning!", netsvc.LOG_WARNING,
"No wizard is found for the payment type '%s'." % type)
_logger.warning("No wizard found for the payment type '%s'.", type)
return None
def _total(self, cursor, user, ids, name, args, context=None):
@ -95,7 +96,7 @@ class payment_order(osv.osv):
('cancel', 'Cancelled'),
('open', 'Confirmed'),
('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)]}),
'total': fields.function(_total, string="Total", type='float'),
'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'),
('posted','Posted')
], 'Status', readonly=True, size=32,
help=' * The \'Draft\' state 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 \'Posted\' state 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.'),
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 status,voucher does not have an voucher number. \
\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\' 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)]}),
'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."),

View File

@ -52,7 +52,7 @@ class sale_receipt_report(osv.osv):
('proforma','Pro-forma'),
('posted','Posted'),
('cancel','Cancelled')
], 'Voucher State', readonly=True),
], 'Voucher Status', readonly=True),
'pay_now':fields.selection([
('pay_now','Pay Directly'),
('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="%(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" 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"/>
<field name="state" widget="statusbar" statusbar_visible="draft,posted" statusbar_colors='{"proforma":"blue"}'/>
</header>
@ -209,7 +209,7 @@
<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="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"/>
<field name="state" widget="statusbar" statusbar_visible="draft,posted" statusbar_colors='{"proforma":"blue"}'/>
</header>

View File

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

View File

@ -8,14 +8,14 @@ msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-02-08 00:36+0000\n"
"PO-Revision-Date: 2012-05-10 17:50+0000\n"
"Last-Translator: Wei \"oldrev\" Li <oldrev@gmail.com>\n"
"PO-Revision-Date: 2012-10-25 16:32+0000\n"
"Last-Translator: ccdos <Unknown>\n"
"Language-Team: Chinese (Simplified) <zh_CN@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-19 05:35+0000\n"
"X-Generator: Launchpad (build 16165)\n"
"X-Launchpad-Export-Date: 2012-10-26 04:56+0000\n"
"X-Generator: Launchpad (build 16194)\n"
#. module: base_action_rule
#: help:base.action.rule,act_mail_to_user:0
@ -315,7 +315,7 @@ msgstr "激活"
#: code:addons/base_action_rule/base_action_rule.py:329
#, python-format
msgid "No Email ID Found for your Company address!"
msgstr ""
msgstr "公司地址中没有设置Email !"
#. module: base_action_rule
#: 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, \
fnct_inv=_rrule_write, store=True, string='Recurrent Rule'),
'rrule_type': fields.selection([
('daily', 'Daily'),
('weekly', 'Weekly'),
('monthly', 'Monthly'),
('yearly', 'Yearly')
('daily', 'Day(s)'),
('weekly', 'Week(s)'),
('monthly', 'Month(s)'),
('yearly', 'Year(s)')
], 'Recurrency', states={'done': [('readonly', True)]},
help="Let the event automatically repeat at that interval"),
'alarm_id': fields.many2one('res.alarm', 'Reminder', states={'done': [('readonly', True)]},

View File

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

View File

@ -156,5 +156,11 @@
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"/>
<div>
<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"/>
</div>
</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."),
'state': fields.selection(AVAILABLE_STATES, 'Related Status', required=True,
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',
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',

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', \
multi='day_close', type="float", store=True),
'state': fields.related('stage_id', 'state', type="selection", store=True,
selection=crm.AVAILABLE_STATES, string="State", readonly=True,
help='The state is set to \'Draft\', when a case is created.\
If the case is in progress the state is set to \'Open\'.\
When the case is over, the state is set to \'Done\'.\
If the case needs to be reviewed then the state is \
selection=crm.AVAILABLE_STATES, string="Status", readonly=True,
help='The Status is set to \'Draft\', when a case is created.\
If the case is in progress the Status is set to \'Open\'.\
When the case is over, the Status is set to \'Done\'.\
If the case needs to be reviewed then the Status is \
set to \'Pending\'.'),
# Only used for type opportunity

View File

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

View File

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

View File

@ -7,14 +7,14 @@ msgstr ""
"Project-Id-Version: OpenERP Server 6.0dev\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-02-08 01:37+0100\n"
"PO-Revision-Date: 2012-03-22 16:17+0000\n"
"Last-Translator: Wei \"oldrev\" Li <oldrev@gmail.com>\n"
"PO-Revision-Date: 2012-10-25 16:22+0000\n"
"Last-Translator: fenshuajiang <openerp@126.com>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-08-28 06:06+0000\n"
"X-Generator: Launchpad (build 15864)\n"
"X-Launchpad-Export-Date: 2012-10-26 04:56+0000\n"
"X-Generator: Launchpad (build 16194)\n"
#. module: crm
#: view:crm.lead.report:0
@ -172,7 +172,7 @@ msgstr "预计结束月份"
#. module: crm
#: view:crm.lead2opportunity.partner.mass:0
msgid "Assigned Opportunities to"
msgstr ""
msgstr "分配商机给"
#. module: crm
#: view:crm.lead:0 field:crm.lead,partner_id:0 view:crm.lead.report:0
@ -583,7 +583,7 @@ msgstr "结束日期"
#. module: crm
#: view:crm.opportunity2phonecall:0 view:crm.phonecall2phonecall:0
msgid "Schedule/Log a Call"
msgstr ""
msgstr "计划/记录一个电话"
#. module: crm
#: constraint:base.action.rule:0
@ -763,7 +763,7 @@ msgstr "继续"
#. module: crm
#: field:crm.segmentation,som_interval:0
msgid "Days per Period"
msgstr ""
msgstr "每阶段的天数"
#. module: crm
#: field:crm.meeting,byday:0
@ -926,7 +926,7 @@ msgstr "开启天数"
#. module: crm
#: view:crm.meeting:0
msgid "Show Time as"
msgstr ""
msgstr "显示时间为"
#. module: crm
#: view:crm.phonecall2partner:0
@ -1299,7 +1299,7 @@ msgstr "写日期"
#. module: crm
#: view:crm.meeting:0
msgid "End of Recurrency"
msgstr ""
msgstr "结束循环"
#. module: crm
#: view:crm.meeting:0
@ -1835,7 +1835,7 @@ msgstr "回复到"
#. module: crm
#: view:crm.case.section:0
msgid "Select Stages for this Sales Team"
msgstr ""
msgstr "为这个销售团队选择阶段"
#. module: crm
#: view:board.board:0
@ -2683,7 +2683,7 @@ msgstr "这联系的邮件地址"
#. module: crm
#: field:crm.lead,referred:0
msgid "Referred by"
msgstr ""
msgstr "推荐人"
#. module: crm
#: 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."),
'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."),
'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',
help='Refused stages are specific stages for done.'),
'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)]"),
'cause': fields.text('Root Cause'),
'state': fields.related('stage_id', 'state', type="selection", store=True,
selection=crm.AVAILABLE_STATES, string="State", readonly=True,
help='The state is set to \'Draft\', when a case is created.\
If the case is in progress the state is set to \'Open\'.\
When the case is over, the state is set to \'Done\'.\
If the case needs to be reviewed then the state is \
selection=crm.AVAILABLE_STATES, string="Status", readonly=True,
help='The status is set to \'Draft\', when a case is created.\
If the case is in progress the status is set to \'Open\'.\
When the case is over, the status is set to \'Done\'.\
If the case needs to be reviewed then the status is \
set to \'Pending\'.'),
}

View File

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

View File

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

View File

@ -8,14 +8,14 @@ msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-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"
"Language-Team: Russian <ru@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-19 05:34+0000\n"
"X-Generator: Launchpad (build 16165)\n"
"X-Launchpad-Export-Date: 2012-10-25 05:35+0000\n"
"X-Generator: Launchpad (build 16179)\n"
#. module: crm_helpdesk
#: field:crm.helpdesk.report,delay_close:0
@ -46,7 +46,7 @@ msgstr "Март"
#. module: crm_helpdesk
#: view:crm.helpdesk.report:0
msgid "Helpdesk requests occurred in current year"
msgstr ""
msgstr "Запросы на техподдержку в текущем году"
#. module: crm_helpdesk
#: field:crm.helpdesk,company_id:0
@ -80,7 +80,7 @@ msgstr "Добавить внутреннею заметку"
#. module: crm_helpdesk
#: view:crm.helpdesk.report:0
msgid "Date of helpdesk requests"
msgstr ""
msgstr "Дата запросов техподдержки"
#. module: crm_helpdesk
#: view:crm.helpdesk:0
@ -95,7 +95,7 @@ msgstr "Сообщения"
#. module: crm_helpdesk
#: view:crm.helpdesk.report:0
msgid "My company"
msgstr ""
msgstr "Моя компания"
#. module: crm_helpdesk
#: selection:crm.helpdesk,state:0
@ -156,7 +156,7 @@ msgstr "Раздел"
#. module: crm_helpdesk
#: view:crm.helpdesk.report:0
msgid "Helpdesk requests occurred in last month"
msgstr ""
msgstr "последний месяц"
#. module: crm_helpdesk
#: view:crm.helpdesk:0
@ -166,14 +166,14 @@ msgstr "Отправить новое эл. письмо"
#. module: crm_helpdesk
#: view:crm.helpdesk:0
msgid "Helpdesk requests during last 7 days"
msgstr ""
msgstr "Запросы на техподдержку за последние 7 дней"
#. module: crm_helpdesk
#: view:crm.helpdesk:0
#: selection:crm.helpdesk,state:0
#: view:crm.helpdesk.report:0
msgid "New"
msgstr ""
msgstr "Новый"
#. module: crm_helpdesk
#: model:ir.model,name:crm_helpdesk.model_crm_helpdesk_report
@ -207,7 +207,7 @@ msgstr "# Писем"
#: view:crm.helpdesk:0
#: view:crm.helpdesk.report:0
msgid "My Sales Team(s)"
msgstr ""
msgstr "Мои отделы продаж"
#. module: crm_helpdesk
#: field:crm.helpdesk,create_date:0
@ -252,7 +252,7 @@ msgstr "Категории"
#. module: crm_helpdesk
#: view:crm.helpdesk:0
msgid "New Helpdesk Request"
msgstr ""
msgstr "Новый запрос техподдержки"
#. module: crm_helpdesk
#: view:crm.helpdesk:0
@ -267,13 +267,13 @@ msgstr "Даты"
#. module: crm_helpdesk
#: view:crm.helpdesk.report:0
msgid "Month of helpdesk requests"
msgstr ""
msgstr "Месяц запросов техподдержки"
#. module: crm_helpdesk
#: code:addons/crm_helpdesk/crm_helpdesk.py:101
#, python-format
msgid "No Subject"
msgstr ""
msgstr "Без темы"
#. module: crm_helpdesk
#: view:crm.helpdesk.report:0
@ -283,12 +283,12 @@ msgstr "№ техподдержки"
#. module: crm_helpdesk
#: view:crm.helpdesk:0
msgid "All pending Helpdesk Request"
msgstr ""
msgstr "Все ожидающие запросы техподдержки"
#. module: crm_helpdesk
#: view:crm.helpdesk.report:0
msgid "Year of helpdesk requests"
msgstr ""
msgstr "Год запросов техподдержки"
#. module: crm_helpdesk
#: view:crm.helpdesk:0
@ -324,7 +324,7 @@ msgstr "Дата изменения"
#. module: crm_helpdesk
#: view:crm.helpdesk.report:0
msgid "Helpdesk requests occurred in current month"
msgstr ""
msgstr "Запросы техподдержки в текущем месяце"
#. module: crm_helpdesk
#: view:crm.helpdesk.report:0
@ -345,7 +345,7 @@ msgstr "Категория"
#. module: crm_helpdesk
#: view:crm.helpdesk:0
msgid "Responsible User"
msgstr ""
msgstr "Ответственный пользователь"
#. module: crm_helpdesk
#: view:crm.helpdesk:0
@ -361,7 +361,7 @@ msgstr "Планируемые затраты"
#. module: crm_helpdesk
#: help:crm.helpdesk,channel_id:0
msgid "Communication channel."
msgstr ""
msgstr "Канал общения"
#. module: crm_helpdesk
#: help:crm.helpdesk,email_cc:0
@ -575,7 +575,7 @@ msgstr "Дерево поддержи"
#. module: crm_helpdesk
#: selection:crm.helpdesk,state:0
msgid "In Progress"
msgstr ""
msgstr "В работе"
#. module: crm_helpdesk
#: view:crm.helpdesk:0
@ -660,7 +660,7 @@ msgstr "Название"
#. module: crm_helpdesk
#: view:crm.helpdesk.report:0
msgid "Month-1"
msgstr ""
msgstr "Месяц-1"
#. module: crm_helpdesk
#: model:ir.ui.menu,name:crm_helpdesk.menu_help_support_main
@ -699,17 +699,17 @@ msgstr ""
#. module: crm_helpdesk
#: view:crm.helpdesk:0
msgid "Todays's Helpdesk Requests"
msgstr ""
msgstr "Запросы техподдержки за сегодня"
#. module: crm_helpdesk
#: view:crm.helpdesk:0
msgid "Request Date"
msgstr ""
msgstr "Дата запроса"
#. module: crm_helpdesk
#: view:crm.helpdesk:0
msgid "Open Helpdesk Request"
msgstr ""
msgstr "Открыть запрос техподдержки"
#. module: crm_helpdesk
#: 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.)"),
'opportunity_assigned_ids': fields.one2many('crm.lead', 'partner_assigned_id',\
'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),
'date_partnership' : fields.date('Partnership Date'),
'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)
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)
return False

View File

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

View File

@ -29,7 +29,7 @@ _logger = logging.getLogger(__name__)
try:
import controllers
except ImportError:
_logger.warn(
_logger.warning(
"""Could not load openerp-web section of EDI, EDI will not behave correctly
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_bird.body, _body_html2, 'mail.message body on Bird incorrect')
# Test: partner_ids: p_a_id (default) + 3 newly created partners
message_pigs_pids = [partner.id for partner in message_pigs.partner_ids]
message_bird_pids = [partner.id for partner in message_bird.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.notified_partner_ids]
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 partner_ids')
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')
self.assertEqual(set(message_pigs_pids), set(partner_ids), 'mail.message on pigs incorrect number of notified_partner_ids')
self.assertEqual(set(message_bird_pids), set(partner_ids), 'mail.message on bird notified_partner_ids incorrect')

View File

@ -201,7 +201,7 @@ class event_event(osv.osv):
('confirm', 'Confirmed'),
('done', 'Done')],
'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_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."),
@ -330,7 +330,7 @@ class event_registration(osv.osv):
_inherit = ['ir.needaction_mixin','mail.thread']
_columns = {
'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)]}),
'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)]}),

View File

@ -15,7 +15,7 @@
id="event_main_menu"
groups="base.group_user"
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 -->
@ -219,7 +219,7 @@
<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'">
<field name="name" string="Name"/>
<field name="type"/>
<field name="type" string="Event Category"/>
<field name="date_begin"/>
<field name="date_end"/>
<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.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 == 0"><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>No ticket available.</i></t>
<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>
<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.
</i>
</t>
</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">
<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">

View File

@ -8,7 +8,7 @@
<form string="Configure Moodle" version="7.0">
<header>
<button type="object" name="configure_moodle"
string="Configure Moodle" class="oe_highlight" />
string="Apply" class="oe_highlight" />
or
<button string="Cancel" class="oe_link" special="cancel" />
</header>
@ -16,12 +16,12 @@
<separator string="Server" colspan="4"/>
<field name="server_moodle"/>
<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"/>
<field name="moodle_token"/>
<newline/>
<separator string="Connexion with Password and Username" 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"/>
<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 appropriate access rights." colspan="4"/>
<field name="moodle_username"/>
<field name="moodle_password"/>
</group>

View File

@ -112,7 +112,7 @@ class hr_job(osv.osv):
'requirements': fields.text('Requirements'),
'department_id': fields.many2one('hr.department', 'Department'),
'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."),
}
_defaults = {

View File

@ -330,8 +330,8 @@
<field name="arch" type="xml">
<form string="Job" version="7.0">
<header>
<button name="job_recruitement" string="In 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_recruitement" string="Launch Recruitement" states="open" 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"/>
</header>
<sheet>

View File

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

View File

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

View File

@ -64,15 +64,15 @@ class hr_expense_expense(osv.osv):
_description = "Expense"
_order = "id desc"
_columns = {
'name': fields.char('Description', size=128, required=True),
'name': fields.char('Description', size=128),
'id': fields.integer('Sheet ID', readonly=True),
'date': fields.date('Date', select=True),
'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),
'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_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'),
'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."),
'user_valid': fields.many2one('res.users', 'Validation By'),
'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)]} ),
'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.'))
acc = exp.employee_id.address_home_id.property_account_payable.id
voucher = {
'name': exp.name,
'name': exp.name or '/',
'reference': sequence_obj.get(cr, uid, 'hr.expense.invoice'),
'account_id': acc,
'type': 'purchase',
@ -233,7 +233,7 @@ hr_expense_expense()
class product_product(osv.osv):
_inherit = "product.product"
_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):

View File

@ -79,7 +79,7 @@
</group>
<group>
<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)"/>
</group>
</group>
@ -128,9 +128,9 @@
</group>
</group>
</page>
<page string="Other Info">
<page string="Accounting" groups="account.group_account_user">
<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="voucher_id" context="{'form_view_ref': 'account_voucher.view_purchase_receipt_form'}"/>
</group>

View File

@ -115,10 +115,10 @@ class hr_holidays(osv.osv):
_columns = {
'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', readonly=True, help='The state is set to \'To Submit\', when a holiday request is created.\
\nThe state is \'To Approve\', when holiday request is confirmed by user.\
\nThe state is \'Refused\', when holiday request is refused by manager.\
\nThe state is \'Approved\', when holiday request is approved by manager.'),
'Status', readonly=True, help='The status is set to \'To Submit\', when a holiday request is created.\
\nThe status is \'To Approve\', when holiday request is confirmed by user.\
\nThe status is \'Refused\', when holiday request is refused 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),
'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)]}),

View File

@ -272,10 +272,10 @@ class hr_payslip(osv.osv):
('done', 'Done'),
('cancel', 'Rejected'),
], 'Status', select=True, readonly=True,
help='* When the payslip is created the state is \'Draft\'.\
\n* If the payslip is under verification, the state is \'Waiting\'. \
\n* If the payslip is confirmed then state is set to \'Done\'.\
\n* When user cancel payslip the state is \'Rejected\'.'),
help='* When the payslip is created the status is \'Draft\'.\
\n* If the payslip is under verification, the status is \'Waiting\'. \
\n* If the payslip is confirmed then status is set to \'Done\'.\
\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': 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)]}),

View File

@ -62,7 +62,7 @@ class hr_recruitment_stage(osv.osv):
'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."),
'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."),
'requirements': fields.text('Requirements'),
}
@ -189,11 +189,11 @@ class hr_applicant(base_stage, osv.Model):
'stage_id': fields.many2one ('hr.recruitment.stage', 'Stage',
domain="['&', ('fold', '=', False), '|', ('department_id', '=', department_id), ('department_id', '=', False)]"),
'state': fields.related('stage_id', 'state', type="selection", store=True,
selection=AVAILABLE_STATES, string="State", readonly=True,
help='The state is set to \'Draft\', when a case is created.\
If the case is in progress the state is set to \'Open\'.\
When the case is over, the state is set to \'Done\'.\
If the case needs to be reviewed then the state is \
selection=AVAILABLE_STATES, string="Status", readonly=True,
help='The status is set to \'Draft\', when a case is created.\
If the case is in progress the status is set to \'Open\'.\
When the case is over, the status is set to \'Done\'.\
If the case needs to be reviewed then the status is \
set to \'Pending\'.'),
'categ_ids': fields.many2many('hr.applicant_category', string='Tags'),
'company_id': fields.many2one('res.company', 'Company'),

View File

@ -107,7 +107,7 @@
<form string="Jobs - Recruitment Form" version="7.0">
<header>
<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"
states="draft,open,pending" class="oe_highlight"/>
<field name="stage_id" widget="statusbar" clickable="True"/>

View File

@ -41,7 +41,7 @@ class hr_recruitment_report(osv.osv):
_columns = {
'user_id': fields.many2one('res.users', 'User', 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'), \
('03', 'March'), ('04', 'April'),\
('05', 'May'), ('06', 'June'), \

View File

@ -7,14 +7,14 @@ msgstr ""
"Project-Id-Version: OpenERP Server 6.0dev\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-02-08 00:36+0000\n"
"PO-Revision-Date: 2012-05-10 18:19+0000\n"
"Last-Translator: Jeff Wang <wjfonhand@hotmail.com>\n"
"PO-Revision-Date: 2012-10-25 17:20+0000\n"
"Last-Translator: ccdos <Unknown>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-10-19 05:15+0000\n"
"X-Generator: Launchpad (build 16165)\n"
"X-Launchpad-Export-Date: 2012-10-26 04:56+0000\n"
"X-Generator: Launchpad (build 16194)\n"
#. module: hr_timesheet
#: code:addons/hr_timesheet/report/user_timesheet.py:43
@ -468,7 +468,7 @@ msgstr "一般信息"
#. module: hr_timesheet
#: model:ir.actions.act_window,name:hr_timesheet.action_hr_timesheet_my
msgid "My Current Timesheet"
msgstr ""
msgstr "我当前的时间表"
#. module: hr_timesheet
#: 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'),
'analytic_amount': fields.float('Minimum Analytic Amount'),
'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),
'emp_id': fields.many2one('hr.employee', 'Employee ID')
}
@ -111,7 +111,7 @@ class hr_si_project(osv.osv_memory):
_description = 'Sign In By Project'
_columns = {
'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'),
'server_date': fields.datetime('Current Date', readonly=True),
'emp_id': fields.many2one('hr.employee', 'Employee ID')

View File

@ -206,9 +206,9 @@ class hr_timesheet_sheet(osv.osv):
('draft','Open'),
('confirm','Waiting Approval'),
('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. \
\n* The \'Confirmed\' state is used for to confirm the timesheet by user. \
\n* The \'Done\' state is used when users timesheet is accepted by his/her senior.'),
help=' * The \'Draft\' status is used when a user is encoding a new and unconfirmed timesheet. \
\n* The \'Confirmed\' status is used for to confirm the timesheet by user. \
\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),
'total_attendance': fields.function(_total, method=True, string='Total Attendance', multi="_total"),
'total_timesheet': fields.function(_total, method=True, string='Total Timesheet', multi="_total"),

View File

@ -54,18 +54,18 @@
</header>
<sheet>
<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>
<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="department_id"/>
<field name="department_id" invisible="1"/>
<field name="company_id" groups="base.group_multi_company"/>
</group>
<group>
<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="user_id" invisible="1"/>
</group>
@ -76,8 +76,8 @@
</widget>
</page>
<page string="Daily">
<group colspan="4" col="3">
<field context="{'user_id':user_id}" name="attendances_ids" nolabel="1" groups="base.group_hr_attendance">
<group groups="base.group_hr_attendance">
<field context="{'user_id':user_id}" name="attendances_ids" nolabel="1">
<tree string="Attendances" editable="bottom">
<field name="name"/>
<field name="action"/>
@ -85,21 +85,19 @@
</tree>
</field>
<group>
<div align="right" groups="base.group_hr_manager,base.group_hr_attendance">
<button name="attendance_action_change" attrs="{'invisible': [('state_attendance', '=', 'present')]}" type="object" string="Sign In" groups="base.group_hr_attendance"/>
<button name="attendance_action_change" attrs="{'invisible': ['|', ('state_attendance','=',False), ('state_attendance', '=', 'absent')]}" type="object" string="Sign Out" groups="base.group_hr_attendance"/>
<field name="state_attendance" nolabel="1"/>
<div align="right" groups="base.group_hr_manager">
<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>
</group>
</group>
<group col="4">
<field name="state_attendance" groups="base.group_hr_attendance"/>
</group>
<field colspan="4" context="{'user_id':user_id}" name="timesheet_ids" nolabel="1">
<field context="{'user_id':user_id}" name="timesheet_ids" nolabel="1">
<tree editable="top" string="Timesheet Lines">
<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 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 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)"/>
@ -123,13 +121,13 @@
</form>
</field>
</page>
<page string="Summary">
<field colspan="4" name="period_ids" nolabel="1">
<page string="Summary" groups="base.group_hr_attendance">
<field name="period_ids">
<tree colors="red:total_difference&lt;0.1;blue:total_difference&gt;=0.1" string="Period">
<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_difference" widget="float_time" groups="base.group_hr_attendance"/>
<field name="total_difference" widget="float_time"/>
</tree>
</field>
</page>

View File

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

View File

@ -2,13 +2,9 @@
<openerp>
<data>
<record id="config_call_account_template_ar" model="ir.actions.todo">
<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 id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>
</data>
</openerp>

View File

@ -1,12 +1,8 @@
<openerp>
<data>
<record id="config_call_account_template_at" model="ir.actions.todo">
<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 id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>
</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}: |
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':
wiz = self.pool.get('wizard.multi.charts.accounts')
values = {

View File

@ -1,13 +1,9 @@
<openerp>
<data>
<record id="config_call_account_template_ca" model="ir.actions.todo">
<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 id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>
</data>
</openerp>

View File

@ -1,13 +1,7 @@
<openerp>
<data>
<record id="config_call_account_template_l10n_ch" model="ir.actions.todo">
<field name="name">Generate Chart of Accounts for l10n_ch</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 id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>
</data>
</openerp>

View File

@ -1,14 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="config_call_account_template_cl" model="ir.actions.todo">
<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 id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>
</data>
</openerp>

View File

@ -1,12 +1,7 @@
<openerp>
<data>
<record id="config_call_account_template_cn_chart" model="ir.actions.todo">
<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 id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>
</data>

View File

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

View File

@ -1,12 +1,9 @@
<openerp>
<data>
<record id="config_call_account_template_de" model="ir.actions.todo">
<field name="name">Generiert Kontenplan aus Vorlage</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>
<field name="action_id" ref="account.action_wizard_multi_chart"/>
<field name="type">automatic</field>
</record>
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>
</data>
</openerp>

View File

@ -1,13 +1,8 @@
<openerp>
<data>
<record id="config_call_account_template_ec" model="ir.actions.todo">
<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 id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>
</data>
</openerp>

View File

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

View File

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

View File

@ -1,12 +1,7 @@
<openerp>
<data>
<record id="config_call_account_template_gr" model="ir.actions.todo">
<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 id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>
</data>

View File

@ -1,14 +1,8 @@
<openerp>
<data noupdate="1">
<record id="config_call_account_template_gt_minimal" 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="type">automatic</field>
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>
<!-- Moneda Quetzal -->

View File

@ -2,13 +2,7 @@
<openerp>
<data noupdate="1">
<record id="config_call_account_template_hn_minimal" 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"/>
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>

View File

@ -1,13 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="config_call_account_template_in_minimal" model="ir.actions.todo">
<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 id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>
</data>

View File

@ -65,7 +65,7 @@ class payroll_advice(osv.osv):
('draft', 'Draft'),
('confirm', 'Confirmed'),
('cancel', 'Cancelled'),
], 'State', select=True, readonly=True),
], 'Status', select=True, 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),
'chaque_nos':fields.char('Cheque Numbers', size=256),

View File

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

View File

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

View File

@ -1,12 +1,7 @@
<openerp>
<data>
<record id="config_call_account_template_generic" model="ir.actions.todo">
<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 id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>
</data>
</openerp>

View File

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

View File

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

View File

@ -14,7 +14,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\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"
#. module: l10n_mx

View File

@ -1,12 +1,7 @@
<openerp>
<data>
<record id="config_call_account_template_mx_chart" model="ir.actions.todo">
<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 id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>
</data>

View File

@ -1,19 +1,8 @@
<openerp>
<data>
<record id="config_call_account_template" model="ir.actions.todo">
<field name="name">Genereer Grootboekrekingschema vanuit het Nederlandse Grootboek Template</field>
<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>
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>
</data>
</openerp>

View File

@ -2,12 +2,8 @@
<openerp>
<data>
<record id="config_call_account_template_pe" model="ir.actions.todo">
<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 id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>
</data>

View File

@ -1,12 +1,7 @@
<openerp>
<data>
<record id="config_call_account_template_pl_chart" model="ir.actions.todo">
<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 id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>
</data>

View File

@ -1,12 +1,7 @@
<openerp>
<data>
<record id="config_call_account_template_ro" model="ir.actions.todo">
<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 id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>
</data>

View File

@ -1,11 +1,7 @@
<openerp>
<data>
<record id="config_call_account_template_syscohada" model="ir.actions.todo">
<field name="name">Generate Chart of Accounts from a Chart Template</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.
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 id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>
</data>
</openerp>

View File

@ -643,14 +643,9 @@
</record>
<!-- INSTALL ACTION -->
<record id="config_call_account_template_th" model="ir.actions.todo">
<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 id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>
</data>
</openerp><!-- vim: set fdm=marker : -->

View File

@ -1,16 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record id="config_call_account_template_tr_chart" model="ir.actions.todo">
<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 id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>
</data>
</openerp>

View File

@ -1,41 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<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>
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>

View File

@ -1,12 +1,7 @@
<openerp>
<data>
<record id="config_call_account_template" model="ir.actions.todo">
<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 id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>
</data>

View File

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

View File

@ -1,15 +1,7 @@
<openerp>
<data>
<record id="config_call_account_template_ve_chart" model="ir.actions.todo">
<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 id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>
</data>

View File

@ -8,6 +8,7 @@
<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>
<field name="type">comment</field>
<field name="subtype_id" ref="mt_comment"/>
</record>
<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="parent_id" ref="message_blogpost0"/>
<field name="type">comment</field>
<field name="subtype_id" ref="mt_comment"/>
</record>
<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="parent_id" ref="message_blogpost0"/>
<field name="type">comment</field>
<field name="subtype_id" ref="mt_comment"/>
</record>
<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="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="parent_id" ref="message_blogpost0"/>
<field name="type">comment</field>
</record>
<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>
<field name="subtype_id" ref="mt_comment"/>
</record>
</data>

View File

@ -131,7 +131,8 @@ class mail_notification(osv.Model):
def _notify(self, cr, uid, msg_id, context=None):
""" 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
if context.get('mail_noemail'):
return True
@ -141,9 +142,15 @@ class mail_notification(osv.Model):
if not notify_partner_ids:
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')
# add signature
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 ''
if 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 openerp import SUPERUSER_ID
from osv import osv, orm, fields
from tools.translate import _
from openerp.osv import osv, orm, fields
from openerp.tools.translate import _
_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 """
def decode(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']
_order = 'id desc'
_message_read_limit = 15
_message_read_fields = ['id', 'parent_id', 'model', 'res_id', 'body', 'subject', 'date', 'to_read',
_message_read_limit = 10
_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']
_message_record_name_length = 18
_message_read_more_limit = 1024
@ -57,17 +63,13 @@ class mail_message(osv.Model):
return name[:self._message_record_name_length] + '...'
def _get_record_name(self, cr, uid, ids, name, arg, context=None):
""" Return the related document name, using name_get. It is included in
a try/except statement, because if uid cannot read the related
document, he should see a void string instead of crashing. """
""" Return the related document name, using name_get. It is done using
SUPERUSER_ID, to be sure to have the record name correctly stored. """
result = dict.fromkeys(ids, False)
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
try:
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
result[message['id']] = self._shorten_name(self.pool.get(message['model']).name_get(cr, SUPERUSER_ID, [message['res_id']], context=context)[0][1])
return result
def _get_to_read(self, cr, uid, ids, name, arg, context=None):
@ -114,16 +116,21 @@ class mail_message(osv.Model):
], 'Type',
help="Message type: email for email message, notification for system "\
"message, comment for other messages such as user replies"),
'author_id': fields.many2one('res.partner', 'Author', required=True),
'partner_ids': fields.many2many('res.partner', 'mail_notification', 'message_id', 'partner_id', 'Recipients'),
'email_from': fields.char('From',
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',
'message_id', 'attachment_id', 'Attachments'),
'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'),
'model': fields.char('Related Document Model', size=128, select=1),
'res_id': fields.integer('Related Document ID', select=1),
'record_name': fields.function(_get_record_name, type='string',
string='Message Record Name',
'record_name': fields.function(_get_record_name, type='char',
store=True, string='Message Record Name',
help="Name get of the related document."),
'notification_ids': fields.one2many('mail.notification', 'message_id', 'Notifications'),
'subject': fields.char('Subject'),
@ -200,6 +207,9 @@ class mail_message(osv.Model):
is_author = False
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]
author_id = message['author_id']
elif message['email_from']:
author_id = (0, message['email_from'])
has_voted = False
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'):
is_favorite = True
is_private = False
is_private = True
if message.get('model') and message.get('res_id'):
is_private = True
is_private = False
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)]
@ -235,11 +245,10 @@ class mail_message(osv.Model):
'record_name': message['record_name'],
'subject': message['subject'],
'date': message['date'],
'author_id': message['author_id'],
'author_id': author_id,
'is_author': is_author,
# TDE note: is this useful ? to check
'partner_ids': partner_ids,
'ancestor_id': False,
'parent_id': False,
'vote_nb': len(message['vote_user_ids']),
'has_voted': has_voted,
'is_private': is_private,
@ -269,12 +278,12 @@ class mail_message(osv.Model):
easily have access to their values, given their ID
:return bool: True
"""
def _get_expandable(domain, message_nb, ancestor_id, id, model):
def _get_expandable(domain, message_nb, parent_id, id, model):
return {
'domain': domain,
'nb_messages': message_nb,
'type': 'expandable',
'ancestor_id': ancestor_id,
'parent_id': parent_id,
'id': id,
# TDE note: why do we need model sometimes, and sometimes not ???
'model': model,
@ -282,6 +291,8 @@ class mail_message(osv.Model):
# all_not_loaded_ids = []
id_list = sorted(read_messages.keys())
if not id_list:
return message_list
# 1. get the expandable for new threads
if thread_level == 0:
@ -351,7 +362,7 @@ class mail_message(osv.Model):
except (orm.except_orm, osv.except_osv):
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
messages to be displayed as discussion threads. If IDs is set,
fetch these records. Otherwise use the domain to fetch messages.
@ -375,6 +386,13 @@ class mail_message(osv.Model):
ancestors and expandables
: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
domain = domain if domain 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 = {}
message_list = []
# specific IDs given: fetch those ids and return directly the message list
if ids:
for message in self.read(cr, uid, ids, self._message_read_fields, context=context):
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)
# no specific IDS given: fetch messages according to the domain, add their parents if uid has access to
if ids is None:
ids = self.search(cr, uid, domain, context=context, limit=limit)
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 read_messages.get(message.get('id')) and message.get('id') not in message_unload_ids:
read_messages[message.get('id')] = message
if not message_id in read_messages and not message_id in message_unload_ids:
read_messages[message_id] = message
message_list.append(self._message_get_dict(cr, uid, message, context=context))
# get the older ancestor the user can read, update its ancestor field
if not thread_level:
message_list[-1]['ancestor_id'] = parent_id
message_list[-1]['parent_id'] = parent_id
continue
parent = self._get_parent(cr, uid, message, context=context)
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
parent = self._get_parent(cr, uid, message, context=context)
# 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:
read_messages[message.get('id')] = message
if not message['id'] in read_messages and not message['id'] in message_unload_ids:
read_messages[message['id']] = message
message_list.append(self._message_get_dict(cr, uid, message, context=context))
# 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,
message_loaded_ids=message_unload_ids, domain=domain, parent_id=parent_id, context=context, limit=limit)
print message_list
return message_list
# TDE Note: do we need this ?
@ -431,7 +446,7 @@ class mail_message(osv.Model):
# return attachment_list
#------------------------------------------------------
# Email api
# mail_message internals
#------------------------------------------------------
def init(self, cr):
@ -439,23 +454,74 @@ class mail_message(osv.Model):
if not cr.fetchone():
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):
""" Access rules of mail.message:
- read: if
- notification exist (I receive pushed message) OR
- author_id = pid (I am the author) OR
- I can read the related document if res_model, res_id
- Otherwise: raise
- author_id == pid, uid is the author, OR
- mail_notification (id, pid) exists, uid has been notified, OR
- uid have read access to the related document if model, res_id
- otherwise: raise
- create: if
- I am in the document message_follower_ids OR
- I can write on the related document if res_model, res_id OR
- I create a private message (no model, no res_id)
- Otherwise: raise
- no model, no res_id, I create a private message
- pid in message_follower_ids if model, res_id OR
- uid have write access on the related document if model, res_id, OR
- otherwise: raise
- 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
- 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
"""
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]
# Read mail_message.ids to have their values
model_record_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,))
for id, rmod, rid, author_id in cr.fetchall():
message_values[id] = {'res_model': rmod, 'res_id': rid, 'author_id': author_id}
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':
not_obj = self.pool.get('mail.notification')
not_ids = not_obj.search(cr, SUPERUSER_ID, [
@ -481,38 +557,24 @@ class mail_message(osv.Model):
('message_id', 'in', 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':
author_ids = [mid for mid, message in message_values.iteritems()
if not message.get('model') and not message.get('res_id')]
else:
author_ids = []
# Create: Check message_follower_ids
if operation == 'create':
doc_follower_ids = []
for model, mids in model_record_ids.items():
notified_ids = []
for doc_model, doc_dict in model_record_ids.items():
fol_obj = self.pool.get('mail.followers')
fol_ids = fol_obj.search(cr, SUPERUSER_ID, [
('res_model', '=', model),
('res_id', 'in', list(mids)),
('res_model', '=', doc_model),
('res_id', 'in', list(doc_dict.keys())),
('partner_id', '=', partner_id),
], 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()
if message.get('res_model') == model and message.get('res_id') in fol_mids]
notified_ids += [mid for mid, message in message_values.iteritems()
if message.get('res_model') == doc_model and message.get('res_id') in fol_mids]
else:
doc_follower_ids = []
notified_ids = []
# Calculate remaining ids, and related model/res_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:
if message_values[id]['res_model']:
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]
# 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:
return
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)
return super(mail_message, self).unlink(cr, uid, ids, context=context)
def _notify_followers(self, cr, uid, newid, message, context=None):
""" Add the related record followers to the destination partner_ids.
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)
#------------------------------------------------------
# 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([])
# message has no subtype_id: pure log message -> no partners, no one notified
if not message.subtype_id:
message.write({'partner_ids': [5]})
return True
# all partner_ids of the mail.message have to be notified
if message.partner_ids:
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
if message.model and message.res_id:
fol_obj = self.pool.get("mail.followers")
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)
fol_objs = fol_obj.browse(cr, uid, fol_ids, context=context)
extra_notified = set(fol.partner_id.id for fol in fol_objs)
missing_notified = extra_notified - partners_to_notify
if missing_notified:
self.write(cr, SUPERUSER_ID, [newid], {'partner_ids': [(4, p_id) for p_id in missing_notified]}, context=context)
1. message.parent_id = False: new thread, no quote_context
2. get the lasts messages in the thread before message
3. get the message header
4. add an expandable between them
:param dict quote_context: options for quoting
:return string: html quote
"""
add_expandable = False
message = self.browse(cr, uid, id, context=context)
if not message.parent_id:
return ''
context_ids = self.search(cr, uid, [
('parent_id', '=', message.parent_id.id),
('id', '<', message.id),
], 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):
""" 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
"""
message = self.browse(cr, uid, newid, context=context)
if message.model and message.res_id:
self._notify_followers(cr, uid, newid, message, context=context)
message = self.read(cr, uid, newid, ['model', 'res_id', 'author_id', 'subtype_id', 'partner_ids'], context=context)
# add myself if I wrote on my wall, otherwise remove myself author
if ((message.model == "res.partner" and message.res_id == message.author_id.id)):
self.write(cr, SUPERUSER_ID, [newid], {'partner_ids': [(4, message.author_id.id)]}, context=context)
else:
self.write(cr, SUPERUSER_ID, [newid], {'partner_ids': [(3, message.author_id.id)]}, context=context)
partners_to_notify = set([])
# message has no subtype_id: pure log message -> no partners, no one notified
if not message.get('subtype_id'):
return True
# 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)
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
#------------------------------------------------------

View File

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

View File

@ -554,7 +554,11 @@ class mail_thread(osv.AbstractModel):
('file2', 'bytes')}
}
"""
msg_dict = {}
msg_dict = {
'type': 'email',
'subtype': 'mail.mt_comment',
'author_id': False,
}
if not isinstance(message, Message):
if isinstance(message, 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:
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['to'] = decode(message.get('to'))
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)
if author_ids:
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)
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:
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
# 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.update({
@ -690,32 +708,28 @@ class mail_thread(osv.AbstractModel):
return mail_message.create(cr, uid, values, context=context)
def message_post_api(self, cr, uid, thread_id, body='', subject=False, type='notification',
subtype=None, parent_id=False, attachments=None, context=None, **kwargs):
# TDE FIXME: body is plaintext: convert it into html
# when writing on res.partner, without specific thread_id -> redirect to the user's partner
if self._name == 'res.partner' and not thread_id:
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']
parent_id=False, attachment_ids=None, context=None):
""" Wrapper on message_post, used only in Chatter (JS). The purpose is
to handle attachments.
# TDE FIXME: body is plaintext: convert it into html
"""
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
if attachments:
# HACK FIXME: Chatter: attachments linked to the document (not done JS-side), load the message
if attachment_ids:
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)
if attachment_ids:
mail_message = self.pool.get('mail.message')
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)
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
return new_message_id
#------------------------------------------------------
# Followers API

View File

@ -45,7 +45,7 @@
sequence="10"/>
<!-- 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"/>
<record id="mail_inboxfeeds" model="ir.ui.menu">
@ -79,4 +79,4 @@
<field name="parent_id" ref="mail.mail_feeds"/>
</record>
</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_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_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_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
@ -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_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_message_subtype,mail.message.subtype,model_mail_message_subtype,,1,1,1,1
access_mail_mail_user,mail.mail,model_mail_mail,base.group_user,1,1,1,0
access_mail_message_subtype_all,mail.message.subtype.all,model_mail_message_subtype,,1,0,0,0
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),
false,
'comment',
'mail.mt_comment',
this.context.default_parent_id,
attachments,
this.parent_thread.context
@ -438,7 +437,7 @@ openerp.mail = function (session) {
// data of this expandable message
this.id = datasets.id || -1,
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.thread_level = datasets.thread_level || 0,
this.type = 'expandable',
@ -512,10 +511,10 @@ openerp.mail = function (session) {
* - record.attachment_ids[].url: url of each attachmentThe
* thread view :
* - root thread
* - - sub message (ancestor_id = root message)
* - - sub message (parent_id = root message)
* - - - sub thread
* - - - - sub sub message (parent id = sub thread)
* - - sub message (ancestor_id = root message)
* - - sub message (parent_id = root message)
* - - - sub thread
*/
mail.ThreadMessage = session.web.Widget.extend({
@ -553,7 +552,7 @@ openerp.mail = function (session) {
// data of this message
this.id = datasets.id || -1,
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.type = datasets.type || 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
* thread view:
* - root thread
* - - sub message (ancestor_id = root message)
* - - sub message (parent_id = root message)
* - - - sub thread
* - - - - sub sub message (parent id = sub thread)
* - - sub message (ancestor_id = root message)
* - - sub message (parent_id = root message)
* - - - sub thread
*/
mail.Thread = session.web.Widget.extend({
@ -907,7 +906,7 @@ openerp.mail = function (session) {
// data of this thread
this.id = datasets.id || 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.author_id = datasets.author_id || false,
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
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]
).then(this.proxy('switch_new_message'));
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'));
},
/**
@ -1254,7 +1253,7 @@ openerp.mail = function (session) {
var self=this;
_(records).each(function (record) {
var thread = self.browse_thread({
'id': record.ancestor_id,
'id': record.parent_id,
'default_return_top_thread':true
});
// create object and attach to the thread object
@ -1334,10 +1333,10 @@ openerp.mail = function (session) {
var expandable = new mail.ThreadExpandable(this, {
'id': message.id,
'model': message.model,
'ancestor_id': message.ancestor_id,
'parent_id': message.parent_id,
'nb_messages': 1,
'thread_level': message.thread_level,
'ancestor_id': message.ancestor_id,
'parent_id': message.parent_id,
'domain': message_dom,
'options': message.options,
}, {

View File

@ -94,6 +94,8 @@ class TestMailMockups(common.TransactionCase):
self._build_email_kwargs_list = []
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_kwargs_list.append(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_id = group_employee_ref and group_employee_ref[1] or False
# 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)
# 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):
""" 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"
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='')
@ -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',
'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):
""" Tests designed for the many2many function field 'follower_ids'.
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_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. """
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'})
@ -361,11 +403,11 @@ class test_mail(TestMailMockups):
# the html2plaintext uses etree or beautiful soup, so the result may be slighly different
# depending if you have installed beautiful soup.
self.assertIn(sent_email['body_alternative'], _mail_bodyalt1 + '\nBert Tartopoils\n', 'sent_email body_alternative is incorrect')
# Test: mail_message: partner_ids = group followers
message_pids = set([partner.id for partner in message.partner_ids])
# Test: mail_message: notified_partner_ids = group followers
message_pids = set([partner.id for partner in message.notified_partner_ids])
test_pids = set([p_b_id, p_c_id])
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_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')
@ -394,11 +436,11 @@ class test_mail(TestMailMockups):
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_bodyalt2, sent_email['body_alternative'], 'sent_email body_alternative incorrect')
# Test: mail_message: partner_ids = group followers
message_pids = set([partner.id for partner in message.partner_ids])
# Test: mail_message: notified_partner_ids = group followers
message_pids = set([partner.id for partner in message.notified_partner_ids])
test_pids = set([p_b_id, p_c_id, p_d_id])
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_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')
@ -412,6 +454,11 @@ class test_mail(TestMailMockups):
self.assertIn((attach.name, attach.datas.decode('base64')), _attachments,
'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):
""" Tests designed for the mail.compose.message wizard. """
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
self.assertEqual(message.subject, False, 'mail.message incorrect subject')
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)
msg_pids = [partner.id for partner in message.partner_ids]
# 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.notified_partner_ids]
test_pids = [p_b_id, p_c_id, p_d_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(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
@ -526,20 +573,6 @@ class test_mail(TestMailMockups):
def test_30_message_read(self):
""" 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
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
# 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
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
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(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
new_threads_exp, new_msg_exp = None, None
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:
new_threads_exp = msg
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')
domain = new_msg_exp.get('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', '>=', 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.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)
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']
# 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')
@ -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')
domain = new_threads_exp.get('domain', [])
# Test: expandable, conditions in domain
_print_debug('Executing %s' % domain, _debug)
for condition in pigs_domain:
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)
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']
# 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(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
new_threads_exp, new_msg_exp = None, None
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:
new_threads_exp = msg
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')
domain = new_msg_exp.get('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', '>=', 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.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)
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']
# 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')
@ -654,7 +677,6 @@ class test_mail(TestMailMockups):
self.assertIsNotNone(new_threads_exp, 'message_read should have returned a new threads expandable')
domain = new_threads_exp.get('domain', [])
# Test: expandable, conditions in domain
_print_debug('Executing %s' % domain, _debug)
for condition in pigs_domain:
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)
@ -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
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')
for msg in read_msg_list:
_print_msg(msg, _debug)
# ----------------------------------------
# CASE2: message_read with domain, flat
# ----------------------------------------
_print_debug('\nCASE2: message_read with domain, flat\n', _debug)
# Do: read 2 lasts message, flat
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
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.assertFalse(read_msg_list[0].get('ancestor_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[0].get('parent_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
new_threads_exp, new_msg_exp = None, None
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:
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')
domain = new_threads_exp.get('domain', [])
# Test: expandable, conditions in domain
_print_debug('Executing %s' % domain, _debug)
for condition in pigs_domain:
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)
@ -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([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')
for msg in read_msg_list:
_print_msg(msg, _debug)
def test_40_needaction(self):
""" 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',
extra='In-Reply-To: %s' % msg1.message_id)
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
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)
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
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):
""" Test designed for the vote/unvote feature. """
cr, uid = self.cr, self.uid
user_admin = self.res_users.browse(cr, uid, uid)
group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
msg1 = group_pigs.message_post(body='My Body', subject='1')
msg1 = self.mail_message.browse(cr, uid, msg1)
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)
# Create user Bert Tartopoils
user_bert_id = self.res_users.create(cr, uid, {'name': 'Bert', 'login': 'bert'})
user_bert = self.res_users.browse(cr, uid, user_bert_id)
# Test: msg1 and msg2 have void vote_user_ids
self.assertFalse(msg1.vote_user_ids, 'newly created message msg1 has not void vote_user_ids')
# Do: Admin vote for msg1
self.mail_message.vote_toggle(cr, uid, [msg1.id])
msg1.refresh()
# Test: msg1 has Admin as voter
self.assertEqual(set(msg1.vote_user_ids), set([user_admin]), 'after voting, Admin is not the voter')
# Do: Bert vote for msg1
self.mail_message.vote_toggle(cr, user_bert_id, [msg1.id])
msg1.refresh()
# Test: msg1 has Admin and Bert as voters
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')
# Do: Admin vote for msg
self.mail_message.vote_toggle(cr, uid, [msg.id])
msg.refresh()
# Test: msg has Admin as voter
self.assertEqual(set(msg.vote_user_ids), set([user_admin]), 'mail_message vote: after voting, Admin should be in the voter')
# Do: Bert vote for msg
self.mail_message.vote_toggle(cr, user_raoul.id, [msg.id])
msg.refresh()
# Test: msg has Admin and Bert as voters
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')
# Do: Admin unvote for msg
self.mail_message.vote_toggle(cr, uid, [msg.id])
msg.refresh()
# Test: msg has Bert as voter
self.assertEqual(set(msg.vote_user_ids), set([user_raoul]), 'mail_message vote: after unvoting, Bert should be in the voter')
def test_70_message_favorite(self):
""" 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