[MERGE] Sync with trunk

bzr revid: odo@openerp.com-20121114172252-q1xj3hdugqhky532
bzr revid: odo@openerp.com-20121115135141-ia8uf5649rapj0v7
This commit is contained in:
Olivier Dony 2012-11-15 14:51:41 +01:00
commit c558ac6272
99 changed files with 976 additions and 537 deletions

View File

@ -436,7 +436,7 @@ class account_invoice(osv.osv):
if t['state'] in ('draft', 'cancel') and t['internal_number']== False:
unlink_ids.append(t['id'])
else:
raise osv.except_osv(_('Invalid Action!'), _('You cannot delete an invoice which is open or paid. You should refund it instead.'))
raise osv.except_osv(_('Invalid Action!'), _('You can not delete an invoice which is not cancelled. You should refund it instead.'))
osv.osv.unlink(self, cr, uid, unlink_ids, context=context)
return True

View File

@ -436,7 +436,7 @@
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
<field name="message_ids" widget="mail_thread" placeholder="Share a note..."/>
</div>
</form>
</field>

View File

@ -7,20 +7,20 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-02-08 00:35+0000\n"
"PO-Revision-Date: 2011-03-17 20:16+0000\n"
"PO-Revision-Date: 2012-11-13 15:01+0000\n"
"Last-Translator: jpdborgna <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-30 05:06+0000\n"
"X-Generator: Launchpad (build 16206)\n"
"X-Launchpad-Export-Date: 2012-11-14 04:40+0000\n"
"X-Generator: Launchpad (build 16251)\n"
#. module: account
#: view:account.invoice.report:0
#: view:analytic.entries.report:0
msgid "last month"
msgstr ""
msgstr "Ultimo mes"
#. module: account
#: model:process.transition,name:account.process_transition_supplierreconcilepaid0
@ -146,7 +146,7 @@ msgstr "Referencia"
#. module: account
#: view:account.open.closed.fiscalyear:0
msgid "Choose Fiscal Year "
msgstr ""
msgstr "Seleccione el año fiscal "
#. module: account
#: help:account.payment.term,active:0
@ -159,7 +159,7 @@ msgstr ""
#: code:addons/account/account_invoice.py:1430
#, python-format
msgid "Warning!"
msgstr ""
msgstr "¡Advertencia!"
#. module: account
#: code:addons/account/account.py:3129
@ -187,7 +187,7 @@ msgstr ""
#: code:addons/account/wizard/account_move_journal.py:95
#, python-format
msgid "Journal: %s"
msgstr ""
msgstr "Diario: %s"
#. module: account
#: help:account.analytic.journal,type:0
@ -228,6 +228,7 @@ msgstr ""
#, python-format
msgid "Invoice '%s' is paid partially: %s%s of %s%s (%s%s remaining)"
msgstr ""
"La factura '%s' está parcialmente pagada: %s%s de %s%s (%s%s pendiente)"
#. module: account
#: model:process.transition,note:account.process_transition_supplierentriesreconcile0
@ -268,7 +269,7 @@ msgstr ""
#. module: account
#: view:account.fiscalyear.close.state:0
msgid "Close Fiscalyear"
msgstr ""
msgstr "Cerrar ejercicio fiscal"
#. module: account
#: field:account.automatic.reconcile,allow_write_off:0
@ -335,7 +336,7 @@ msgstr ""
#. module: account
#: view:account.installer:0
msgid "Configure"
msgstr ""
msgstr "Configurar"
#. module: account
#: selection:account.entries.report,month:0
@ -344,7 +345,7 @@ msgstr ""
#: selection:report.account.sales,month:0
#: selection:report.account_type.sales,month:0
msgid "June"
msgstr ""
msgstr "Junio"
#. module: account
#: model:ir.actions.act_window,help:account.action_account_moves_bank
@ -378,12 +379,12 @@ msgstr "Fecha de creación"
#. module: account
#: selection:account.journal,type:0
msgid "Purchase Refund"
msgstr ""
msgstr "Devolución de compra"
#. module: account
#: selection:account.journal,type:0
msgid "Opening/Closing Situation"
msgstr ""
msgstr "Situación de apertura/cierre"
#. module: account
#: help:account.journal,currency:0
@ -393,7 +394,7 @@ msgstr "La moneda utilizada para el extracto"
#. module: account
#: field:account.open.closed.fiscalyear,fyear_id:0
msgid "Fiscal Year to Open"
msgstr "Año fiscal para abrir"
msgstr "Ejercicio fiscal a abrir"
#. module: account
#: help:account.journal,sequence_id:0
@ -495,7 +496,7 @@ msgstr ""
#. module: account
#: field:account.bank.statement,account_id:0
msgid "Account used in this journal"
msgstr ""
msgstr "Cuenta utilizada en este diario"
#. module: account
#: help:account.aged.trial.balance,chart_account_id:0
@ -557,7 +558,7 @@ msgstr "Cerrar un año fiscal"
#. module: account
#: model:process.transition,note:account.process_transition_confirmstatementfromdraft0
msgid "The accountant confirms the statement."
msgstr ""
msgstr "El contador confirma la declaración."
#. module: account
#: report:account.account.balance:0
@ -8156,7 +8157,7 @@ msgstr ""
#: field:account.bank.statement,balance_end_real:0
#: field:account.treasury.report,ending_balance:0
msgid "Ending Balance"
msgstr "Balance final"
msgstr "Saldo Final"
#. module: account
#: help:account.move.line,blocked:0

View File

@ -0,0 +1,4 @@
from . import test_tax
fast_suite = [test_tax,
]

View File

@ -0,0 +1,49 @@
from openerp.tests.common import TransactionCase
class TestTax(TransactionCase):
"""Tests for taxes (account.tax)
We don't really need at this point to link taxes to tax codes
(account.tax.code) nor to companies (base.company) to check computation
results.
"""
def setUp(self):
super(TestTax, self).setUp()
self.tax_model = self.registry('account.tax')
def test_programmatic_tax(self):
cr, uid = self.cr, self.uid
tax_id = self.tax_model.create(cr, uid, dict(
name="Programmatic tax",
type='code',
python_compute='result = 12.0',
python_compute_inv='result = 11.0',
))
tax_records = self.tax_model.browse(cr, uid, [tax_id])
res = self.tax_model.compute_all(cr, uid, tax_records, 50.0, 2)
tax_detail = res['taxes'][0]
self.assertEquals(tax_detail['amount'], 24.0)
self.assertEquals(res['total_included'], 124.0)
def test_percent_tax(self):
"""Test computations done by a 10 percent tax."""
cr, uid = self.cr, self.uid
tax_id = self.tax_model.create(cr, uid, dict(
name="Percent tax",
type='percent',
amount='0.1',
))
tax_records = self.tax_model.browse(cr, uid, [tax_id])
res = self.tax_model.compute_all(cr, uid, tax_records, 50.0, 2)
tax_detail = res['taxes'][0]
self.assertEquals(tax_detail['amount'], 10.0)
self.assertEquals(res['total_included'], 110.0)
# now the inverse computation
res = self.tax_model.compute_inv(cr, uid, tax_records, 55.0, 2)
self.assertEquals(res[0]['amount'], 10.0)

View File

@ -14,15 +14,19 @@
</xpath>
<xpath expr="//notebook/page[@string='Filters']" position="after">
<page string="Comparison" attrs="{'invisible': [('enable_filter','=',False)]}">
<field name="label_filter" attrs="{'required': [('enable_filter', '=', True)]}"/>
<field name="fiscalyear_id_cmp"/><newline/>
<field name="filter_cmp"/>
<separator string="Dates" colspan="4"/>
<field name="date_from_cmp" attrs="{'readonly':[('filter_cmp', '!=', 'filter_date')], 'required':[('filter_cmp', '=', 'filter_date')]}" colspan="4"/>
<field name="date_to_cmp" attrs="{'readonly':[('filter_cmp', '!=', 'filter_date')], 'required':[('filter_cmp', '=', 'filter_date')]}" colspan="4"/>
<separator string="Periods" colspan="4"/>
<field name="period_from_cmp" domain="[('fiscalyear_id', '=', fiscalyear_id_cmp)]" attrs="{'readonly':[('filter_cmp','!=','filter_period')], 'required':[('filter_cmp', '=', 'filter_period')]}" colspan="4"/>
<field name="period_to_cmp" domain="[('fiscalyear_id', '=', fiscalyear_id_cmp)]" attrs="{'readonly':[('filter_cmp','!=','filter_period')], 'required':[('filter_cmp', '=', 'filter_period')]}" colspan="4"/>
<group>
<field name="label_filter" attrs="{'required': [('enable_filter', '=', True)]}"/>
<field name="fiscalyear_id_cmp"/><newline/>
<field name="filter_cmp"/>
</group>
<group string="Dates" attrs="{'invisible':[('filter_cmp', '!=', 'filter_date')]}">
<field name="date_from_cmp" attrs="{'required':[('filter_cmp', '=', 'filter_date')]}"/>
<field name="date_to_cmp" attrs="{'required':[('filter_cmp', '=', 'filter_date')]}"/>
</group>
<group string="Periods" attrs="{'invisible':[('filter_cmp', '!=', 'filter_period')]}">
<field name="period_from_cmp" domain="[('fiscalyear_id', '=', fiscalyear_id_cmp)]" attrs="{'required':[('filter_cmp', '=', 'filter_period')]}"/>
<field name="period_to_cmp" domain="[('fiscalyear_id', '=', fiscalyear_id_cmp)]" attrs="{'required':[('filter_cmp', '=', 'filter_period')]}"/>
</group>
</page>
</xpath>
<xpath expr="//notebook/page[@string='Journals']" position="replace">

View File

@ -27,7 +27,7 @@ class account_open_closed_fiscalyear(osv.osv_memory):
_description = "Choose Fiscal Year"
_columns = {
'fyear_id': fields.many2one('account.fiscalyear', \
'Fiscal Year to Open', required=True, help='Select Fiscal Year which you want to remove entries for its End of year entries journal'),
'Fiscal Year', required=True, help='Select Fiscal Year which you want to remove entries for its End of year entries journal'),
}
def remove_entries(self, cr, uid, ids, context=None):
@ -36,7 +36,7 @@ class account_open_closed_fiscalyear(osv.osv_memory):
data = self.browse(cr, uid, ids, context=context)[0]
period_journal = data.fyear_id.end_journal_period_id or False
if not period_journal:
raise osv.except_osv(_('Error!'), _('You have to set the end of the fiscal year for this journal.'))
raise osv.except_osv(_('Error!'), _("You have to set the 'End of Year Entries Journal' for this Fiscal Year which is set after generating opening entries from 'Generate Opening Entries'."))
ids_move = move_obj.search(cr, uid, [('journal_id','=',period_journal.journal_id.id),('period_id','=',period_journal.period_id.id)])
if ids_move:

View File

@ -5,14 +5,18 @@
<field name="name">account.open.closed.fiscalyear.form</field>
<field name="model">account.open.closed.fiscalyear</field>
<field name="arch" type="xml">
<form string="Choose Fiscal Year " version="7.0">
<form string="Cancel Fiscal Year Opening Entries" version="7.0">
<separator string="Cancel Fiscal Year Opening Entries"/>
<p class="oe_grey">
This wizard will remove the end of year journal entries of selected fiscal year. Note that you can run this wizard many times for the same fiscal year.
</p>
<group>
<field name="fyear_id" domain="[('state','=','draft')]"/>
<field name="fyear_id" domain="[('state','=','draft'), ('end_journal_period_id', '!=', False)]"/>
</group>
<footer>
<button string="Open" name="remove_entries" type="object" class="oe_highlight"/>
<button string="Cancel Opening Entries" name="remove_entries" type="object" class="oe_highlight"/>
or
<button string="Cancel" class="oe_link" special="cancel"/>
<button string="Discard" class="oe_link" special="cancel"/>
</footer>
</form>
</field>

View File

@ -9,8 +9,7 @@
<field name="inherit_id" ref="account_common_report_view" />
<field name="arch" type="xml">
<data>
<xpath expr="//field[@name='journal_ids']" position="replace">
<field name="journal_ids" colspan="4" nolabel="1" required="0" readonly="1"/>
<xpath expr="//notebook/page[@string='Journals']" position="replace">
</xpath>
<xpath expr="//field[@name='target_move']" position="after">
<field name="display_account"/>

View File

@ -26,12 +26,10 @@
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subtype_id" ref="mail.mt_comment"/>
<field name="subject">Accounting and Finance application installed!</field>
<field name="body"><![CDATA[
With OpenERP's accounting, you get instant access to your financial data, and can setup analytic accounting, forecast taxes, control budgets, easily create and send invoices, record bank statements, etc.
<p>The accounting features are fully integrated with other OpenERP applications to automate all your processes: creation of customer invoices, control of supplier invoices, point-of-sale integration, automated follow-ups, etc.</p>
]]></field>
<field name="body"><![CDATA[<p>With OpenERP's accounting, you get instant access to your financial data, and can setup analytic accounting, forecast taxes, control budgets, easily create and send invoices, record bank statements, etc.</p>
<p>The accounting features are fully integrated with other OpenERP applications to automate all your processes: creation of customer invoices, control of supplier invoices, point-of-sale integration, automated follow-ups, etc.</p>]]></field>
</record>
</data>
</openerp>

View File

@ -377,9 +377,8 @@ class account_asset_depreciation_line(osv.osv):
move_line_obj = self.pool.get('account.move.line')
currency_obj = self.pool.get('res.currency')
created_move_ids = []
asset_ids = []
for line in self.browse(cr, uid, ids, context=context):
if currency_obj.is_zero(cr, uid, line.asset_id.currency_id, line.remaining_value):
can_close = True
depreciation_date = time.strftime('%Y-%m-%d')
period_ids = period_obj.find(cr, uid, depreciation_date, context=context)
company_currency = line.asset_id.company_id.currency_id.id
@ -409,8 +408,8 @@ class account_asset_depreciation_line(osv.osv):
'period_id': period_ids and period_ids[0] or False,
'journal_id': journal_id,
'partner_id': partner_id,
'currency_id': company_currency <> current_currency and current_currency or False,
'amount_currency': company_currency <> current_currency and - sign * line.amount or 0.0,
'currency_id': company_currency != current_currency and current_currency or False,
'amount_currency': company_currency != current_currency and - sign * line.amount or 0.0,
'date': depreciation_date,
})
move_line_obj.create(cr, uid, {
@ -423,16 +422,19 @@ class account_asset_depreciation_line(osv.osv):
'period_id': period_ids and period_ids[0] or False,
'journal_id': journal_id,
'partner_id': partner_id,
'currency_id': company_currency <> current_currency and current_currency or False,
'amount_currency': company_currency <> current_currency and sign * line.amount or 0.0,
'currency_id': company_currency != current_currency and current_currency or False,
'amount_currency': company_currency != current_currency and sign * line.amount or 0.0,
'analytic_account_id': line.asset_id.category_id.account_analytic_id.id,
'date': depreciation_date,
'asset_id': line.asset_id.id
})
self.write(cr, uid, line.id, {'move_id': move_id}, context=context)
created_move_ids.append(move_id)
if can_close:
asset_obj.write(cr, uid, [line.asset_id.id], {'state': 'close'}, context=context)
asset_ids.append(line.asset_id.id)
# we re-evaluate the assets to determine whether we can close them
for asset in asset_obj.browse(cr, uid, list(set(asset_ids)), context=context):
if currency_obj.is_zero(cr, uid, asset.currency_id, asset.value_residual):
asset.write({'state': 'close'})
return created_move_ids
account_asset_depreciation_line()

View File

@ -72,12 +72,12 @@
<field name="date" readonly="1"/>
<field name="val_date" readonly="1"/>
<field name="name"/>
<field name="statement_id" readonly="1"/>
<field name="statement_id"/>
<field name="ref" readonly="1"/>
<field name="partner_id" on_change="onchange_partner_id(partner_id)"/>
<field name="type" on_change="onchange_type(partner_id, type)"/>
<field name="account_id" domain="[('journal_id','=',journal_id)]"/>
<field name="analytic_account_id" groups="analytic.group_analytic_accounting" domain="[('company_id', '=', parent.company_id), ('type', '&lt;&gt;', 'view')]"/>
<field name="account_id"/>
<field name="analytic_account_id" groups="analytic.group_analytic_accounting" domain="[('type', '&lt;&gt;', 'view')]"/>
<field name="amount" readonly="1" sum="Total Amount"/>
<field name="globalisation_id" string="Glob. Id"/>
<field name="globalisation_amount" string="Glob. Am."/>
@ -100,8 +100,8 @@
<field name="ref" readonly="0"/>
<field name="partner_id" on_change="onchange_partner_id(partner_id)"/>
<field name="type" on_change="onchange_type(partner_id, type)"/>
<field domain="[('journal_id', '=', journal_id), ('type', '&lt;&gt;', 'view')]" name="account_id"/>
<field name="analytic_account_id" groups="analytic.group_analytic_accounting" domain="[('company_id', '=', parent.company_id), ('type', '&lt;&gt;', 'view')]"/>
<field domain="[('type', '&lt;&gt;', 'view')]" name="account_id"/>
<field name="analytic_account_id" groups="analytic.group_analytic_accounting" domain="[('type', '&lt;&gt;', 'view')]"/>
<field name="amount"/>
<field name="globalisation_id"/>
<field name="sequence" readonly="0"/>

View File

@ -383,8 +383,9 @@ class account_voucher(osv.osv):
total_tax = 0.0
if not tax[0].price_include:
for tax_line in tax_pool.compute_all(cr, uid, tax, voucher_amount, 1).get('taxes', []):
total_tax += tax_line.get('amount', 0.0)
for line in voucher.line_ids:
for tax_line in tax_pool.compute_all(cr, uid, tax, line.amount, 1).get('taxes', []):
total_tax += tax_line.get('amount', 0.0)
total += total_tax
else:
for line in voucher.line_ids:
@ -415,31 +416,31 @@ class account_voucher(osv.osv):
line_ids = resolve_o2m_operations(cr, uid, line_pool, line_ids, ["amount"], context)
total_tax = 0.0
for line in line_ids:
line_amount = 0.0
line_amount = line.get('amount',0.0)
if tax_id:
tax = [tax_pool.browse(cr, uid, tax_id, context=context)]
if partner_id:
partner = partner_pool.browse(cr, uid, partner_id, context=context) or False
taxes = position_pool.map_tax(cr, uid, partner and partner.property_account_position or False, tax)
tax = tax_pool.browse(cr, uid, taxes, context=context)
if not tax[0].price_include:
for tax_line in tax_pool.compute_all(cr, uid, tax, line_amount, 1).get('taxes', []):
total_tax += tax_line.get('amount')
voucher_total += line_amount
total = voucher_total
total_tax = 0.0
if tax_id:
tax = [tax_pool.browse(cr, uid, tax_id, context=context)]
if partner_id:
partner = partner_pool.browse(cr, uid, partner_id, context=context) or False
taxes = position_pool.map_tax(cr, uid, partner and partner.property_account_position or False, tax)
tax = tax_pool.browse(cr, uid, taxes, context=context)
if not tax[0].price_include:
for tax_line in tax_pool.compute_all(cr, uid, tax, voucher_total, 1).get('taxes', []):
total_tax += tax_line.get('amount')
total += total_tax
total = voucher_total + total_tax
res.update({
'amount':total or voucher_total,
'tax_amount':total_tax
'amount': total or voucher_total,
'tax_amount': total_tax
})
return {
'value':res
'value': res
}
def onchange_term_id(self, cr, uid, ids, term_id, amount):

View File

@ -7,12 +7,10 @@
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subtype_id" ref="mail.mt_comment"/>
<field name="subject">eInvoicing &amp; Payments application installed!</field>
<field name="body"><![CDATA[
OpenERP's electronic invoicing accelerates the creation of invoices and collection of customer payments. Invoices are created in a few clicks and your customers receive them by email. They can pay online and/or import them in their own system.
<p>You can track customer payments easily and automate follow-ups. You get an overview of the discussion with your customers on each invoice for easier traceability. For advanced accounting features, you should install the "Accounting and Finance" module.</p>
]]></field>
<field name="body"><![CDATA[<p>OpenERP's electronic invoicing accelerates the creation of invoices and collection of customer payments. Invoices are created in a few clicks and your customers receive them by email. They can pay online and/or import them in their own system.</p>
<p>You can track customer payments easily and automate follow-ups. You get an overview of the discussion with your customers on each invoice for easier traceability. For advanced accounting features, you should install the "Accounting and Finance" module.</p>]]></field>
</record>
<!-- mail: subtypes -->

View File

@ -327,7 +327,7 @@ class account_analytic_line(osv.osv):
'date': fields.date('Date', required=True, select=True),
'amount': fields.float('Amount', required=True, help='Calculated by multiplying the quantity and the price given in the Product\'s cost price. Always expressed in the company main currency.', digits_compute=dp.get_precision('Account')),
'unit_amount': fields.float('Quantity', help='Specifies the amount of quantity to count.'),
'account_id': fields.many2one('account.analytic.account', 'Analytic Account', required=True, ondelete='cascade', select=True, domain=[('type','<>','view')]),
'account_id': fields.many2one('account.analytic.account', 'Analytic Account', required=True, ondelete='restrict', select=True, domain=[('type','<>','view')]),
'user_id': fields.many2one('res.users', 'User'),
'company_id': fields.related('account_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True),

View File

@ -346,8 +346,13 @@ class audittrail_objects_proxy(object_proxy):
x2m_model_id = x2m_model_ids and x2m_model_ids[0] or False
assert x2m_model_id, _("'%s' Model does not exist..." %(field_obj._obj))
x2m_model = pool.get('ir.model').browse(cr, SUPERUSER_ID, x2m_model_id)
#recursive call on x2m fields that need to be checked too
data.update(self.get_data(cr, SUPERUSER_ID, pool, resource[field], x2m_model, method))
field_resource_ids = list(set(resource[field]))
if model.model == x2m_model.model:
# we need to remove current resource_id from the many2many to prevent an infinit loop
if resource_id in field_resource_ids:
field_resource_ids.remove(resource_id)
data.update(self.get_data(cr, SUPERUSER_ID, pool, field_resource_ids, x2m_model, method))
data[(model.id, resource_id)] = {'text':values_text, 'value': values}
return data
@ -408,6 +413,10 @@ class audittrail_objects_proxy(object_proxy):
x2m_new_values_ids = new_values.get(key, {'value': {}})['value'].get(field_name, [])
# We use list(set(...)) to remove duplicates.
res_ids = list(set(x2m_old_values_ids + x2m_new_values_ids))
if model.model == x2m_model.model:
# we need to remove current resource_id from the many2many to prevent an infinit loop
if resource_id in res_ids:
res_ids.remove(resource_id)
for res_id in res_ids:
lines.update(self.prepare_audittrail_log_line(cr, SUPERUSER_ID, pool, x2m_model, res_id, method, old_values, new_values, field_list))
# if the value value is different than the old value: record the change

View File

@ -4,11 +4,11 @@ openerp.auth_anonymous = function(instance) {
start: function() {
var self = this;
return $.when(this._super()).then(function() {
var dblist = self._db_list || [];
var dblist = self.db_list || [];
if (!self.session.session_is_valid() && dblist.length === 1) {
self.remember_credentials = false;
// XXX get login/pass from server (via a rpc call) ?
return self.do_login(dblist[0], 'anonymous', 'anonymous')
return self.do_login(dblist[0], 'anonymous', 'anonymous');
}
});

View File

@ -41,7 +41,7 @@ openerp.auth_signup = function(instance) {
on_token_loaded: function(result) {
// select the right the database
this.selected_db = result.db;
this.on_db_loaded({db_list: [result.db]});
this.on_db_loaded([result.db]);
if (result.token) {
// switch to signup mode, set user name and login
this.$el.addClass("oe_login_signup");
@ -80,16 +80,16 @@ openerp.auth_signup = function(instance) {
this.do_warn("Login", "No database selected !");
return false;
} else if (!name) {
this.do_warn("Login", "Please enter a name.")
this.do_warn("Login", "Please enter a name.");
return false;
} else if (!login) {
this.do_warn("Login", "Please enter a username.")
this.do_warn("Login", "Please enter a username.");
return false;
} else if (!password || !confirm_password) {
this.do_warn("Login", "Please enter a password and confirm it.")
this.do_warn("Login", "Please enter a password and confirm it.");
return false;
} else if (password !== confirm_password) {
this.do_warn("Login", "Passwords do not match; please retype them.")
this.do_warn("Login", "Passwords do not match; please retype them.");
return false;
}
var params = {

View File

@ -221,7 +221,7 @@
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="message_ids" widget="mail_thread"/>
<field name="message_ids" widget="mail_thread" placeholder="Share a message..."/>
</div>
</form>
</field>

View File

@ -24,7 +24,7 @@ Re-implement openerp's file import system:
'category': 'Uncategorized',
'website': 'http://www.openerp.com',
'author': 'OpenERP SA',
'depends': ['base'],
'depends': ['web'],
'installable': True,
'auto_install': False,
'css': [
@ -37,4 +37,5 @@ Re-implement openerp's file import system:
'static/src/js/import.js',
],
'qweb': ['static/src/xml/import.xml'],
'test': ['static/test/states.js'],
}

View File

@ -0,0 +1,6 @@
$(document).ready(function () {
module('foo');
test('dummy', function () {
ok(42);
});
});

View File

@ -44,7 +44,6 @@ Shows you a list of applications features to install from.
'installable': True,
'auto_install': False,
'images': ['images/base_setup1.jpeg','images/base_setup2.jpeg','images/base_setup3.jpeg','images/base_setup4.jpeg',],
'js': ['static/src/js/base_setup.js'],
'css': ['static/src/css/base_setup.css'],
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -0,0 +1,30 @@
# Hungarian 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: 2011-01-11 11:14+0000\n"
"PO-Revision-Date: 2012-11-13 16:00+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Hungarian <hu@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-11-14 04:40+0000\n"
"X-Generator: Launchpad (build 16251)\n"
#. module: base_tools
#: model:ir.module.module,shortdesc:base_tools.module_meta_information
msgid "Common base for tools modules"
msgstr ""
#. module: base_tools
#: model:ir.module.module,description:base_tools.module_meta_information
msgid ""
"\n"
" "
msgstr ""

View File

@ -58,9 +58,10 @@
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subtype_id" ref="mail.mt_comment"/>
<field name="subject">CRM application installed!</field>
<field name="body">From the top Sales menu you can track leads and opportunities, get accurate forecast on your sales pipeline, plan meetings and phonecalls, get realtime statistics and efficiently organize the communication with your prospects.
To manage quotations and sale orders, install the "Sales Management" application.</field>
<field name="body"><![CDATA[<p>From the top Sales menu you can track leads and opportunities, get accurate forecast on your sales pipeline, plan meetings and phonecalls, get realtime statistics and efficiently organize the communication with your prospects.</p>
<p>To manage quotations and sale orders, install the "Sales Management" application.</p>]]></field>
</record>
<record model="mail.alias" id="default_sales_alias">

View File

@ -168,7 +168,7 @@
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
<field name="message_ids" widget="mail_thread" placeholder="Share a note..."/>
</div>
</form>
</field>

View File

@ -95,7 +95,7 @@
</notebook>
</sheet>
<div class="oe_chatter">
<field name="message_ids" widget="mail_thread"/>
<field name="message_ids" widget="mail_thread" placeholder="Share a note..."/>
<field name="message_follower_ids" widget="mail_followers"/>
</div>
</form>

View File

@ -28,8 +28,6 @@ from osv import osv
from osv import fields
import tools
from tools.translate import _
from tools.html_sanitize import html_sanitize
from tools import append_content_to_html
from urllib import quote as quote
_logger = logging.getLogger(__name__)
@ -293,10 +291,10 @@ class email_template(osv.osv):
or False
if template.user_signature:
signature = self.pool.get('res.users').browse(cr, uid, uid, context).signature
values['body_html'] = append_content_to_html(values['body_html'], signature)
values['body_html'] = tools.append_content_to_html(values['body_html'], signature)
if values['body_html']:
values['body'] = html_sanitize(values['body_html'])
values['body'] = tools.html_sanitize(values['body_html'])
values.update(mail_server_id=template.mail_server_id.id or False,
auto_delete=template.auto_delete,

View File

@ -20,10 +20,10 @@
##############################################################################
import base64
from openerp.addons.mail.tests import test_mail
from openerp.addons.mail.tests import test_mail_mockup
class test_message_compose(test_mail.TestMailMockups):
class test_message_compose(test_mail_mockup.TestMailMockups):
def setUp(self):
super(test_message_compose, self).setUp()
@ -52,8 +52,8 @@ class test_message_compose(test_mail.TestMailMockups):
# Mail data
_subject1 = 'Pigs'
_subject2 = 'Bird'
_body_html1 = 'Fans of Pigs, unite !\n<pre>Admin</pre>\n'
_body_html2 = 'I am angry !\n<pre>Admin</pre>\n'
_body_html1 = 'Fans of Pigs, unite !\n<p>Admin</p>\n'
_body_html2 = 'I am angry !\n<p>Admin</p>\n'
_attachments = [
{'name': 'First', 'datas_fname': 'first.txt', 'datas': base64.b64encode('My first attachment')},
{'name': 'Second', 'datas_fname': 'second.txt', 'datas': base64.b64encode('My second attachment')}

View File

@ -25,6 +25,21 @@ from osv import osv
from osv import fields
def _reopen(self, res_id, model):
return {'type': 'ir.actions.act_window',
'view_mode': 'form',
'view_type': 'form',
'res_id': res_id,
'res_model': self._name,
'target': 'new',
# save original model in context, because selecting the list of available
# templates requires a model in context
'context': {
'default_model': model,
},
}
class mail_compose_message(osv.TransientModel):
_inherit = 'mail.compose.message'
@ -42,10 +57,8 @@ class mail_compose_message(osv.TransientModel):
else:
model = context.get('default_model', context.get('active_model'))
if model:
record_ids = email_template_obj.search(cr, uid, [('model', '=', model)], context=context)
return email_template_obj.name_get(cr, uid, record_ids, context) + [(False, '')]
return []
record_ids = email_template_obj.search(cr, uid, [('model', '=', model)], context=context)
return email_template_obj.name_get(cr, uid, record_ids, context) + [(False, '')]
def default_get(self, cr, uid, fields, context=None):
if context is None:
@ -110,7 +123,7 @@ class mail_compose_message(osv.TransientModel):
onchange_res['partner_ids'] = [(4, partner_id) for partner_id in onchange_res.pop('partner_ids', [])]
onchange_res['attachment_ids'] = [(4, attachment_id) for attachment_id in onchange_res.pop('attachment_ids', [])]
record.write(onchange_res)
return True
return _reopen(self, record.id, record.model)
def onchange_use_template(self, cr, uid, ids, use_template, template_id, composition_mode, model, res_id, context=None):
""" onchange_use_template (values: True or False). If use_template is
@ -142,8 +155,8 @@ class mail_compose_message(osv.TransientModel):
'attachment_ids': [(6, 0, [att.id for att in record.attachment_ids])]
}
template_id = email_template.create(cr, uid, values, context=context)
record.write({'template_id': template_id, 'use_template': True})
return True
record.write(record.onchange_template_id(True, template_id, record.composition_mode, record.model, record.res_id)['value'])
return _reopen(self, record.id, record.model)
#------------------------------------------------------
# Wizard validation and send

View File

@ -14,12 +14,11 @@
</xpath>
<xpath expr="//footer" position="inside">
<group class="oe_right" col="1">
<div>Use template
<div attrs="{'invisible':[('use_template','=',False)]}">Use template
<field name="template_id" attrs="{'invisible':[('use_template','=',False)]}"
nolabel="1"
on_change="onchange_template_id(use_template, template_id, composition_mode, model, res_id, context)"/>
</div>
or
<button icon="/email_template/static/src/img/email_template_save.png"
type="object" name="save_as_template" string="Save as new template" class="oe_link"
help="Save as a new template"

View File

@ -205,7 +205,7 @@
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
<field name="message_ids" widget="mail_thread" placeholder="Share a note..."/>
</div>
</form>
</field>
@ -473,7 +473,7 @@
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
<field name="message_ids" widget="mail_thread" placeholder="Share a note..."/>
</div>
</form>
</field>

View File

@ -243,20 +243,20 @@ class mail_mail(osv.osv):
def create(self, cr, uid, values, context=None):
if context is None:
context={}
context = {}
fetchmail_server_id = context.get('fetchmail_server_id')
if fetchmail_server_id:
values['fetchmail_server_id'] = fetchmail_server_id
res = super(mail_mail,self).create(cr, uid, values, context=context)
res = super(mail_mail, self).create(cr, uid, values, context=context)
return res
def write(self, cr, uid, ids, values, context=None):
if context is None:
context={}
context = {}
fetchmail_server_id = context.get('fetchmail_server_id')
if fetchmail_server_id:
values['fetchmail_server_id'] = server_id
res = super(mail_mail,self).write(cr, uid, ids, values, context=context)
values['fetchmail_server_id'] = fetchmail_server_id
res = super(mail_mail, self).write(cr, uid, ids, values, context=context)
return res

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -6,11 +6,11 @@
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subtype_id" ref="mail.mt_comment"/>
<field name="subject">Employee Directory application installed!</field>
<field name="body">Manage your human resources with OpenERP: employees and their hierarchy, HR departments and job positions.
More HR features are available via extra applications: Recruitment Process (manage job positions and recruitment), Timesheet Validation (record timesheets and attendance),
Leave Management (keep track of employee leaves), Expense Management (manage employee expenses), Employee Appraisals (organize employee surveys, where employees evaluate their subordinates or their manager).</field>
<field name="body"><![CDATA[<p>Manage your human resources with OpenERP: employees and their hierarchy, HR departments and job positions.</p>
<p>More HR features are available via extra applications: Recruitment Process (manage job positions and recruitment), Timesheet Validation (record timesheets and attendance),
Leave Management (keep track of employee leaves), Expense Management (manage employee expenses), Employee Appraisals (organize employee surveys, where employees evaluate their subordinates or their manager).</p>]]></field>
</record>
<record id="employee" model="hr.employee">

View File

@ -11,9 +11,9 @@
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subtype_id" ref="mail.mt_comment"/>
<field name="subject">Employee Appraisals application installed!</field>
<field name="body">Manage employee reviews: you can define an appraisal campaign with several steps, with specific evaluation surveys according to hierarchy levels.
Evaluations filled by employees may be exported as pdf files.</field>
<field name="body"><![CDATA[<p>Manage employee reviews: you can define an appraisal campaign with several steps, with specific evaluation surveys according to hierarchy levels. Evaluations filled by employees may be exported as pdf files.</p>]]></field>
</record>
<record id="survey_2" model="survey">
@ -811,8 +811,8 @@ Once the form had been filled, the employee send it to his supervisor.
<field name="comment_valid_err_msg">The comment you entered is in an invalid format.</field>
<field name="descriptive_text">* His direct reports will be invited through OpenERP to express a feedback on their supervisor's leadership and to give their opinion about their own engagement and effectiveness, the continuous improvement and openness in action in the company, ...
* The employees will send back their anonymous answers to OpenERP. The data will be handled by the HR manager and a brief summary of the data will be sent to the concerned supervisor, to his team and to the supervisor's supervisor.
* The appraiser should rate the employees major work accomplishments and performance according to the metric provided below :
* The employees will send back their anonymous answers to OpenERP. The data will be handled by the HR manager and a brief summary of the data will be sent to the concerned supervisor, to his team and to the supervisor's supervisor.
* The appraiser should rate the employees major work accomplishments and performance according to the metric provided below :
1 - Significantly exceeds standards and expectations required of the position
2 - Exceeds standards and expectations

View File

@ -6,10 +6,10 @@
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subtype_id" ref="mail.mt_comment"/>
<field name="subject">Expense Management application installed!</field>
<field name="body">Manage your employees' expenses, after due validation by their manager and the accountant, then generate and pay the corresponding invoices.
This feature is also linked to analytic accounting and compatible with timesheet invoices, so you will be able to automatically re-invoice project-related expenses to your customers.</field>
<field name="body"><![CDATA[<p>Manage your employees' expenses, after due validation by their manager and the accountant, then generate and pay the corresponding invoices.</p>
<p>This feature is also linked to analytic accounting and compatible with timesheet invoices, so you will be able to automatically re-invoice project-related expenses to your customers.</p>]]></field>
</record>
<!-- Resource: product.uom.categ -->

View File

@ -11,9 +11,10 @@
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subtype_id" ref="mail.mt_comment"/>
<field name="subject">Leave Management application installed!</field>
<field name="body">Manage employee leaves from the top menu "Human Resources". Employees can create leave requests that are validated by their manager and/or HR officers.
Once validated, they are visible in the employee's calendar. HR officers can define leave types and allocate leaves to employees and employee categories.</field>
<field name="body"><![CDATA[<p>Manage employee leaves from the top menu "Human Resources". Employees can create leave requests that are validated by their manager and/or HR officers.</p>
<p>Once validated, they are visible in the employee's calendar. HR officers can define leave types and allocate leaves to employees and employee categories.</p>]]></field>
</record>

View File

@ -122,7 +122,7 @@
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
<field name="message_ids" widget="mail_thread"/>
</div>
</form>
</field>
@ -159,7 +159,7 @@
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
<field name="message_ids" widget="mail_thread"/>
</div>
</form>
</field>

View File

@ -6,10 +6,10 @@
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subtype_id" ref="mail.mt_comment"/>
<field name="subject">Recruitment Process application installed!</field>
<field name="body">Manage job positions and your company's recruitment process. This application is integrated with the Survey application to help you define interviews for different jobs.
You can automatically receive job application though an email gateway, see the Human Resources settings.</field>
<field name="body"><![CDATA[<p>Manage job positions and your company's recruitment process. This application is integrated with the Survey application to help you define interviews for different jobs.</p>
<p>You can automatically receive job application though an email gateway, see the Human Resources settings.</p>]]></field>
</record>
<!-- Meeting Types (for interview meetings) -->

View File

@ -184,7 +184,7 @@
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="message_ids" widget="mail_thread"/>
<field name="message_ids" widget="mail_thread" placeholder="Share a message..."/>
</div>
</form>
</field>

View File

@ -6,8 +6,9 @@
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subtype_id" ref="mail.mt_comment"/>
<field name="subject">Timesheet Validation application installed!</field>
<field name="body">From the top menu "Human Resources", enter and validate timesheets and attendances.</field>
<field name="body"><![CDATA[<p>From the top menu "Human Resources", enter and validate timesheets and attendances.</p>]]></field>
</record>
<record id="ir_actions_server_timsheet_sheet" model="ir.actions.server">

View File

@ -162,7 +162,7 @@
</notebook>
</sheet>
<div class="oe_chatter">
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
<field name="message_ids" widget="mail_thread"/>
<field name="message_follower_ids" widget="mail_followers"/>
</div>
</form>

View File

@ -1,21 +1,21 @@
# Spanish (Paraguay) translation for openobject-addons
# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
# Spanish (Argentina) 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>, 2011.
# 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: 2011-01-11 11:15+0000\n"
"PO-Revision-Date: 2011-03-21 16:23+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Spanish (Paraguay) <es_PY@li.org>\n"
"PO-Revision-Date: 2012-11-13 15:04+0000\n"
"Last-Translator: Eduardo Alberto Calvo <Unknown>\n"
"Language-Team: Spanish (Argentina) <es_AR@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2011-03-22 04:36+0000\n"
"X-Generator: Launchpad (build 12559)\n"
"X-Launchpad-Export-Date: 2012-11-14 04:40+0000\n"
"X-Generator: Launchpad (build 16251)\n"
#. module: l10n_ar
#: model:ir.module.module,description:l10n_ar.module_meta_information
@ -31,7 +31,7 @@ msgstr ""
#. module: l10n_ar
#: model:ir.module.module,shortdesc:l10n_ar.module_meta_information
msgid "Argentinian Chart of Account"
msgstr "Plan de cuentas de la Argentina"
msgstr "Plan de cuentas de Argentina"
#. module: l10n_ar
#: model:ir.actions.todo,note:l10n_ar.config_call_account_template_in_minimal
@ -45,7 +45,7 @@ msgid ""
"Chart of Accounts from a Chart Template."
msgstr ""
"Generar el plan contable a partir de una plantilla de plan contable. Se le "
"pedirá el nombre de la compañía, la plantilla de plan contable a utilizar, "
"pedirá el nombre de la compañia, la plantilla de plan contable a utilizar, "
"el número de dígitos para generar el código de las cuentas y de la cuenta "
"bancaria, la moneda para crear los diarios. Así pues, se genere una copia "
"exacta de la plantilla de plan contable.\n"

View File

@ -28,6 +28,7 @@ import logging
import re
from traceback import format_exception
from sys import exc_info
from base_iban import base_iban
_logger = logging.getLogger(__name__)
class account_coda_import(osv.osv_memory):
@ -398,6 +399,7 @@ class account_coda_import(osv.osv_memory):
st_line['account_id'] = transfer_acc
match = True
elif find_partner:
counterparty_number = base_iban._pretty_iban(base_iban._format_iban(counterparty_number))
bank_ids = partner_bank_obj.search(cr,uid,[('acc_number','=', counterparty_number)])
if not match and find_partner and bank_ids:
if len(bank_ids) > 1:

View File

@ -11,44 +11,48 @@
<record id="message_blogpost0" model="mail.message">
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<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="body"><![CDATA[<p>Your monthly meal vouchers arrived. You can get them at Christine's office.</p>]]></field>
<field name="type">comment</field>
<field name="subtype_id" ref="mt_comment"/>
<field name="author_id" ref="base.partner_root"/>
</record>
<record id="message_blogpost0_comment0" model="mail.message">
<field name="model">mail.group</field>
<field name="res_id" ref="group_all_employees"/>
<field name="body"><![CDATA[Great.]]></field>
<field name="body"><![CDATA[<p>Oh, I had forgotten. This month you also get 250 EUR of eco-vouchers if you have been in the company for more than a year.</p>]]></field>
<field name="parent_id" ref="message_blogpost0"/>
<field name="type">comment</field>
<field name="subtype_id" ref="mt_comment"/>
<field name="author_id" ref="base.partner_root"/>
</record>
<record id="message_blogpost0_comment1" model="mail.message">
<field name="model">mail.group</field>
<field name="res_id" ref="group_all_employees"/>
<field name="body">Thanks, but where is Christine's office, if I may ask? (I'm new here)</field>
<field name="body"><![CDATA[<p>Thanks! Could you please remind me where is Christine's office, if I may ask? I'm new here!</p>]]></field>
<field name="parent_id" ref="message_blogpost0"/>
<field name="type">comment</field>
<field name="subtype_id" ref="mt_comment"/>
<field name="author_id" ref="base.partner_demo"/>
</record>
<!-- This one is starred for having mailboxes with demo data -->
<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="body"><![CDATA[<p>Building B3, second floor on the right :-).</p>]]></field>
<field name="parent_id" ref="message_blogpost0"/>
<field name="type">comment</field>
<field name="subtype_id" ref="mt_comment"/>
<field name="author_id" ref="base.partner_root"/>
<field name="favorite_user_ids" eval="[(6, 0, [ref('base.user_root'), ref('base.user_demo')])]"/>
</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="body"><![CDATA[<p>Many thanks. Actually that's good news, next year I'll have to buy a new fridge, I think I will pay it with the eco-vouchers!</p>]]></field>
<field name="parent_id" ref="message_blogpost0"/>
<field name="type">comment</field>
<field name="subtype_id" ref="mt_comment"/>
<field name="author_id" ref="base.partner_demo"/>
</record>
<!-- Demo user and admin conversation -->
@ -84,163 +88,5 @@ This month you also get 250 EUR of eco-vouchers if you have been in the company
<field name="partner_ids" eval="[(6, 0, [ref('base.partner_demo')])]"/>
</record>
<!-- External mail + reply with attachment conversation -->
<record id="message_video2" model="mail.message">
<field name="subject">Plan to install OpenERP</field>
<field name="model">mail.message</field>
<field name="body">
&lt;![CDATA[Email0 inquiry]]&gt;
&lt;div&gt;&lt;font size="2"&gt;Hello,&lt;/font&gt;&lt;/div&gt;&lt;div&gt;&lt;font size="2"&gt;&lt;br&gt;&lt;/font&gt;&lt;/div&gt;
&lt;div&gt;&lt;font size="2"&gt;I am interested in your company's product and I plan to install OpenERP for my company and affordable price.&lt;/font&gt;&lt;/div&gt;&lt;br/&gt;
&lt;div&gt;&lt;font size="2"&gt;Can you please send me services catalogue?&lt;/font&gt;&lt;/div&gt;&lt;br/&gt;
Sophie
</field>
<field name="type">email</field>
<field name="author_id" ref="base.res_partner_2"/>
<field name="partner_ids" eval="[(6, 0, [ref('base.partner_demo'), ref('base.partner_root')])]"/>
</record>
<record id="message_video2_attachment1" model="ir.attachment">
<field name="model">ir.attachment</field>
<field name="datas">bWlncmF0aW9uIHRlc3Q=</field>
<field name="datas_fname">catalogue 2012.pdf</field>
<field name="name">catalogue 2012.pdf</field>
</record>
<record id="message_video2_message1" model="mail.message">
<field name="subject">Re: Plan to install OpenERP</field>
<field name="body">
Dear Customer,&lt;br/&gt;
Thanks for showing interest in our products.&lt;br/&gt;
We have attached the catalogue,&lt;br/&gt;
We would like to know your interests, so let us know when we can call you for more details.&lt;br/&gt;
Regards
</field>
<field name="type">comment</field>
<field name="subtype_id" ref="mt_comment"/>
<field name="parent_id" ref="message_video2"/>
<field name="author_id" ref="base.partner_demo"/>
<field name="attachment_ids" eval="[(6, 0, [ref('message_video2_attachment1')])]"/>
<field name="partner_ids" eval="[(6, 0, [ref('base.partner_demo'),ref('base.partner_root'),ref('base.res_partner_2')])]"/>
</record>
<!-- Employee & other + attachments conversation -->
<record id="message_video1_attachment1" model="ir.attachment">
<field name="model">ir.attachment</field>
<field name="datas">bWlncmF0aW9uIHRlc3Q=</field>
<field name="datas_fname">migration.doc</field>
<field name="name">migration.doc</field>
</record>
<record id="message_video1_attachment2" model="ir.attachment">
<field name="model">ir.attachment</field>
<field name="datas">
/9j/4AAQSkZJRgABAQEASABIAAD/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkz
ODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2Nj
Y2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wAARCABkAGQDAREA
AhEBAxEB/8QAGgAAAwEBAQEAAAAAAAAAAAAAAAQFAwIBBv/EAD0QAAEDAgMDCAcHAwUAAAAAAAEA
AgMEEQUSsiExchMzNDVBUXFzIjJhkbGzwRQVJGKBwtElg6FCUlPh8P/EABoBAQADAQEBAAAAAAAA
AAAAAAADBAUBAgb/xAAwEQACAQIDBgYBBAMBAAAAAAAAAQIDBBEyMwUSMUFx8BMhNFGx0cEUgZGh
I0LhNf/aAAwDAQACEQMRAD8A+55QFzgA4lpsbDttf6qqoN8D0e5z/sf7l3w5HMQz/kd7k8OQxOJX
SOheIgWyFpDXFtwDbYV1U5DETLcVFwySnDQLNuHOO/Zc227LBevDGJ1kxE2DpYiA6+xrgSMzT3dw
d7wm4xiZtZiwLS+andZrb+g4XdcZuzdbNb22TcGINbi4YbzU7nZTuY7a6+zs3Af5HtTwxidPbihe
MksDWAvuCxxJF/R7O7f4puDE8DcVLiXSwZc7TZrHXDRa43du33puDEoZ/wAjvcvHhyGIZ/yO9yeH
IYgx4e27d1yP1BsvLWDwZ0Uyh9VVB2W4y5Mx2XLf+h7lIm1FYHBSsldTcoMkBIaXNsHG/d2+Kb7X
mzkvJNoq0ji6khcd5YCfcplwBtddAXQBdAF0AXQBdAF0AXQCWI17qIR5YhIX3vd+WwFvYe9V69wq
LimscSalR8TF48DWm5t3mP1FcnmIkZfZYqmSflWkjlG7jbc0W+JUkEnHzB6cMpizKWOItl9Y7QvW
5FjFoajYIo2xsFmtAA8F7OHSANqANqAEBnJPFE9jJJGtc82aCdpXUmzjkk8GabVw6Iy4i3NPFGwi
WJjnAuHom2z4leazdKm5ik41Km4FNVzS4Uahwj5UZ9wOW4cQNl/YvNtN1YRk+Z6uEqTaXIm108lR
SU8kuXOTKDlFhscB9FS2kt2pBL3+ixYycqcm++JYpubd5j9RVipmKyPafnKjzBpapafAM3Uhwxkq
oo6hkD3ESP8AVGU2O/t/Qrqi2sTy5pPd5my4eidh1RPNV1LJZM7WhrmjKBluXbPbuClqRUUsCClN
ybxGMQLhRvLXFpuNrTY7wvNNYy8z3VbUHgGHlzqGEucXEt2lxuSuTzM7T84oUxLpsHFF8wKSGRkN
TUR1RVM8mKVEMkmaNoJa3KBb0rb1mW9adSrOL4I0qtOMacWuLFH9Nq/Kk1BXLz0z6FK19QM0PUTv
GTW5Q2GlAsXuaXfInz9X0/FNrVfaerDr9Emz9KXfuXKbm3eY/UVNUzECFKwuEU+V7mEzja02PqBW
bdJ8SGu2o+Q5RFz6Gnc5xLnRNJPebLsuLPccqEq3rel4h8HKWOmyGWqipb2lQlgk4SL11XwR/F6n
q8EVqHGXfuOYgPwb9p3t1BR08xJWyMlGWRn2BrJHtb6FwDsN32P+FnXVWcbqME/Jl22hF27bXeA3
iXTYOKP5gWpDIzOqaiOMP65quF2pY1prVOr+TVr6Ue+Ri/p1X5MmoLSvfTPoZ9r6jv3GaLqJ3jJr
cobDSgWL3NLvkT5+r6fim1qvtPVh1+iTZ+lLv3LlNzbvMfqKmqZiBClZzU3njQFatiC4yjdAB930
1/8Aib8AkuLJIZUJ1vW9LxD4OUsdNkMtVFOwUJYJWF2FbVlxsAyPb+r1NV4IrUMz79xyvymieQbg
lu2/5gvFLMiStkZIf61B/a+Ysq89bDv3L9r6Z98h3Eh+Ng4o/mBbEMjMypqI4w/rmq4XaljWmtU6
v5NWvpR75GL+m1fkyagtK99M+hn2vqO/cYoR/QneMmtyhsNKBYvc0u+QhP1fT8U2tV9p6sOv0SbP
0pd+5cpubd5j9RU1TMQIUrebm88aArVsQXGU8wOpfPA6ORrAIWta0gb9ltvuVW3ruvjJor2VxKvF
4rgc4g9kWJ0z3uDWBzSSdw2OV1zjCk3J4ElWUYVE5PBFCCop6jNyMjH5bXt2KCFSM8rxLji0k2uJ
EADm14IBBbFsPG5c2l5W779iPZ+s+/cdYAMBi2D1W6gu2eSPQ9XnGXUSf61B/a+YqF562HfuWrX0
z75DmJW+2wW3Zo/mBbEMjMypqI5w+33zU7rZTqWNaa1Tq/k1a+lHvkYv6bV93IyagtK99M+hn2vq
Biit9xO3XvJrKhsNKBYvc0u+QhP1fT8U2tV9p6sOv0SbP0pd+5cpubd5j9RU1TMQIUrObm88aArV
sQXGUTwGojhkkjeSHSloZs37CsmwqRWMHxZT2VSm6Mp4eWJ1j22UeDfqrd/6b9/wyLaeX+Pya4Hz
1Tws/cqmzOEv2PpLz/UnzSvZUPY02bKGhwtvsSR8VLtWtJYUuWGP9/8ADGs60o3saa4PH4ZVZ1DH
wt1BXrPJHoXLzjLqThKyR9GGkkxuja7Z28oFmXNSM7yO6+H/AEmsqkZ20t3liv6KGJdNg4o/mBbc
MjKFTURxh/XNTwnUsa01qnV/JrV9KPfIxf02r8mTUFpXvpn0M619QMUR/oTvGTWVDYaUCxe5pd8h
Cfq+n4ptar7T1Ydfok2fpS79y5T827zH6ipqmYgQpWc1N540BWrYguMpJw3ptN5v7Svn7TXQ2R6G
XV/gcx7nR4D6rVv/AE37/hmdtPL/AB+TXA+eqeFn7lU2Zll+x9Jef6k2p6W3/wB2lNraq6flmBa/
+jT6P4ZXZ1DHwt1Badllh0NK74y6/kkU/SGefHrCwo+qXUj2R6ap1fwijjZIeHNJa4NaQR2EOut2
vOVO3lKPH/qKd7Jwi5R4pfk4wRznVz3OJc4xXJPacyy9ntynJs2HJytqbfsvgyqZhDWz5gTyjXsF
u8uH8K/tCtGFHcfFozaFaNO6jF82O0PUTvGTW5LDSgXr3NLvkT5+r6fim1qvtPVh1+iTZ+lLv3Ll
PzbvMfqKmnmIBarhmeJGxxhwdIHg5gP9IH0U1GoocSOrBzWCEKTDquCoikdE0hj8xs8dxH1WZQtn
TqKbYsYO3t3Slxbx+DfEqWqrHgshDdg3vHt/lXbnCtS3F74lW8tpV1hF9+Zph0FTSPlc+EHOGgAP
HZf+VBaUvAT3nxNWvVVTDAUlw6sknDxE0AdheEvaX6ialF8sDNo0JU7qNdvyWPw/sdEdQMNZTch6
QAF847DdW7eapKKfItV/8jeHMRhw2sZK1xibYSNf647HA/RZytmqyqY+WOJ5sYu3ozhLi23/AChr
Eaeqqz6EAHogbXjvutCtJVKMqa4v7RXuqEqsWlz+znDqWqpJnSPhBuwNADx3qpa0fBbcnxL29/hh
T5pJfwjKqoKuecyNhaBmJ2vHaV7vYfqN3dfAofp5fqIVcfJPEbp4qmLDjTGAFxzbQ8drifqprZql
CMXyL1w/Fba5k/7srM7rxtyuJIHKbrlU61CdSrvuXljiQ2MZW7qObx3sMP7+y3A1zY/TFiXOda97
XcT9Vbk8XiSDKsnAQAgBACAEAIAQAgBACAEAIAQAgBACAEAIAQAgBACAEAIAQAgBACAEAIAQAgBA
CAEAIAQAgP/Z
</field>
<field name="datas_fname">activity graph 2012.jpg</field>
<field name="name">activity graph 2012</field>
</record>
<record id="message_video1" model="mail.message">
<field name="model">mail.group</field>
<field name="body">
Hi,&lt;br/&gt;
The beta OpenERP 7 is scheduled for November 12.&lt;br/&gt;
You will find attached the document for migration from version 6 to 7, and the activity graph for the current year. Good reading.&lt;br/&gt;
Sincerely
</field>
<field name="type">comment</field>
<field name="subtype_id" ref="mt_comment"/>
<field name="author_id" ref="base.partner_demo"/>
<field name="attachment_ids" eval="[(6, 0, [ref('message_video1_attachment1'), ref('message_video1_attachment2')])]"/>
<field name="notified_partner_ids" eval="[(6, 0, [ref('base.partner_demo'), ref('base.partner_root')])]"/>
</record>
<record id="message_video1_message1" model="mail.message">
<field name="model">mail.group</field>
<field name="body">
Thank you,&lt;br/&gt;
Could you prepare and send us also the document for version 7.1 which will come soon?&lt;br/&gt;
Sincerely
</field>
<field name="type">comment</field>
<field name="subtype_id" ref="mt_comment"/>
<field name="parent_id" ref="message_video1"/>
<field name="author_id" ref="base.partner_root"/>
<field name="notified_partner_ids" eval="[(6, 0, [ref('base.partner_demo'), ref('base.partner_root')])]"/>
</record>
<!-- Network admin & employee conversation -->
<record id="message_video0" model="mail.message">
<field name="model">mail.group</field>
<field name="body">I changed the infrastructure of networks, if there are still changes to be made please do not hesitate to contact me.</field>
<field name="type">comment</field>
<field name="subtype_id" ref="mt_comment"/>
<field name="author_id" ref="base.partner_root"/>
<field name="notified_partner_ids" eval="[(6, 0, [ref('base.partner_demo'), ref('base.partner_root')])]"/>
</record>
<record id="message_video0_message1" model="mail.message">
<field name="model">mail.group</field>
<field name="body">Thank you, the networks is perfect now ! Could you add a IP phone for Jhon ?</field>
<field name="parent_id" ref="message_video0"/>
<field name="type">comment</field>
<field name="subtype_id" ref="mt_comment"/>
<field name="author_id" ref="base.partner_demo"/>
<field name="notified_partner_ids" eval="[(6, 0, [ref('base.partner_demo'), ref('base.partner_root')])]"/>
</record>
<record id="message_video0_message2" model="mail.message">
<field name="model">mail.group</field>
<field name="body">It's right, his internal phone number is 0093</field>
<field name="parent_id" ref="message_video0"/>
<field name="type">comment</field>
<field name="subtype_id" ref="mt_comment"/>
<field name="author_id" ref="base.partner_root"/>
<field name="notified_partner_ids" eval="[(6, 0, [ref('base.partner_demo'), ref('base.partner_root')])]"/>
</record>
</data>
</openerp>

View File

@ -17,12 +17,11 @@
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subtype_id" ref="mail.mt_comment"/>
<field name="subject">Welcome to OpenERP!</field>
<field name="body">Your homepage is a summary of messages you received and key information about documents you follow.
The top menu bar contains all applications you installed. You can use this &lt;i&gt;Settings&lt;/i&gt; menu to install more applications, activate others features or give access to new users.
To setup your preferences (name, email signature, avatar), click on the top right corner.</field>
<field name="body"><![CDATA[<p>Your homepage is a summary of messages you received and key information about documents you follow.</p><p>
The top menu bar contains all applications you installed. You can use the <i>Settings</i> menu to install more applications, activate others features or give access to new users.</p><p>
To setup your preferences (name, email signature, avatar), click on the top right corner.</p>]]></field>
</record>
</data>
</openerp>

View File

@ -84,11 +84,13 @@ class mail_notification(osv.Model):
return False
def set_message_read(self, cr, uid, msg_ids, read=None, context=None):
""" Set a message and its child messages as (un)read for uid.
""" Set messages as (un)read. Technically, the notifications related
to uid are set to (un)read. If for some msg_ids there are missing
notifications (i.e. due to load more or thread parent fetching),
they are created.
:param bool read: read / unread
:param bool read: (un)read notification
"""
# TDE note: use child_of or front-end send correct values ?
user_pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0]
notif_ids = self.search(cr, uid, [
('partner_id', '=', user_pid),
@ -100,10 +102,9 @@ class mail_notification(osv.Model):
return self.write(cr, uid, notif_ids, {'read': read}, context=context)
# some messages do not have notifications: find which one, create notification, update read status
exist_notification = dict.fromkeys(msg_ids, False)
for notification in self.browse(cr, uid, notif_ids, context=context):
exist_notification[notification.message_id.id] = True
for msg_id in exist_notification.keys():
notified_msg_ids = [notification.message_id.id for notification in self.browse(cr, uid, notif_ids, context=context)]
to_create_msg_ids = list(set(msg_ids) - set(notified_msg_ids))
for msg_id in to_create_msg_ids:
self.create(cr, uid, {'partner_id': user_pid, 'read': read, 'message_id': msg_id}, context=context)
return self.write(cr, uid, notif_ids, {'read': read}, context=context)
@ -156,10 +157,10 @@ class mail_notification(osv.Model):
# 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 ''
# body_html = tools.append_content_to_html(body_html, quote_context, plaintext=False)
signature = msg.author_id and msg.author_id.user_ids and msg.author_id.user_ids[0].signature or ''
if signature:
body_html = tools.append_content_to_html(body_html, signature)
body_html = tools.append_content_to_html(body_html, signature, plaintext=True, container_tag='div')
mail_values = {
'mail_message_id': msg.id,

View File

@ -130,7 +130,7 @@ class mail_group(osv.Model):
params = {
'search_view_id': search_ref and search_ref[1] or False,
'domain': [('model', '=', 'mail.group'), ('res_id', '=', mail_group_id)],
'context': {'default_model': 'mail.group', 'default_res_id': mail_group_id},
'context': {'default_model': 'mail.group', 'default_res_id': mail_group_id, 'search_default_message_unread': True},
'res_model': 'mail.message',
'thread_level': 1,
}

View File

@ -84,7 +84,7 @@
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="message_ids" widget="mail_thread" options='{"thread_level": 1}'/>
<field name="message_ids" widget="mail_thread" options='{"thread_level": 1}' placeholder="Send a message to the group..."/>
</div>
</form>
</field>

View File

@ -25,6 +25,7 @@ import tools
from email.header import decode_header
from openerp import SUPERUSER_ID
from openerp.osv import osv, orm, fields
from openerp.tools import html_email_clean
from openerp.tools.translate import _
_logger = logging.getLogger(__name__)
@ -280,7 +281,7 @@ class mail_message(osv.Model):
return {'id': message.id,
'type': message.type,
'body': message.body,
'body': html_email_clean(message.body),
'model': message.model,
'res_id': message.res_id,
'record_name': message.record_name,
@ -633,6 +634,8 @@ class mail_message(osv.Model):
def create(self, cr, uid, values, context=None):
if not values.get('message_id') and values.get('res_id') and values.get('model'):
values['message_id'] = tools.generate_tracking_message_id('%(res_id)s-%(model)s' % values)
elif not values.get('message_id'):
values['message_id'] = tools.generate_tracking_message_id('private')
newid = super(mail_message, self).create(cr, uid, values, context)
self._notify(cr, SUPERUSER_ID, newid, context=context)
return newid
@ -763,7 +766,7 @@ class mail_message(osv.Model):
], 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
# remove me from notified partners, unless the message is written on my own 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'):

View File

@ -319,10 +319,12 @@ class mail_thread(osv.AbstractModel):
"""
assert isinstance(message, Message), 'message must be an email.message.Message at this point'
message_id = message.get('Message-Id')
references = decode_header(message, 'References')
in_reply_to = decode_header(message, 'In-Reply-To')
# 1. Verify if this is a reply to an existing thread
references = decode_header(message, 'References') or decode_header(message, 'In-Reply-To')
ref_match = references and tools.reference_re.search(references)
thread_references = references or in_reply_to
ref_match = thread_references and tools.reference_re.search(thread_references)
if ref_match:
thread_id = int(ref_match.group(1))
model = ref_match.group(2) or model
@ -333,6 +335,14 @@ class mail_thread(osv.AbstractModel):
message_id, model, thread_id, custom_values, uid)
return [(model, thread_id, custom_values, uid)]
# Verify this is a reply to a private message
message_ids = self.pool.get('mail.message').search(cr, uid, [('message_id', '=', in_reply_to)], limit=1, context=context)
if message_ids:
message = self.pool.get('mail.message').browse(cr, uid, message_ids[0], context=context)
_logger.debug('Routing mail with Message-Id %s: direct reply to a private message: %s, custom_values: %s, uid: %s',
message_id, message.id, custom_values, uid)
return [(False, 0, custom_values, uid)]
# 2. Look for a matching mail.alias entry
# Delivered-To is a safe bet in most modern MTAs, but we have to fallback on To + Cc values
# for all the odd MTAs out there, as there is no standard header for the envelope's `rcpt_to` value.
@ -376,14 +386,19 @@ class mail_thread(osv.AbstractModel):
def message_process(self, cr, uid, model, message, custom_values=None,
save_original=False, strip_attachments=False,
thread_id=None, context=None):
"""Process an incoming RFC2822 email message, relying on
``mail.message.parse()`` for the parsing operation,
and ``message_route()`` to figure out the target model.
""" Process an incoming RFC2822 email message, relying on
``mail.message.parse()`` for the parsing operation,
and ``message_route()`` to figure out the target model.
Once the target model is known, its ``message_new`` method
is called with the new message (if the thread record did not exist)
Once the target model is known, its ``message_new`` method
is called with the new message (if the thread record did not exist)
or its ``message_update`` method (if it did).
There is a special case where the target model is False: a reply
to a private message. In this case, we skip the message_new /
message_update step, to just post a new message using mail_thread
message_post.
:param string model: the fallback model to use if the message
does not match any of the currently configured mail aliases
(may be None if a matching alias is supposed to be present)
@ -425,15 +440,19 @@ class mail_thread(osv.AbstractModel):
for model, thread_id, custom_values, user_id in routes:
if self._name != model:
context.update({'thread_model': model})
model_pool = self.pool.get(model)
assert thread_id and hasattr(model_pool, 'message_update') or hasattr(model_pool, 'message_new'), \
"Undeliverable mail with Message-Id %s, model %s does not accept incoming emails" % \
(msg['message_id'], model)
if thread_id and hasattr(model_pool, 'message_update'):
model_pool.message_update(cr, user_id, [thread_id], msg, context=context)
if model:
model_pool = self.pool.get(model)
assert thread_id and hasattr(model_pool, 'message_update') or hasattr(model_pool, 'message_new'), \
"Undeliverable mail with Message-Id %s, model %s does not accept incoming emails" % \
(msg['message_id'], model)
if thread_id and hasattr(model_pool, 'message_update'):
model_pool.message_update(cr, user_id, [thread_id], msg, context=context)
else:
thread_id = model_pool.message_new(cr, user_id, msg, custom_values, context=context)
else:
thread_id = model_pool.message_new(cr, user_id, msg, custom_values, context=context)
model_pool.message_post(cr, uid, [thread_id], context=context, **msg)
assert thread_id == 0, "Posting a message without model should be with a null res_id, to create a private message."
model_pool = self.pool.get('mail.thread')
model_pool.message_post_user_api(cr, uid, [thread_id], context=context, content_subtype='html', **msg)
return thread_id
def message_new(self, cr, uid, msg_dict, custom_values=None, context=None):
@ -501,7 +520,7 @@ class mail_thread(osv.AbstractModel):
body = tools.ustr(body, encoding, errors='replace')
if message.get_content_type() == 'text/plain':
# text/plain -> <pre/>
body = tools.append_content_to_html(u'', body)
body = tools.append_content_to_html(u'', body, preserve=True)
else:
alternative = (message.get_content_type() == 'multipart/alternative')
for part in message.walk():
@ -516,7 +535,7 @@ class mail_thread(osv.AbstractModel):
# 2) text/plain -> <pre/>
if part.get_content_type() == 'text/plain' and (not alternative or not body):
body = tools.append_content_to_html(body, tools.ustr(part.get_payload(decode=True),
encoding, errors='replace'))
encoding, errors='replace'), preserve=True)
# 3) text/html -> raw
elif part.get_content_type() == 'text/html':
html = tools.ustr(part.get_payload(decode=True), encoding, errors='replace')
@ -556,7 +575,6 @@ class mail_thread(osv.AbstractModel):
"""
msg_dict = {
'type': 'email',
'subtype': 'mail.mt_comment',
'author_id': False,
}
if not isinstance(message, Message):
@ -588,7 +606,7 @@ class mail_thread(osv.AbstractModel):
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
msg_dict['partner_ids'] = [(4, partner_id) for partner_id in partner_ids]
if 'Date' in message:
date_hdr = decode(message.get('Date'))
@ -629,7 +647,8 @@ class mail_thread(osv.AbstractModel):
mail.message ID. Extra keyword arguments will be used as default
column values for the new mail.message record.
Auto link messages for same id and object
:param int thread_id: thread ID to post into, or list with one ID
:param int thread_id: thread ID to post into, or list with one ID;
if False/0, mail.message model will also be set as False
:param str body: body of the message, usually raw HTML that will
be sanitized
:param str subject: optional subject
@ -639,10 +658,13 @@ class mail_thread(osv.AbstractModel):
``(name,content)``, where content is NOT base64 encoded
:return: ID of newly created mail.message
"""
context = context or {}
attachments = attachments or []
if context is None:
context = {}
if attachments is None:
attachments = {}
assert (not thread_id) or isinstance(thread_id, (int, long)) or \
(isinstance(thread_id, (list, tuple)) and len(thread_id) == 1), "Invalid thread_id"
(isinstance(thread_id, (list, tuple)) and len(thread_id) == 1), "Invalid thread_id; should be 0, False, an ID or a list with one ID"
if isinstance(thread_id, (list, tuple)):
thread_id = thread_id and thread_id[0]
mail_message = self.pool.get('mail.message')
@ -682,7 +704,6 @@ class mail_thread(osv.AbstractModel):
# 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)
@ -707,18 +728,45 @@ 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, 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
def message_post_user_api(self, cr, uid, thread_id, body='', subject=False, parent_id=False,
attachment_ids=None, context=None, content_subtype='plaintext', **kwargs):
""" Wrapper on message_post, used for user input :
- mail gateway
- quick reply in Chatter (refer to mail.js), not
the mail.compose.message wizard
The purpose is to perform some pre- and post-processing:
- if body is plaintext: convert it into html
- if parent_id: handle reply to a previous message by adding the
parent partners to the message
- type and subtype: comment and mail.mt_comment by default
- attachment_ids: supposed not attached to any document; attach them
to the related document. Should only be set by Chatter.
"""
new_message_id = self.message_post(cr, uid, thread_id=thread_id, body=body, subject=subject, type='comment',
subtype='mail.mt_comment', parent_id=parent_id, context=context)
ir_attachment = self.pool.get('ir.attachment')
mail_message = self.pool.get('mail.message')
# HACK FIXME: Chatter: attachments linked to the document (not done JS-side), load the message
# 1. Pre-processing: body, partner_ids, type and subtype
if content_subtype == 'plaintext':
body = tools.plaintext2html(body)
partner_ids = kwargs.pop('partner_ids', [])
if parent_id:
parent_message = self.pool.get('mail.message').browse(cr, uid, parent_id, context=context)
partner_ids += [(4, partner.id) for partner in parent_message.partner_ids]
# TDE FIXME HACK: mail.thread -> private message
if self._name == 'mail.thread' and parent_message.author_id.id:
partner_ids.append((4, parent_message.author_id.id))
message_type = kwargs.pop('type', 'comment')
message_subtype = kwargs.pop('subtype', 'mail.mt_comment')
# 2. Post message
new_message_id = self.message_post(cr, uid, thread_id=thread_id, body=body, subject=subject, type=message_type,
subtype=message_subtype, parent_id=parent_id, context=context, partner_ids=partner_ids, **kwargs)
# 3. Post-processing
# HACK TDE FIXME: Chatter: attachments linked to the document (not done JS-side), load the message
if attachment_ids:
ir_attachment = self.pool.get('ir.attachment')
mail_message = self.pool.get('mail.message')
filtered_attachment_ids = ir_attachment.search(cr, SUPERUSER_ID, [
('res_model', '=', 'mail.compose.message'),
('res_id', '=', 0),

View File

@ -7,7 +7,7 @@
<field name="res_model">mail.message</field>
<field name="context">{
'default_model': 'res.users',
'default_res_id': uid
'default_res_id': uid,
}</field>
<field name="params" eval="&quot;{
'domain': [

View File

@ -42,4 +42,23 @@ class res_partner_mail(osv.Model):
'notification_email_send': lambda *args: 'comment'
}
def message_post(self, cr, uid, thread_id, body='', subject=None, type='notification',
subtype=None, parent_id=False, attachments=None, context=None, **kwargs):
""" Override related to res.partner. In case of email message, set it as
private:
- add the target partner in the message partner_ids
- set thread_id as None, because this will trigger the 'private'
aspect of the message (model=False, res_id=False)
"""
if isinstance(thread_id, (list, tuple)):
thread_id = thread_id[0]
if type == 'email':
partner_ids = kwargs.get('partner_ids', [])
if thread_id not in partner_ids:
partner_ids.append(thread_id)
kwargs['partner_ids'] = partner_ids
thread_id = False
return super(res_partner_mail, self).message_post(cr, uid, thread_id, body=body, subject=subject,
type=type, subtype=subtype, parent_id=parent_id, attachments=attachments, context=context, **kwargs)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -91,8 +91,10 @@ class res_users(osv.Model):
return user_id
def _create_welcome_message(self, cr, uid, user, context=None):
company_name = user.company_id.name if user.company_id else _('the company')
body = _('%s has joined %s.') % (user.name, company_name)
if not self.has_group(cr, uid, 'base.group_user'):
return False
company_name = user.company_id.name if user.company_id else ''
body = _('%s has joined the %s network.') % (user.name, company_name)
# TODO change SUPERUSER_ID into user.id but catch errors
return self.pool.get('res.partner').message_post(cr, SUPERUSER_ID, [user.partner_id.id],
body=body, context=context)
@ -111,7 +113,8 @@ class res_users(osv.Model):
alias_pool.unlink(cr, uid, alias_ids, context=context)
return res
def message_post_api(self, cr, uid, thread_id, body='', subject=False, parent_id=False, attachment_ids=None, context=None):
def message_post_user_api(self, cr, uid, thread_id, body='', subject=False, parent_id=False,
attachment_ids=None, context=None, content_subtype='plaintext', **kwargs):
""" Redirect the posting of message on res.users to the related partner.
This is done because when giving the context of Chatter on the
various mailboxes, we do not have access to the current partner_id.
@ -122,8 +125,8 @@ class res_users(osv.Model):
if isinstance(thread_id, (list, tuple)):
thread_id = thread_id[0]
partner_id = self.pool.get('res.users').read(cr, uid, thread_id, ['partner_id'], context=context)['partner_id'][0]
return self.pool.get('res.partner').message_post_api(cr, uid, partner_id, body=body, subject=subject,
parent_id=parent_id, attachment_ids=attachment_ids, context=context)
return self.pool.get('res.partner').message_post_user_api(cr, uid, partner_id, body=body, subject=subject,
parent_id=parent_id, attachment_ids=attachment_ids, context=context, content_subtype=content_subtype, **kwargs)
def message_post(self, cr, uid, thread_id, context=None, **kwargs):
""" Redirect the posting of message on res.users to the related partner.
@ -138,10 +141,6 @@ class res_users(osv.Model):
partner_id = self.pool.get('res.users').read(cr, uid, thread_id, ['partner_id'], context=context)['partner_id'][0]
return self.pool.get('res.partner').message_post(cr, uid, partner_id, context=context, **kwargs)
def message_update(self, cr, uid, ids, msg_dict, update_vals=None, context=None):
partner_id = self.pool.get('res.users').browse(cr, uid, ids)[0].partner_id.id
return self.pool.get('res.partner').message_update(cr, uid, [partner_id], msg_dict,
update_vals=update_vals, context=context)
class res_users_mail_group(osv.Model):
""" Update of res.users class

View File

@ -7,12 +7,13 @@ access_mail_mail_system,mail.mail.system,model_mail_mail,base.group_system,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
access_mail_notification_all,mail.notification.all,model_mail_notification,,1,0,0,0
access_mail_notification_aystem,mail.notification.system,model_mail_notification,base.group_system,1,1,1,1
access_mail_notification_group_user,mail.notification.user,model_mail_notification,base.group_user,1,1,1,0
access_mail_notification_system,mail.notification.system,model_mail_notification,base.group_system,1,1,1,1
access_mail_group_all,mail.group.all,model_mail_group,,1,0,0,0
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_alias_user,mail.alias.user,model_mail_alias,base.group_user,1,1,1,0
access_mail_alias_system,mail.alias.system,model_mail_alias,base.group_system,1,1,1,1
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
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
9 access_mail_notification_all mail.notification.all model_mail_notification 1 0 0 0
10 access_mail_notification_aystem access_mail_notification_group_user mail.notification.system mail.notification.user model_mail_notification base.group_system base.group_user 1 1 1 1 0
11 access_mail_notification_system mail.notification.system model_mail_notification base.group_system 1 1 1 1
12 access_mail_group_all mail.group.all model_mail_group 1 0 0 0
13 access_mail_group_user mail.group.user model_mail_group base.group_user 1 1 1 1
14 access_mail_alias_all mail.alias.all model_mail_alias 1 0 0 0
15 access_mail_alias_user mail.alias mail.alias.user model_mail_alias base.group_user 1 1 1 0
16 access_mail_alias_system mail.alias mail.alias.system model_mail_alias base.group_system 1 1 1 1
17 access_mail_message_subtype_all mail.message.subtype.all model_mail_message_subtype 1 0 0 0
18 access_mail_vote_all mail.vote.all model_mail_vote 1 1 1 1
19 access_mail_favorite_all mail.favorite.all model_mail_favorite 1 1 1 1

View File

@ -10,7 +10,7 @@
<field name="domain_force">['|', '|', ('public', '=', 'public'), ('message_follower_ids', 'in', [user.partner_id.id]), '&amp;', ('public','=','groups'), ('group_public_id','in', [g.id for g in user.groups_id])]</field>
</record>
<record id="mail_followers_read_own" model="ir.rule">
<record id="mail_followers_read_write_own" model="ir.rule">
<field name="name">mail.followers: read and write its own entries</field>
<field name="model_id" ref="model_mail_followers"/>
<field name="domain_force">[('partner_id', '=', user.partner_id.id)]</field>
@ -18,6 +18,14 @@
<field name="perm_unlink" eval="False"/>
</record>
<record id="mail_notification_read_write_own" model="ir.rule">
<field name="name">mail.notification: read and write its own entries</field>
<field name="model_id" ref="model_mail_notification"/>
<field name="domain_force">[('partner_id', '=', user.partner_id.id)]</field>
<field name="perm_create" eval="False"/>
<field name="perm_unlink" eval="False"/>
</record>
<!--
This rule can not be uncommented, because we have a more wide method in mail.message. When we implement a many2one_variable field, we will be able to uncomment this.
<record id="mail_message_read_partner_or_author" model="ir.rule">

View File

@ -87,6 +87,13 @@
margin-bottom: 0px;
margin-top: 2px;
}
.openerp .oe_mail .oe_msg .oe_msg_content .oe_msg_body p:first-of-type {
margin-top: 0px;
}
.openerp .oe_mail .oe_msg .oe_msg_content .oe_msg_body p {
margin-bottom: 0px;
}
/* a) Indented Messages */
@ -111,7 +118,7 @@
padding-top:2px;
}
.openerp .oe_mail .oe_msg.oe_msg_indented .oe_msg_footer{
margin-bottom: 0px;
margin-bottom: 5px;
}
/* b) Votes (likes) */

View File

@ -52,7 +52,7 @@
border-collapse: separate;
-moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
-webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
box-shadow: 0 1px 4px 3px rgba(0, 0, 0, 0.4);
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
-o-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
}

View File

@ -24,7 +24,7 @@ openerp.mail = function (session) {
*/
var context_keys = ['default_template_id', 'default_composition_mode',
'default_use_template', 'default_partner_ids', 'default_model',
'default_res_id', 'default_content_subtype', , 'default_subject',
'default_res_id', 'default_content_subtype', 'default_subject',
'default_body', 'active_id', 'lang', 'bin_raw', 'tz',
'active_model', 'edi_web_url_view', 'active_ids',
'default_attachment_ids']
@ -56,12 +56,14 @@ openerp.mail = function (session) {
/* Get an image in /web/binary/image?... */
get_image: function (session, model, field, id, resize) {
return session.prefix + '/web/binary/image?session_id=' + session.session_id + '&model=' + model + '&field=' + field + '&id=' + (id || '') + '&resize=' + (resize ? encodeURIComponent(resize) : '');
var r = resize ? encodeURIComponent(resize) : '';
id = id || '';
return session.url('/web/binary/image', {model: model, field: field, id: id, resize: r});
},
/* Get the url of an attachment {'id': id} */
get_attachment_url: function (session, attachment) {
return session.origin + '/web/binary/saveas?session_id=' + session.session_id + '&model=ir.attachment&field=datas&filename_field=datas_fname&id=' + attachment['id'];
return session.url('/web/binary/saveas', {model: 'ir.attachment', field: 'datas', filename_field: 'datas_fname', id: attachment['id']});
},
/**
@ -519,8 +521,6 @@ openerp.mail = function (session) {
on_compose_fullmail: function (default_composition_mode) {
if (default_composition_mode == 'reply') {
var context = {
'default_model': this.context.default_model,
'default_res_id': this.context.default_res_id,
'default_composition_mode': default_composition_mode,
'default_parent_id': this.id,
'default_body': mail.ChatterUtils.get_text2html(this.$el ? (this.$el.find('textarea:not(.oe_compact)').val() || '') : ''),
@ -530,7 +530,6 @@ openerp.mail = function (session) {
var context = {
'default_model': this.context.default_model,
'default_res_id': this.context.default_res_id,
'default_content_subtype': 'html',
'default_composition_mode': default_composition_mode,
'default_parent_id': this.id,
'default_body': mail.ChatterUtils.get_text2html(this.$el ? (this.$el.find('textarea:not(.oe_compact)').val() || '') : ''),
@ -590,7 +589,7 @@ openerp.mail = function (session) {
if (body.match(/\S+/)) {
//session.web.blockUI();
this.parent_thread.ds_thread.call('message_post_api', [
this.parent_thread.ds_thread.call('message_post_user_api', [
this.context.default_res_id,
mail.ChatterUtils.get_text2html(body),
false,
@ -599,16 +598,15 @@ openerp.mail = function (session) {
this.parent_thread.context
]).done(function (record) {
var thread = self.parent_thread;
if (self.options.display_indented_thread < self.thread_level && thread.parent_message) {
thread = thread.parent_message.parent_thread;
var thread = thread.parent_message.parent_thread;
}
var root = thread == self.options.root_thread;
// create object and attach to the thread object
thread.message_fetch([['id', 'child_of', [self.id]]], false, [record], function (arg, data) {
data[0].no_sorted = true;
var message = thread.create_message_object( data[0] );
// insert the message on dom
thread.insert_message( message, self.$el );
thread.insert_message( message, root ? undefined : self.$el, root );
if (thread.parent_message) {
self.$el.remove();
self.parent_thread.compose_message = null;
@ -728,7 +726,6 @@ openerp.mail = function (session) {
mail.ThreadMessage = mail.MessageCommon.extend({
template: 'mail.thread.message',
start: function () {
this._super.apply(this, arguments);
@ -1274,7 +1271,7 @@ openerp.mail = function (session) {
* The sort is define by the thread_level (O for newer on top).
* @param : {object} ThreadMessage object
*/
insert_message: function (message, dom_insert_after) {
insert_message: function (message, dom_insert_after, prepend) {
var self=this;
if (this.options.show_compact_message > this.thread_level) {
this.instantiate_compose_message();
@ -1286,6 +1283,8 @@ openerp.mail = function (session) {
if (dom_insert_after) {
message.insertAfter(dom_insert_after);
}if (prepend) {
message.prependTo(self.$el);
} else {
message.appendTo(self.$el);
}
@ -1698,7 +1697,6 @@ openerp.mail = function (session) {
views: [[false, 'form']],
target: 'new',
context: {
'default_content_subtype': 'html',
},
};
session.client.action_manager.do_action(action);
@ -1732,7 +1730,7 @@ openerp.mail = function (session) {
view_type: 'form',
views: [[false, 'form']],
target: 'new',
context: { 'default_content_subtype': 'html' },
context: {},
};
session.client.action_manager.do_action(action);
},

View File

@ -95,14 +95,6 @@
</t>
</t>
<t t-name="mail.thread.message.private">
<div>
<span class="oe_placeholder_checkbox_private"/>
<span class="oe_send_private">This email is private.</span>
<span class="oe_send_public">I wrote for contacts and all my followers.</span>
</div>
</t>
<!--
template to the recipients list
-->

View File

@ -18,6 +18,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from . import test_mail, test_mail_access_rights
checks = [

View File

@ -21,8 +21,8 @@
import tools
from openerp.tests import common
from openerp.tools.html_sanitize import html_sanitize
from openerp.addons.mail.tests import test_mail_mockup
from openerp.tools.mail import html_sanitize
MAIL_TEMPLATE = """Return-Path: <whatever-2a840@postmaster.twitter.com>
To: {to}
@ -84,43 +84,11 @@ Sylvie
"""
class TestMailMockups(common.TransactionCase):
def _mock_smtp_gateway(self, *args, **kwargs):
return True
def _init_mock_build_email(self):
self._build_email_args_list = []
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)
def setUp(self):
super(TestMailMockups, self).setUp()
# Install mock SMTP gateway
self._init_mock_build_email()
self._build_email = self.registry('ir.mail_server').build_email
self.registry('ir.mail_server').build_email = self._mock_build_email
self._send_email = self.registry('ir.mail_server').send_email
self.registry('ir.mail_server').send_email = self._mock_smtp_gateway
def tearDown(self):
# Remove mocks
self.registry('ir.mail_server').build_email = self._build_email
self.registry('ir.mail_server').send_email = self._send_email
super(TestMailMockups, self).tearDown()
class test_mail(TestMailMockups):
class test_mail(test_mail_mockup.TestMailMockups):
def _mock_send_get_mail_body(self, *args, **kwargs):
# def _send_get_mail_body(self, cr, uid, mail, partner=None, context=None)
body = tools.append_content_to_html(args[2].body_html, kwargs.get('partner').name if kwargs.get('partner') else 'No specific partner')
body = tools.append_content_to_html(args[2].body_html, kwargs.get('partner').name if kwargs.get('partner') else 'No specific partner', plaintext=False)
return body
def setUp(self):
@ -375,10 +343,10 @@ class test_mail(TestMailMockups):
_subject = 'Pigs'
_mail_subject = '%s posted on %s' % (user_admin.name, group_pigs.name)
_body1 = 'Pigs rules'
_mail_body1 = 'Pigs rules\n<pre>Admin</pre>\n'
_mail_bodyalt1 = 'Pigs rules\nAdmin'
_mail_body1 = 'Pigs rules\n<div><p>Admin</p></div>\n'
_mail_bodyalt1 = 'Pigs rules\nAdmin\n'
_body2 = '<html>Pigs rules</html>'
_mail_body2 = html_sanitize('<html>Pigs rules\n<pre>Admin</pre>\n</html>')
_mail_body2 = html_sanitize('<html>Pigs rules\n<div><p>Admin</p></div>\n</html>')
_mail_bodyalt2 = 'Pigs rules\nAdmin'
_attachments = [('First', 'My first attachment'), ('Second', 'My second attachment')]
@ -399,7 +367,7 @@ class test_mail(TestMailMockups):
# Test: sent_email: email send by server: correct subject, body, body_alternative
for sent_email in sent_emails:
self.assertEqual(sent_email['subject'], _subject, 'sent_email subject incorrect')
self.assertEqual(sent_email['body'], _mail_body1 + '\n<pre>Bert Tartopoils</pre>\n', 'sent_email body incorrect')
self.assertEqual(sent_email['body'], _mail_body1 + '\nBert Tartopoils\n', 'sent_email body incorrect')
# 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')
@ -495,7 +463,8 @@ class test_mail(TestMailMockups):
# 1. Comment group_pigs with body_text and subject
compose_id = mail_compose.create(cr, uid,
{'subject': _subject, 'body_text': _body_text, 'partner_ids': [(4, p_c_id), (4, p_d_id)]},
{'default_composition_mode': 'comment', 'default_model': 'mail.group', 'default_res_id': self.group_pigs_id})
{'default_composition_mode': 'comment', 'default_model': 'mail.group', 'default_res_id': self.group_pigs_id,
'default_content_subtype': 'plaintext'})
compose = mail_compose.browse(cr, uid, compose_id)
# Test: mail.compose.message: composition_mode, model, res_id
self.assertEqual(compose.composition_mode, 'comment', 'mail.compose.message incorrect composition_mode')

View File

@ -19,11 +19,11 @@
#
##############################################################################
from openerp.addons.mail.tests import test_mail
from openerp.addons.mail.tests import test_mail_mockup
from osv.orm import except_orm
class test_mail_access_rights(test_mail.TestMailMockups):
class test_mail_access_rights(test_mail_mockup.TestMailMockups):
def setUp(self):
super(test_mail_access_rights, self).setUp()

View File

@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Business Applications
# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.tests import common
class TestMailMockups(common.TransactionCase):
def _mock_smtp_gateway(self, *args, **kwargs):
return True
def _init_mock_build_email(self):
self._build_email_args_list = []
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)
def setUp(self):
super(TestMailMockups, self).setUp()
# Install mock SMTP gateway
self._init_mock_build_email()
self._build_email = self.registry('ir.mail_server').build_email
self.registry('ir.mail_server').build_email = self._mock_build_email
self._send_email = self.registry('ir.mail_server').send_email
self.registry('ir.mail_server').send_email = self._mock_smtp_gateway
def tearDown(self):
# Remove mocks
self.registry('ir.mail_server').build_email = self._build_email
self.registry('ir.mail_server').send_email = self._send_email
super(TestMailMockups, self).tearDown()

View File

@ -114,7 +114,7 @@ class mail_compose_message(osv.TransientModel):
_defaults = {
'composition_mode': 'comment',
'content_subtype': lambda self, cr, uid, ctx={}: 'plain',
'content_subtype': lambda self, cr, uid, ctx={}: 'html',
'body_text': lambda self, cr, uid, ctx={}: False,
'body': lambda self, cr, uid, ctx={}: '',
'subject': lambda self, cr, uid, ctx={}: False,
@ -135,7 +135,7 @@ class mail_compose_message(osv.TransientModel):
related to.
:param int res_id: id of the document record this mail is related to
"""
doc_name_get = self.pool.get(model).name_get(cr, uid, res_id, context=context)
doc_name_get = self.pool.get(model).name_get(cr, uid, [res_id], context=context)
if doc_name_get:
record_name = doc_name_get[0][1]
else:

View File

@ -6,11 +6,11 @@
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subtype_id" ref="mail.mt_comment"/>
<field name="subject">MRP application installed!</field>
<field name="body">Manage your manufacturing process with OpenERP by defining your bills of materials (BoM), routings and work centers.
This application supports complete integration and production scheduling for stockable goods, consumables, and services.
From the Manufacturing Settings, you can choose to compute production schedules periodically or just-in-time.</field>
<field name="body"><![CDATA[<p>Manage your manufacturing process with OpenERP by defining your bills of materials (BoM), routings and work centers.</p><p>
This application supports complete integration and production scheduling for stockable goods, consumables, and services.</p>
<p>From the Manufacturing Settings, you can choose to compute production schedules periodically or just-in-time.</p>]]></field>
</record>
<record id="sequence_mrp_prod_type" model="ir.sequence.type">

View File

@ -38,6 +38,7 @@ Notes can be found in the 'Home' menu.
'author': 'OpenERP SA',
'website': 'http://openerp.com',
'summary': 'Sticky notes, Collaborative, Memos',
'sequence': 9,
'depends': [
'mail',
],

334
addons/note/i18n/pt_BR.po Normal file
View File

@ -0,0 +1,334 @@
# Brazilian Portuguese 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-11-02 12:54+0000\n"
"PO-Revision-Date: 2012-11-14 04:29+0000\n"
"Last-Translator: Guilherme R. Santos <Unknown>\n"
"Language-Team: Brazilian Portuguese <pt_BR@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-11-15 04:42+0000\n"
"X-Generator: Launchpad (build 16265)\n"
#. module: note
#: sql_constraint:res.users:0
msgid "You can not have two users with the same login !"
msgstr "Você não pode ter dois usuários com o mesmo login!"
#. module: note
#: field:note.note,memo:0
msgid "Note Content"
msgstr "Conteúdo da Nota"
#. module: note
#: view:note.stage:0
msgid "Stages of Notes"
msgstr "Estágio das Notas"
#. module: note
#: model:ir.model,name:note.model_base_config_settings
msgid "base.config.settings"
msgstr "base.config.settings"
#. module: note
#: model:ir.model,name:note.model_note_tag
msgid "Note Tag"
msgstr "Tag da Nota"
#. module: note
#: model:res.groups,name:note.group_note_fancy
msgid "Notes / Fancy mode"
msgstr "Notas / Modo fantasia"
#. module: note
#: model:ir.model,name:note.model_note_note
#: view:note.note:0
msgid "Note"
msgstr "Nota"
#. module: note
#: view:note.note:0
msgid "Group By..."
msgstr "Agrupar Por..."
#. module: note
#: field:note.note,message_summary:0
msgid "Summary"
msgstr "Resumo"
#. module: note
#: field:note.note,message_follower_ids:0
msgid "Followers"
msgstr "Seguidores"
#. module: note
#: model:ir.actions.act_window,help:note.action_note_note
msgid ""
"<p class=\"oe_view_nocontent_create\">\n"
" Click to add a personal note.\n"
" </p><p>\n"
" Use notes to organize personal tasks or notes. All\n"
" notes are private; no one else will be able to see them. "
"However\n"
" you can share some notes with other people by inviting "
"followers\n"
" on the note. (Useful for meeting minutes, especially if\n"
" you activate the pad feature for collaborative writings).\n"
" </p><p>\n"
" You can customize how you process your notes/tasks by adding,\n"
" removing or modifying columns.\n"
" </p>\n"
" "
msgstr ""
"<p class=\"oe_view_nocontent_create\">\n"
" Clique para adicionar nota pessoal.\n"
" </p><p>\n"
" Use notas para organizar tarefas ou notas pessoais. Todas\n"
" notas são privadas; ninguém mais é capaz de vê-las. Contudo\n"
" você pode compartilhar algumas notas com outras pessoas "
"convidando seguidores\n"
" na nota. (Útil para atas de reunião, especialmente se\n"
" você ativar o recurso \"PAD\" para textos colaborativos).\n"
" </p><p>\n"
" Você pode customizar a forma como você processa suas "
"notas/tarefas adicionando,\n"
" removendo ou modificando colunas.\n"
" </p>\n"
" "
#. module: note
#: view:note.note:0
msgid "kanban note"
msgstr "nota kanban"
#. module: note
#: model:note.stage,name:note.demo_note_stage_01
#: model:note.stage,name:note.note_stage_01
msgid "Today"
msgstr "Hoje"
#. module: note
#: model:ir.model,name:note.model_res_users
msgid "Users"
msgstr "Usuários"
#. module: note
#: view:note.note:0
msgid "í"
msgstr "í"
#. module: note
#: view:note.stage:0
msgid "Stage of Notes"
msgstr "Estágios das Notas"
#. module: note
#: field:note.note,message_unread:0
msgid "Unread Messages"
msgstr "Mensagens não lidas"
#. module: note
#: field:note.note,current_partner_id:0
msgid "unknown"
msgstr "desconhecido"
#. module: note
#: view:note.note:0
msgid "By sticky note Category"
msgstr ""
#. module: note
#: help:note.note,message_unread:0
msgid "If checked new messages require your attention."
msgstr "Se marcado novas mensagens requerem sua atenção"
#. module: note
#: field:note.stage,name:0
msgid "Stage Name"
msgstr "Nome do Estágio"
#. module: note
#: field:note.note,message_is_follower:0
msgid "Is a Follower"
msgstr "É um seguidor"
#. module: note
#: view:note.note:0
msgid "title"
msgstr "título"
#. module: note
#: model:note.stage,name:note.demo_note_stage_02
#: model:note.stage,name:note.note_stage_02
msgid "Tomorrow"
msgstr "Amanhã"
#. module: note
#: view:note.note:0
#: field:note.note,open:0
msgid "Active"
msgstr "Ativo"
#. module: note
#: help:note.stage,user_id:0
msgid "Owner of the note stage."
msgstr "Proprietário do estágio da nota."
#. module: note
#: model:ir.ui.menu,name:note.menu_notes_stage
msgid "Categories"
msgstr "Categorias"
#. module: note
#: field:note.note,message_comment_ids:0
#: help:note.note,message_comment_ids:0
msgid "Comments and emails"
msgstr "Comentários e emails"
#. module: note
#: field:note.tag,name:0
msgid "Tag Name"
msgstr "Nome da Tag"
#. module: note
#: field:note.note,message_ids:0
msgid "Messages"
msgstr "Mensagens"
#. module: note
#: view:base.config.settings:0
#: model:ir.actions.act_window,name:note.action_note_note
#: model:ir.ui.menu,name:note.menu_note_notes
#: view:note.note:0
#: model:note.stage,name:note.note_stage_04
msgid "Notes"
msgstr "Notas"
#. module: note
#: model:note.stage,name:note.demo_note_stage_03
#: model:note.stage,name:note.note_stage_03
msgid "Later"
msgstr "Mais tarde"
#. module: note
#: model:ir.model,name:note.model_note_stage
msgid "Note Stage"
msgstr "Estágio da Nota"
#. module: note
#: view:note.note:0
msgid "dropdown menu"
msgstr "dropdown menu"
#. module: note
#: model:note.stage,name:note.demo_note_stage_04
msgid "Morning"
msgstr "Manhã"
#. module: note
#: help:note.stage,sequence:0
msgid "Used to order the note stages"
msgstr "Usado para ordenar os estágios das notas"
#. module: note
#: view:note.note:0
msgid "W"
msgstr "W"
#. module: note
#: field:note.note,stage_ids:0
msgid "Stages of Users"
msgstr "Estágios de Usuários"
#. module: note
#: field:note.note,name:0
msgid "Note Summary"
msgstr "Resumo da Nota"
#. module: note
#: model:ir.actions.act_window,name:note.action_note_stage
#: view:note.note:0
msgid "Stages"
msgstr "Estágios"
#. module: note
#: help:note.note,message_ids:0
msgid "Messages and communication history"
msgstr "Histórico de mensagens e comunicação"
#. module: note
#: view:note.note:0
msgid "Delete"
msgstr "Excluir"
#. module: note
#: field:note.note,color:0
msgid "Color Index"
msgstr "Índice de Cores"
#. module: note
#: field:note.note,sequence:0
#: field:note.stage,sequence:0
msgid "Sequence"
msgstr "Sequencia"
#. module: note
#: field:note.note,tag_ids:0
msgid "Tags"
msgstr "Tags"
#. module: note
#: view:note.note:0
msgid "Archive"
msgstr "Arquivo"
#. module: note
#: field:base.config.settings,module_note_pad:0
msgid "Use collaborative pads (etherpad)"
msgstr "Usar pads colaborativos (etherpad)"
#. module: note
#: help:note.note,message_summary:0
msgid ""
"Holds the Chatter summary (number of messages, ...). This summary is "
"directly in html format in order to be inserted in kanban views."
msgstr ""
#. module: note
#: field:base.config.settings,group_note_fancy:0
msgid "Use fancy layouts for notes"
msgstr "Usar leiautes fantasia para notas"
#. module: note
#: field:note.stage,user_id:0
msgid "Owner"
msgstr "Proprietário"
#. module: note
#: constraint:res.users:0
msgid "The chosen company is not in the allowed companies for this user"
msgstr ""
"A empresa escolhida não está entre as empresas habilitadas para este usuário"
#. module: note
#: view:note.note:0
#: field:note.note,stage_id:0
msgid "Stage"
msgstr "Estágio"
#. module: note
#: field:note.note,date_done:0
msgid "Date done"
msgstr "Data de conclusão"
#. module: note
#: field:note.stage,fold:0
msgid "Folded by Default"
msgstr "Dobrado por Padrão"

View File

@ -20,9 +20,7 @@
##############################################################################
from openerp.osv import osv, fields
from tools.translate import _
import re
from openerp.tools.misc import html2plaintext
from openerp.tools import html2plaintext
class note_stage(osv.osv):
""" Category of Note """

View File

@ -6,6 +6,10 @@
<field model="ir.model" ref="model_note_note" name="model_id"/>
<field name="domain_force">[('message_follower_ids','=',user.partner_id.id)]</field>
<field eval="True" name="global"/>
<field eval="1" name="perm_unlink"/>
<field eval="0" name="perm_write"/>
<field eval="1" name="perm_read"/>
<field eval="0" name="perm_create"/>
</record>
<record id="note_stage_rule_global" model="ir.rule">

View File

@ -6,7 +6,7 @@ import string
import urllib2
import logging
from tools.translate import _
from openerp.tools.misc import html2plaintext
from openerp.tools import html2plaintext
from py_etherpad import EtherpadLiteClient
_logger = logging.getLogger(__name__)

View File

@ -20,10 +20,10 @@
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subtype_id" ref="mail.mt_comment"/>
<field name="subject">Point of Sale application installed!</field>
<field name="body">Record sale orders, register payments, compute change to return, create invoices, and manage refunds through a specific web touch-screen interface.
If you install the PoS proxy you will be able to interface OpenERP with retail hardware: barcode scanners, printers, cash registers, weighing machines, credit card payment terminals.</field>
<field name="body"><![CDATA[<p>Record sale orders, register payments, compute change to return, create invoices, and manage refunds through a specific web touch-screen interface.</p>
<p>If you install the PoS proxy you will be able to interface OpenERP with retail hardware: barcode scanners, printers, cash registers, weighing machines, credit card payment terminals.</p>]]></field>
</record>
<record id="unreferenced_product" model="product.product">

View File

@ -320,7 +320,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
module.Product = Backbone.Model.extend({
get_image_url: function(){
return '/web/binary/image?session_id='+instance.session.session_id+'&model=product.product&field=image&id='+this.get('id');
return instance.session.url('/web/binary/image', {model: 'product.product', field: 'image', id: this.get('id')});
},
});

View File

@ -474,7 +474,7 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
},
get_image_url: function(category){
return '/web/binary/image?session_id='+instance.session.session_id+'&model=pos.category&field=image&id='+category.id;
return instance.session.url('/web/binary/image', {model: 'pos.category', field: 'image', id: category.id});
},
renderElement: function(){

View File

@ -36,5 +36,5 @@ class mail_mail(osv.Model):
if partner:
context = dict(context or {}, signup_valid=True)
partner = self.pool.get('res.partner').browse(cr, uid, partner.id, context)
body = tools.append_content_to_html(body, "Log in our portal at: %s" % partner.signup_url)
body = tools.append_content_to_html(body, ("<div><p>Log in our portal at: %s</p></div>" % partner.signup_url), plaintext=False)
return body

View File

@ -1,17 +1,22 @@
<?xml version="1.0"?>
<openerp>
<data>
<data noupdate="1">
<!-- Create a portal member attached to a partner -->
<record id="demo_user0" model="res.users">
<!-- Create a partner, that is also a portal user -->
<record id="partner_demo_portal" model="res.partner">
<field name="name">Demo Portal User</field>
<field name="login">portal</field>
<field name="password">portal</field>
<!-- Avoid auto-including this user in any default group -->
<field name="groups_id" eval="[(5,)]"/>
<field name="email">demo@portal.example.com</field>
<field name="supplier" eval="False"/>
<field name="customer" eval="True"/>
<field name="email">demo@portal.wrong.address</field>
</record>
<record id="demo_user0" model="res.users">
<field name="partner_id" ref="partner_demo_portal"/>
<field name="login">portal</field>
<field name="password">portal</field>
<field name="signature">--
Mr Demo Portal</field>
<!-- Avoid auto-including this user in any default group -->
<field name="groups_id" eval="[(5,)]"/>
</record>
<!-- Add the demo user to the portal (and therefore to the portal member group) -->
@ -24,33 +29,41 @@
<field name="subject">Our company's first blog-post !</field>
<field name="model">mail.group</field>
<field name="res_id" ref="company_news_feed"/>
<field name="body"><![CDATA[Hello, and welcome to our company's portal !
Lorem ipsum <b>sit amet</b>, consectetur <em>adipiscing elit</em>. Pellentesque et quam sapien, in sagittis tellus.
Praesent vel massa sed massa consequat egestas in tristique orci. Praesent iaculis libero et neque vehicula iaculis. Vivamus placerat tincidunt orci ac ornare. Proin ut dolor fringilla velit ultricies consequat. Maecenas sit amet ipsum non leo interdum imperdiet. Donec sapien mi.
Fusce tempus elit volutpat mi auctor adipiscing. Nam congue luctus suscipit. Sed tellus libero, venenatis ut mollis ut, luctus quis dui. Sed rhoncus pulvinar orci in consectetur.
Nulla turpis leo, rhoncus ut egestas sit amet, consectetur vitae urna. Mauris in dolor in sapien tempus vehicula.]]></field>
<field name="body"><![CDATA[<p>Hello, and welcome to our company's portal !</p>
<p>It is a great pleasure to announce you the creation of our portal by writing this first news! As you may have seen, a new discussion group is now present under your 'My groups' menu: <b>Company's News</b>. We will post news about the company and its employees in this discussion group. Moreover, we will be able to communicate with our partners that are given the opportunity to join us in our portal.</p>
<p>A new era of communication has begun! <b>Feel free to post your feelings about our portal by replying on this message!</b></p>]]></field>
<field name="type">comment</field>
<field name="subtype_id" ref="mail.mt_comment"/>
<field name="author_id" ref="base.partner_root"/>
</record>
<record id="message_company_news0_comment0" model="mail.message">
<field name="model">mail.group</field>
<field name="res_id" ref="company_news_feed"/>
<field name="body"><![CDATA[Great first blogpost ! (first comment)]]></field>
<field name="body"><![CDATA[<p>As your first portal member, I am very pleased to be able to be able to communicate directly with you. Be sure I'll read all news carefully!</p>]]></field>
<field name="parent_id" ref="message_company_news0"/>
<field name="type">comment</field>
<field name="author_id" ref="base.res_partner_1"/>
<field name="subtype_id" ref="mail.mt_comment"/>
<field name="author_id" ref="partner_demo_portal"/>
</record>
<record id="message_company_news0_comment1" model="mail.message">
<field name="model">mail.group</field>
<field name="res_id" ref="company_news_feed"/>
<field name="body"><![CDATA[Thanks ! (second comment)]]></field>
<field name="body"><![CDATA[<p>That's good news! As said by <i>Demo Portal User</i> in the previous post, I'm looking forward to hearing from you!</p>]]></field>
<field name="parent_id" ref="message_company_news0"/>
<field name="type">comment</field>
<field name="subtype_id" ref="mail.mt_comment"/>
<field name="author_id" ref="base.res_partner_1"/>
</record>
<record id="message_company_news0_comment2" model="mail.message">
<field name="model">mail.group</field>
<field name="res_id" ref="company_news_feed"/>
<field name="body"><![CDATA[<p>This feature is realy great! We will be able to communicate directly to our partners!</p>]]></field>
<field name="parent_id" ref="message_company_news0"/>
<field name="type">comment</field>
<field name="subtype_id" ref="mail.mt_comment"/>
<field name="author_id" ref="base.partner_demo"/>
</record>

View File

@ -19,12 +19,11 @@
#
##############################################################################
from openerp.addons.mail.tests import test_mail
from openerp.tools import append_content_to_html
from openerp.addons.mail.tests import test_mail_mockup
from osv.orm import except_orm
class test_portal(test_mail.TestMailMockups):
class test_portal(test_mail_mockup.TestMailMockups):
def setUp(self):
super(test_portal, self).setUp()

View File

@ -24,10 +24,9 @@ import random
from osv import osv, fields
from tools.translate import _
from tools.misc import email_re
from tools import email_re
from openerp import SUPERUSER_ID
from base.res.res_partner import _lang_get
_logger = logging.getLogger(__name__)
# welcome email sent to portal users

View File

@ -7,6 +7,10 @@
<field ref="crm_claim.model_crm_claim" name="model_id"/>
<field name="domain_force">[('message_follower_ids','in', [user.partner_id.id])]</field>
<field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
<field eval="1" name="perm_unlink"/>
<field eval="1" name="perm_write"/>
<field eval="1" name="perm_read"/>
<field eval="0" name="perm_create"/>
</record>
</data>

View File

@ -7,6 +7,10 @@
<field ref="project.model_project_task" name="model_id"/>
<field name="domain_force">[('message_follower_ids','in', [user.partner_id.id])]</field>
<field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
<field eval="1" name="perm_unlink"/>
<field eval="1" name="perm_write"/>
<field eval="1" name="perm_read"/>
<field eval="0" name="perm_create"/>
</record>
</data>

View File

@ -7,6 +7,10 @@
<field ref="project_issue.model_project_issue" name="model_id"/>
<field name="domain_force">[('message_follower_ids','in', [user.partner_id.id])]</field>
<field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
<field eval="1" name="perm_unlink"/>
<field eval="1" name="perm_write"/>
<field eval="1" name="perm_read"/>
<field eval="0" name="perm_create"/>
</record>
</data>

View File

@ -20,6 +20,10 @@ their documents through the portal.</field>
<field name="model_id" ref="sale.model_sale_order"/>
<field name="domain_force">[('message_follower_ids','in',[user.partner_id.id])]</field>
<field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
<field eval="1" name="perm_unlink"/>
<field eval="1" name="perm_write"/>
<field eval="1" name="perm_read"/>
<field eval="0" name="perm_create"/>
</record>
<record id="portal_stock_picking_user_rule" model="ir.rule">

View File

@ -35,7 +35,7 @@ This module shows the basic processes involved in the selected modules and in th
""",
'author': 'OpenERP SA',
'website': 'http://www.openerp.com',
'depends': ['base'],
'depends': ['web'],
'data': [
'security/ir.model.access.csv',
'process_view.xml'

View File

@ -56,11 +56,12 @@ class product_product(osv.osv):
sum(l.price_unit * l.quantity)/sum(l.quantity) as avg_unit_price,
sum(l.quantity) as num_qty,
sum(l.quantity * (l.price_subtotal/l.quantity)) as total,
sum(l.quantity * product.list_price) as sale_expected,
sum(l.quantity * product.standard_price) as normal_cost
sum(l.quantity * pt.list_price) as sale_expected,
sum(l.quantity * pt.standard_price) as normal_cost
from account_invoice_line l
left join account_invoice i on (l.invoice_id = i.id)
left join product_template product on (product.id=l.product_id)
left join product_product product on (product.id=l.product_id)
left join product_template pt on (pt.id=product.product_tmpl_id)
where l.product_id = %s and i.state in %s and i.type IN %s and (i.date_invoice IS NULL or (i.date_invoice>=%s and i.date_invoice<=%s))
"""
invoice_types = ('out_invoice', 'in_refund')

View File

@ -125,11 +125,11 @@
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subtype_id" ref="mail.mt_comment"/>
<field name="subject">Project Management application installed!</field>
<field name="body">Manage multi-level projects and tasks. You can delegate tasks, track task work, and review your planning.
You can manage todo lists on tasks by installing the "Todo Lists" application, supporting the Getting Things Done (GTD) methodology.
You can also manage issues/bugs in projects by installing the "Issue Tracker" application.</field>
<field name="body"><![CDATA[<p>Manage multi-level projects and tasks. You can delegate tasks, track task work, and review your planning.</p>
<p>You can manage todo lists on tasks by installing the <i>Todo Lists</i> application, supporting the Getting Things Done (GTD) methodology.</p>
<p>You can also manage issues/bugs in projects by installing the "Issue Tracker" application.</p>]]></field>
</record>
</data>
</openerp>

View File

@ -21,31 +21,15 @@
<field name="name">Usability</field>
</record>
<!-- Projects -->
<record id="project_project_internal" model="project.project">
<field name="name">Internal Projects</field>
<field name="parent_id" ref="all_projects_account"/>
<field name="user_id" ref="base.user_root"/>
<field name="alias_model">project.task</field>
<field name="type_ids" eval="[(6, 0, [ref('project_tt_specification'),ref('project_tt_development'),ref('project_tt_testing'),ref('project_tt_merge'),ref('project_tt_deployment')])]"/>
</record>
<record id="project_project_customer" model="project.project">
<field name="name">Customer Projects</field>
<field name="parent_id" ref="all_projects_account"/>
<field name="user_id" ref="base.user_root"/>
<field name="alias_model">project.task</field>
<field name="type_ids" eval="[(6, 0, [ref('project_tt_analysis'),ref('project_tt_specification'),ref('project_tt_negotiation'),ref('project_tt_development'),ref('project_tt_testing'),ref('project_tt_deployment')])]"/>
</record>
<record id="project_project_1" model="project.project">
<field name="date_start" eval="time.strftime('%Y-%m-01 10:00:00')"/>
<field name="state">open</field>
<field name="type">normal</field>
<field name="name">The Jackson Group's Project</field>
<field name="color">3</field>
<field name="partner_id" ref="base.res_partner_10"/>
<field name="parent_id" ref="all_projects_account"/>
<field name="privacy_visibility">followers</field>
<field name="privacy_visibility">public</field>
<field name="members" eval="[(6, 0, [
ref('base.user_root'),
ref('base.user_demo')])]"/>
@ -58,6 +42,7 @@
<record id="project_project_2" model="project.project">
<field name="name">Research &amp; Development</field>
<field name="parent_id" ref="all_projects_account"/>
<field name="privacy_visibility">public</field>
<field name="user_id" ref="base.user_demo"/>
<field name="alias_model">project.task</field>
<field name="type_ids" eval="[(6, 0, [ref('project_tt_specification'),ref('project_tt_development'),ref('project_tt_testing'),ref('project_tt_merge'),ref('project_tt_deployment')])]"/>
@ -69,6 +54,7 @@
<field name="name">E-Learning Integration</field>
<field name="user_id" ref="base.user_demo"/>
<field name="alias_model">project.task</field>
<field name="privacy_visibility">public</field>
<field name="members" eval="[(6, 0, [
ref('base.user_root'),
ref('base.user_demo')])]"/>

View File

@ -24,7 +24,7 @@
'name': 'Todo Lists',
'version': '1.0',
'category': 'Project Management',
'sequence': 9,
'sequence': 100,
'summary': 'Personal Tasks, Contexts, Timeboxes',
'description': """
Implement concepts of the "Getting Things Done" methodology

View File

@ -30,9 +30,10 @@
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subtype_id" ref="mail.mt_comment"/>
<field name="subject">Todo Lists application installed!</field>
<field name="body">Add todo items on project tasks, to help you organize your work.
This application supports the Getting Things Done (GTD) methodology, based on David Allen's book.</field>
<field name="body"><![CDATA[<p>Add todo items on project tasks, to help you organize your work.</p><p>
This application supports the Getting Things Done (GTD) methodology, based on David Allen's book.</p>]]></field>
</record>
</data>

View File

@ -36,10 +36,11 @@
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subtype_id" ref="mail.mt_comment"/>
<field name="subject">Issue Tracker application installed!</field>
<field name="body">Manage the issues you might face in a project, such as bugs in a system, client complaints or material breakdowns.
You can record issues, assign them to a responsible person, and keep track of their status as they evolve over time.
Access all issues from the top Project menu, and access the issues of a specific project via the projects gallery view.</field>
<field name="body"><![CDATA[<p>Manage the issues you might face in a project, such as bugs in a system, client complaints or material breakdowns.</p><p>
You can record issues, assign them to a responsible person, and keep track of their status as they evolve over time.</p><p>
Access all issues from the top Project menu, and access the issues of a specific project via the projects gallery view.</p>]]></field>
</record>
<!-- Mail subtypes -->

View File

@ -1,5 +1,24 @@
<?xml version="1.0"?>
<openerp>
<data>
<record id="project.project_project_1" model="project.project">
<field name="use_issues" eval="True"/>
</record>
<record id="project.project_project_2" model="project.project">
<field name="use_issues" eval="True"/>
</record>
<record id="project.project_project_3" model="project.project">
<field name="use_issues" eval="True"/>
</record>
<record id="project.project_project_4" model="project.project">
<field name="use_issues" eval="True"/>
</record>
<record id="project.project_project_5" model="project.project">
<field name="use_issues" eval="True"/>
</record>
</data>
<data noupdate="1">
<!-- Categories -->

View File

@ -121,8 +121,8 @@
<xpath expr="//div[contains(@class, 'oe_kanban_project_list')]" position="inside">
<a t-if="record.use_phases.raw_value"
name="%(act_project_phases)d" type="action">
<span t-if="record.phase_count.raw_value gt 1">Phases(<field name="phase_count"/>)</span>
<span t-if="record.phase_count.raw_value lt 2">Phase(<field name="phase_count"/>)</span>
<span t-if="record.phase_count.raw_value gt 1"><field name="phase_count"/> Phases</span>
<span t-if="record.phase_count.raw_value lt 2"><field name="phase_count"/> Phase</span>
</a>
</xpath>
</field>

View File

@ -7,10 +7,10 @@
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subtype_id" ref="mail.mt_comment"/>
<field name="subject">Purchase Management application installed!</field>
<field name="body">From the top menu Purchases, create purchase orders to buy products from your suppliers, enter supplier invoices and manage payments.
You can also manage purchase requisitions, see also the Purchase Settings.</field>
<field name="body"><![CDATA[<p>From the top menu Purchases, create purchase orders to buy products from your suppliers, enter supplier invoices and manage payments.</p>
<p>You can also manage purchase requisitions, see also the Purchase Settings.</p>]]></field>
</record>
<record id="req_link_purchase_order" model="res.request.link">

View File

@ -38,10 +38,10 @@
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subtype_id" ref="mail.mt_comment"/>
<field name="subject">Sales Management application installed!</field>
<field name="body">This application lets you create and send quotations and process your sales orders; from delivery to invoicing.
If you need to manage your sales pipeline (leads, opportunities, phonecalls), the &lt;i&gt;CRM&lt;/i&gt; application may be useful. Use the Settings menu to install it.</field>
<field name="body"><![CDATA[<p>This application lets you create and send quotations and process your sales orders; from delivery to invoicing.</p>
<p>If you need to manage your sales pipeline (leads, opportunities, phonecalls), the <i>CRM</i> application may be useful. Use the Settings menu to install it.</p>]]></field>
</record>
</data>
</openerp>

View File

@ -311,7 +311,7 @@
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="message_ids" widget="mail_thread"/>
<field name="message_ids" widget="mail_thread" placeholder="Share a message..."/>
</div>
</form>
</field>

View File

@ -2878,7 +2878,7 @@ class stock_inventory(osv.osv):
if change:
location_id = line.product_id.product_tmpl_id.property_stock_inventory.id
value = {
'name': 'INV:' + str(line.inventory_id.id) + ':' + line.inventory_id.name,
'name': _('INV:') + (line.inventory_id.name or ''),
'product_id': line.product_id.id,
'product_uom': line.product_uom.id,
'prodlot_id': lot_id,

View File

@ -6,9 +6,10 @@
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subtype_id" ref="mail.mt_comment"/>
<field name="subject">Warehouse Management application installed!</field>
<field name="body">Manage your product inventoy and stock locations: you can control stock moves history and planning,
watch your stock valuation, and track production lots upstream and downstream (based on serial numbers).</field>
<field name="body"><![CDATA[<p>Manage your product inventoy and stock locations: you can control stock moves history and planning,
watch your stock valuation, and track production lots upstream and downstream (based on serial numbers).</p>]]></field>
</record>
<record id="stock_journal_sequence" model="ir.sequence">

View File

@ -283,10 +283,11 @@
<field name="model">stock.tracking</field>
<field name="field_parent">child_ids</field>
<field name="arch" type="xml">
<tree colors="grey:not active" string="Packs">
<tree colors="grey:active == False" string="Packs">
<field name="name"/>
<field name="serial"/>
<field name="date"/>
<field name="active" invisible="1"/>
</tree>
</field>
</record>
@ -913,7 +914,7 @@
<xpath expr="/form/sheet" position="after">
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
<field name="message_ids" widget="mail_thread"/>
</div>
</xpath>
</data>
@ -1039,7 +1040,7 @@
<xpath expr="/form/sheet" position="after">
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
<field name="message_ids" widget="mail_thread"/>
</div>
</xpath>
</data>

View File

@ -10,7 +10,7 @@
<field name="new_quantity" />
<field name="product_id" invisible="1"/>
<field name="location_id" groups="stock.group_locations"/>
<field name="prodlot_id" groups="stock.group_tracking_lot"/>
<field name="prodlot_id" context="{'search_default_product_id':product_id,'default_product_id':product_id}" groups="stock.group_tracking_lot"/>
</group>
<footer>
<button name="change_product_qty" string="_Apply" type="object" class="oe_highlight"/>

View File

@ -20,7 +20,7 @@ openerp.web_linkedin = function(instance) {
var tag = document.createElement('script');
tag.type = 'text/javascript';
tag.src = "http://platform.linkedin.com/in.js";
tag.innerHTML = 'api_key : ' + self.api_key + '\nauthorize : true';
tag.innerHTML = 'api_key : ' + self.api_key + '\nauthorize : true\nscope: r_network r_contactinfo';
document.getElementsByTagName('head')[0].appendChild(tag);
self.linkedin_added = true;
$(tag).load(function() {
@ -107,7 +107,7 @@ openerp.web_linkedin = function(instance) {
}
to_change.website = entity.websiteUrl;
to_change.phone = false;
_.each(entity.locations.values || [], function(el) {
_.each((entity.locations || {}).values || [], function(el) {
to_change.phone = el.contactInfo.phone1;
});
var children_def = $.Deferred();