diff --git a/addons/account/account_invoice.py b/addons/account/account_invoice.py
index 409551585fa..3e86c4963b7 100644
--- a/addons/account/account_invoice.py
+++ b/addons/account/account_invoice.py
@@ -432,7 +432,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
diff --git a/addons/account/account_invoice_view.xml b/addons/account/account_invoice_view.xml
index 4feb97c2f5f..d3697b13ea9 100644
--- a/addons/account/account_invoice_view.xml
+++ b/addons/account/account_invoice_view.xml
@@ -436,7 +436,7 @@
-
+
diff --git a/addons/account/tests/__init__.py b/addons/account/tests/__init__.py
new file mode 100644
index 00000000000..11fe4186db6
--- /dev/null
+++ b/addons/account/tests/__init__.py
@@ -0,0 +1,4 @@
+from . import test_tax
+
+fast_suite = [test_tax,
+ ]
diff --git a/addons/account/tests/test_tax.py b/addons/account/tests/test_tax.py
new file mode 100644
index 00000000000..a172a17e30d
--- /dev/null
+++ b/addons/account/tests/test_tax.py
@@ -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)
diff --git a/addons/account/wizard/account_financial_report_view.xml b/addons/account/wizard/account_financial_report_view.xml
index 8388284be4a..507809e1961 100644
--- a/addons/account/wizard/account_financial_report_view.xml
+++ b/addons/account/wizard/account_financial_report_view.xml
@@ -14,15 +14,19 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/account/wizard/account_open_closed_fiscalyear.py b/addons/account/wizard/account_open_closed_fiscalyear.py
index b8d64fac0b5..1b5622a589d 100644
--- a/addons/account/wizard/account_open_closed_fiscalyear.py
+++ b/addons/account/wizard/account_open_closed_fiscalyear.py
@@ -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:
diff --git a/addons/account/wizard/account_open_closed_fiscalyear_view.xml b/addons/account/wizard/account_open_closed_fiscalyear_view.xml
index c2c271af41b..d4cfd398920 100644
--- a/addons/account/wizard/account_open_closed_fiscalyear_view.xml
+++ b/addons/account/wizard/account_open_closed_fiscalyear_view.xml
@@ -5,14 +5,18 @@
account.open.closed.fiscalyear.formaccount.open.closed.fiscalyear
-
diff --git a/addons/account/wizard/account_report_account_balance_view.xml b/addons/account/wizard/account_report_account_balance_view.xml
index b2c8ccd3011..3609ee3b4de 100644
--- a/addons/account/wizard/account_report_account_balance_view.xml
+++ b/addons/account/wizard/account_report_account_balance_view.xml
@@ -9,8 +9,7 @@
-
-
+
diff --git a/addons/account_accountant/account_accountant_data.xml b/addons/account_accountant/account_accountant_data.xml
index cf143b1bb58..c7d6eb80bc6 100644
--- a/addons/account_accountant/account_accountant_data.xml
+++ b/addons/account_accountant/account_accountant_data.xml
@@ -26,12 +26,10 @@
mail.groupnotification
+ Accounting and Finance application installed!
- 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.
- ]]>
+ 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.
+
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.
]]>
diff --git a/addons/account_bank_statement_extensions/account_bank_statement_view.xml b/addons/account_bank_statement_extensions/account_bank_statement_view.xml
index 3d5560856a3..adc2963c803 100644
--- a/addons/account_bank_statement_extensions/account_bank_statement_view.xml
+++ b/addons/account_bank_statement_extensions/account_bank_statement_view.xml
@@ -72,12 +72,12 @@
-
+
-
-
+
+
@@ -100,8 +100,8 @@
-
-
+
+
diff --git a/addons/account_voucher/account_voucher.py b/addons/account_voucher/account_voucher.py
index b0c53b72835..32be8c34929 100644
--- a/addons/account_voucher/account_voucher.py
+++ b/addons/account_voucher/account_voucher.py
@@ -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):
diff --git a/addons/account_voucher/account_voucher_data.xml b/addons/account_voucher/account_voucher_data.xml
index 3d4252e697d..fc008e479e9 100644
--- a/addons/account_voucher/account_voucher_data.xml
+++ b/addons/account_voucher/account_voucher_data.xml
@@ -7,12 +7,10 @@
mail.groupnotification
+ eInvoicing & Payments application installed!
- 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.
- ]]>
+ 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.
+
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.
]]>
diff --git a/addons/analytic/analytic.py b/addons/analytic/analytic.py
index 1c9a095d6ed..708f9b3b196 100644
--- a/addons/analytic/analytic.py
+++ b/addons/analytic/analytic.py
@@ -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),
diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py
index 45ab0c4fbb1..54284dee4da 100644
--- a/addons/audittrail/audittrail.py
+++ b/addons/audittrail/audittrail.py
@@ -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
diff --git a/addons/auth_anonymous/static/src/js/auth_anonymous.js b/addons/auth_anonymous/static/src/js/auth_anonymous.js
index 8a78aca479c..6768bc63ff9 100644
--- a/addons/auth_anonymous/static/src/js/auth_anonymous.js
+++ b/addons/auth_anonymous/static/src/js/auth_anonymous.js
@@ -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');
}
});
diff --git a/addons/auth_signup/static/src/js/auth_signup.js b/addons/auth_signup/static/src/js/auth_signup.js
index bb249429894..3025069dece 100644
--- a/addons/auth_signup/static/src/js/auth_signup.js
+++ b/addons/auth_signup/static/src/js/auth_signup.js
@@ -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 = {
diff --git a/addons/base_calendar/crm_meeting_view.xml b/addons/base_calendar/crm_meeting_view.xml
index 10c65ab850b..8590bcb8b49 100644
--- a/addons/base_calendar/crm_meeting_view.xml
+++ b/addons/base_calendar/crm_meeting_view.xml
@@ -221,7 +221,7 @@
-
+
diff --git a/addons/base_import/__openerp__.py b/addons/base_import/__openerp__.py
index 6555cd8e3e0..0df83eed035 100644
--- a/addons/base_import/__openerp__.py
+++ b/addons/base_import/__openerp__.py
@@ -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'],
}
diff --git a/addons/base_import/static/test/states.js b/addons/base_import/static/test/states.js
new file mode 100644
index 00000000000..3e349907a6f
--- /dev/null
+++ b/addons/base_import/static/test/states.js
@@ -0,0 +1,6 @@
+$(document).ready(function () {
+ module('foo');
+ test('dummy', function () {
+ ok(42);
+ });
+});
diff --git a/addons/base_setup/__openerp__.py b/addons/base_setup/__openerp__.py
index de2d8236ece..e74238ba59c 100644
--- a/addons/base_setup/__openerp__.py
+++ b/addons/base_setup/__openerp__.py
@@ -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:
diff --git a/addons/crm/crm_data.xml b/addons/crm/crm_data.xml
index 9dfbd5f9948..f2bf56e34ac 100644
--- a/addons/crm/crm_data.xml
+++ b/addons/crm/crm_data.xml
@@ -58,9 +58,10 @@
mail.groupnotification
+ CRM application installed!
- 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.
+ 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.
diff --git a/addons/fetchmail/fetchmail.py b/addons/fetchmail/fetchmail.py
index e0023697594..68f05dfeee2 100644
--- a/addons/fetchmail/fetchmail.py
+++ b/addons/fetchmail/fetchmail.py
@@ -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
diff --git a/addons/fleet/static/src/img/icon.png b/addons/fleet/static/src/img/icon.png
index 3db7ae9fa49..5b41e43c5bd 100644
Binary files a/addons/fleet/static/src/img/icon.png and b/addons/fleet/static/src/img/icon.png differ
diff --git a/addons/hr/hr_data.xml b/addons/hr/hr_data.xml
index 514cf1f80f6..25c882f2201 100644
--- a/addons/hr/hr_data.xml
+++ b/addons/hr/hr_data.xml
@@ -6,11 +6,11 @@
mail.groupnotification
+ Employee Directory application installed!
- 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).
+ 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).
]]>
diff --git a/addons/hr_evaluation/hr_evaluation_data.xml b/addons/hr_evaluation/hr_evaluation_data.xml
index 01915de76a0..2afb5200091 100644
--- a/addons/hr_evaluation/hr_evaluation_data.xml
+++ b/addons/hr_evaluation/hr_evaluation_data.xml
@@ -11,9 +11,9 @@
mail.groupnotification
+ Employee Appraisals application installed!
- 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.
+ 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.]]>
@@ -811,8 +811,8 @@ Once the form had been filled, the employee send it to his supervisor.
The comment you entered is in an invalid format.* 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 employee’s 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 employee’s 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
diff --git a/addons/hr_expense/hr_expense_data.xml b/addons/hr_expense/hr_expense_data.xml
index 2a9f3ae0a56..f54156ac5ec 100644
--- a/addons/hr_expense/hr_expense_data.xml
+++ b/addons/hr_expense/hr_expense_data.xml
@@ -6,10 +6,10 @@
mail.groupnotification
+ Expense Management application installed!
- 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.
+ 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.
]]>
diff --git a/addons/hr_holidays/hr_holidays_data.xml b/addons/hr_holidays/hr_holidays_data.xml
index afe2e69e697..5af0c60fc44 100644
--- a/addons/hr_holidays/hr_holidays_data.xml
+++ b/addons/hr_holidays/hr_holidays_data.xml
@@ -11,9 +11,10 @@
mail.groupnotification
+ Leave Management application installed!
- 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.
+ 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.
diff --git a/addons/hr_recruitment/hr_recruitment_data.xml b/addons/hr_recruitment/hr_recruitment_data.xml
index 330c86652dd..adaeed81205 100644
--- a/addons/hr_recruitment/hr_recruitment_data.xml
+++ b/addons/hr_recruitment/hr_recruitment_data.xml
@@ -6,10 +6,10 @@
mail.groupnotification
+ Recruitment Process application installed!
- 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.
+ 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.
diff --git a/addons/hr_timesheet_sheet/hr_timesheet_sheet_data.xml b/addons/hr_timesheet_sheet/hr_timesheet_sheet_data.xml
index 87edf949972..095a92c032d 100644
--- a/addons/hr_timesheet_sheet/hr_timesheet_sheet_data.xml
+++ b/addons/hr_timesheet_sheet/hr_timesheet_sheet_data.xml
@@ -6,8 +6,9 @@
mail.groupnotification
+ Timesheet Validation application installed!
- From the top menu "Human Resources", enter and validate timesheets and attendances.
+ From the top menu "Human Resources", enter and validate timesheets and attendances.]]>
diff --git a/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml b/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml
index ee5a329c800..6de6be6c08d 100644
--- a/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml
+++ b/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml
@@ -162,7 +162,7 @@
-
+
diff --git a/addons/l10n_be_coda/wizard/account_coda_import.py b/addons/l10n_be_coda/wizard/account_coda_import.py
index ca89cf78325..46c545f0f48 100644
--- a/addons/l10n_be_coda/wizard/account_coda_import.py
+++ b/addons/l10n_be_coda/wizard/account_coda_import.py
@@ -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:
diff --git a/addons/mail/data/mail_demo.xml b/addons/mail/data/mail_demo.xml
index f189b10650c..a5eaa63956a 100644
--- a/addons/mail/data/mail_demo.xml
+++ b/addons/mail/data/mail_demo.xml
@@ -11,44 +11,48 @@
mail.group
- 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.
+ Your monthly meal vouchers arrived. You can get them at Christine's office.]]>comment
+ mail.group
-
+ 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.]]>comment
+ mail.group
- Thanks, but where is Christine's office, if I may ask? (I'm new here)
+ Thanks! Could you please remind me where is Christine's office, if I may ask? I'm new here!]]>comment
+ mail.group
- Building B3, second floor on the right :-)
+ Building B3, second floor on the right :-).]]>comment
+ mail.group
- Great news, I need to buy a new fridge, I think I can pay it with the eco-vouchers!
+ 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!]]>comment
+
@@ -84,163 +88,5 @@ This month you also get 250 EUR of eco-vouchers if you have been in the company
-
-
- Plan to install OpenERP
- mail.message
-
- <![CDATA[Email0 inquiry]]>
- <div><font size="2">Hello,</font></div><div><font size="2"><br></font></div>
- <div><font size="2">I am interested in your company's product and I plan to install OpenERP for my company and affordable price.</font></div><br/>
- <div><font size="2">Can you please send me services catalogue?</font></div><br/>
- Sophie
-
- email
-
-
-
-
- ir.attachment
- bWlncmF0aW9uIHRlc3Q=
- catalogue 2012.pdf
- catalogue 2012.pdf
-
-
- Re: Plan to install OpenERP
-
- Dear Customer,<br/>
- Thanks for showing interest in our products.<br/>
- We have attached the catalogue,<br/>
- We would like to know your interests, so let us know when we can call you for more details.<br/>
- Regards
-
- comment
-
-
-
-
-
-
-
-
-
- ir.attachment
- bWlncmF0aW9uIHRlc3Q=
- migration.doc
- migration.doc
-
-
- ir.attachment
-
- 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
- CAEAIAQAgP/Z
-
- activity graph 2012.jpg
- activity graph 2012
-
-
- mail.group
-
- Hi,<br/>
- The beta OpenERP 7 is scheduled for November 12.<br/>
- You will find attached the document for migration from version 6 to 7, and the activity graph for the current year. Good reading.<br/>
- Sincerely
-
- comment
-
-
-
-
-
-
- mail.group
-
- Thank you,<br/>
- Could you prepare and send us also the document for version 7.1 which will come soon?<br/>
- Sincerely
-
- comment
-
-
-
-
-
-
-
-
- mail.group
- I changed the infrastructure of networks, if there are still changes to be made please do not hesitate to contact me.
- comment
-
-
-
-
-
- mail.group
- Thank you, the networks is perfect now ! Could you add a IP phone for Jhon ?
-
- comment
-
-
-
-
-
- mail.group
- It's right, his internal phone number is 0093
-
- comment
-
-
-
-
-
diff --git a/addons/mail/data/mail_group_data.xml b/addons/mail/data/mail_group_data.xml
index 2daa69b283b..64d989f9e9d 100644
--- a/addons/mail/data/mail_group_data.xml
+++ b/addons/mail/data/mail_group_data.xml
@@ -17,12 +17,11 @@
mail.groupnotification
+ Welcome to OpenERP!
- 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 <i>Settings</i> 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.
+ 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 the Settings 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.
]]>
diff --git a/addons/mail/mail_followers.py b/addons/mail/mail_followers.py
index 6a8b24f85a8..8d3876ec91f 100644
--- a/addons/mail/mail_followers.py
+++ b/addons/mail/mail_followers.py
@@ -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,
diff --git a/addons/mail/mail_group.py b/addons/mail/mail_group.py
index d4c9c565bf3..b163882577b 100644
--- a/addons/mail/mail_group.py
+++ b/addons/mail/mail_group.py
@@ -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,
}
diff --git a/addons/mail/mail_group_view.xml b/addons/mail/mail_group_view.xml
index 214f6edf571..4a880a13c14 100644
--- a/addons/mail/mail_group_view.xml
+++ b/addons/mail/mail_group_view.xml
@@ -84,7 +84,7 @@
-
+
diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py
index cdf61b043ec..9fd476d9d7f 100644
--- a/addons/mail/mail_message.py
+++ b/addons/mail/mail_message.py
@@ -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'):
diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py
index ee00b88dbd9..ee1a015396b 100644
--- a/addons/mail/mail_thread.py
+++ b/addons/mail/mail_thread.py
@@ -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 ->
- 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 ->
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),
diff --git a/addons/mail/res_partner.py b/addons/mail/res_partner.py
index 6b13fe6ad20..df85ac3f17f 100644
--- a/addons/mail/res_partner.py
+++ b/addons/mail/res_partner.py
@@ -42,4 +42,22 @@ 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
+ return super(res_partner_mail, self).message_post(cr, uid, False, 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:
diff --git a/addons/mail/res_users.py b/addons/mail/res_users.py
index 1b6388111ba..932c4dd9518 100644
--- a/addons/mail/res_users.py
+++ b/addons/mail/res_users.py
@@ -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)
diff --git a/addons/mail/security/ir.model.access.csv b/addons/mail/security/ir.model.access.csv
index 4d68b7e3aef..b87c323b53d 100644
--- a/addons/mail/security/ir.model.access.csv
+++ b/addons/mail/security/ir.model.access.csv
@@ -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
diff --git a/addons/mail/security/mail_security.xml b/addons/mail/security/mail_security.xml
index 3f2b7bf3e9a..525425c2aa0 100644
--- a/addons/mail/security/mail_security.xml
+++ b/addons/mail/security/mail_security.xml
@@ -10,7 +10,7 @@
['|', '|', ('public', '=', 'public'), ('message_follower_ids', 'in', [user.partner_id.id]), '&', ('public','=','groups'), ('group_public_id','in', [g.id for g in user.groups_id])]
-
+ mail.followers: read and write its own entries[('partner_id', '=', user.partner_id.id)]
@@ -18,6 +18,14 @@
+
+ mail.notification: read and write its own entries
+
+ [('partner_id', '=', user.partner_id.id)]
+
+
+
+
-
+
+ Demo Portal User
- portal
- portal
-
-
+ demo@portal.example.com
- demo@portal.wrong.address
+
+
+
+ portal
+ portal
+ --
+Mr Demo Portal
+
+
@@ -24,33 +29,41 @@
Our company's first blog-post !mail.group
- sit amet, consectetur adipiscing elit. 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.]]>
+ Hello, and welcome to our company's portal !
+
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: Company's News. 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.
+
A new era of communication has begun! Feel free to post your feelings about our portal by replying on this message!
]]>comment
+ mail.group
-
+ 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!]]>comment
-
+
+ mail.group
-
+ That's good news! As said by Demo Portal User in the previous post, I'm looking forward to hearing from you!]]>comment
+
+
+
+
+
+ mail.group
+
+ This feature is realy great! We will be able to communicate directly to our partners!]]>
+
+ comment
+
diff --git a/addons/portal/tests/test_portal.py b/addons/portal/tests/test_portal.py
index 83b10b39c28..be32b015743 100644
--- a/addons/portal/tests/test_portal.py
+++ b/addons/portal/tests/test_portal.py
@@ -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()
diff --git a/addons/portal/wizard/portal_wizard.py b/addons/portal/wizard/portal_wizard.py
index c94d6509f63..bf8353c92c1 100644
--- a/addons/portal/wizard/portal_wizard.py
+++ b/addons/portal/wizard/portal_wizard.py
@@ -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
diff --git a/addons/portal_claim/security/portal_security.xml b/addons/portal_claim/security/portal_security.xml
index e177b07eab9..3742765f795 100644
--- a/addons/portal_claim/security/portal_security.xml
+++ b/addons/portal_claim/security/portal_security.xml
@@ -7,6 +7,10 @@
[('message_follower_ids','in', [user.partner_id.id])]
+
+
+
+
diff --git a/addons/portal_project/security/portal_security.xml b/addons/portal_project/security/portal_security.xml
index 1247d25365a..ba686f72db4 100644
--- a/addons/portal_project/security/portal_security.xml
+++ b/addons/portal_project/security/portal_security.xml
@@ -7,6 +7,10 @@
[('message_follower_ids','in', [user.partner_id.id])]
+
+
+
+
diff --git a/addons/portal_project_issue/security/portal_security.xml b/addons/portal_project_issue/security/portal_security.xml
index 9527f1f9628..a121eeb593e 100644
--- a/addons/portal_project_issue/security/portal_security.xml
+++ b/addons/portal_project_issue/security/portal_security.xml
@@ -7,6 +7,10 @@
[('message_follower_ids','in', [user.partner_id.id])]
+
+
+
+
diff --git a/addons/portal_sale/security/portal_security.xml b/addons/portal_sale/security/portal_security.xml
index 39dabf754fe..19d44947f03 100644
--- a/addons/portal_sale/security/portal_security.xml
+++ b/addons/portal_sale/security/portal_security.xml
@@ -8,6 +8,10 @@
[('message_follower_ids','in',[user.partner_id.id])]
+
+
+
+
diff --git a/addons/process/__openerp__.py b/addons/process/__openerp__.py
index fcae18c5490..c998288a614 100644
--- a/addons/process/__openerp__.py
+++ b/addons/process/__openerp__.py
@@ -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'
diff --git a/addons/product_margin/product_margin.py b/addons/product_margin/product_margin.py
index 4c033a4a6ca..c06c4971474 100644
--- a/addons/product_margin/product_margin.py
+++ b/addons/product_margin/product_margin.py
@@ -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')
diff --git a/addons/project/project_data.xml b/addons/project/project_data.xml
index 4f467c89a29..08981bd126a 100644
--- a/addons/project/project_data.xml
+++ b/addons/project/project_data.xml
@@ -125,11 +125,11 @@
mail.groupnotification
+ Project Management application installed!
- 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.
+ 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.
]]>
diff --git a/addons/project/project_demo.xml b/addons/project/project_demo.xml
index cd22bad67d4..698a1a99627 100644
--- a/addons/project/project_demo.xml
+++ b/addons/project/project_demo.xml
@@ -21,31 +21,15 @@
Usability
-
-
- Internal Projects
-
-
- project.task
-
-
-
-
- Customer Projects
-
-
- project.task
-
-
-
opennormalThe Jackson Group's Project
+ 3
- followers
+ public
@@ -58,6 +42,7 @@
Research & Development
+ publicproject.task
@@ -69,6 +54,7 @@
E-Learning Integrationproject.task
+ public
diff --git a/addons/project_gtd/project_gtd_data.xml b/addons/project_gtd/project_gtd_data.xml
index 61b2468329c..9d8c99f23ff 100644
--- a/addons/project_gtd/project_gtd_data.xml
+++ b/addons/project_gtd/project_gtd_data.xml
@@ -30,9 +30,10 @@
mail.groupnotification
+ Todo Lists application installed!
- 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.
+ 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.
]]>
diff --git a/addons/project_issue/project_issue_data.xml b/addons/project_issue/project_issue_data.xml
index 72f824715a8..c1460167097 100644
--- a/addons/project_issue/project_issue_data.xml
+++ b/addons/project_issue/project_issue_data.xml
@@ -36,10 +36,11 @@
mail.groupnotification
+ Issue Tracker application installed!
- 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.
+ 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.
]]>
diff --git a/addons/project_issue/project_issue_demo.xml b/addons/project_issue/project_issue_demo.xml
index 9759d15dabb..63fa37c84c3 100644
--- a/addons/project_issue/project_issue_demo.xml
+++ b/addons/project_issue/project_issue_demo.xml
@@ -1,5 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/project_long_term/project_long_term_view.xml b/addons/project_long_term/project_long_term_view.xml
index 52eb5d80a3a..18e471ddd40 100644
--- a/addons/project_long_term/project_long_term_view.xml
+++ b/addons/project_long_term/project_long_term_view.xml
@@ -121,8 +121,8 @@
- Phases()
- Phase()
+ Phases
+ Phase
diff --git a/addons/purchase/purchase_data.xml b/addons/purchase/purchase_data.xml
index 693d18eb1ba..fa701c1f179 100644
--- a/addons/purchase/purchase_data.xml
+++ b/addons/purchase/purchase_data.xml
@@ -7,10 +7,10 @@
mail.groupnotification
+ Purchase Management application installed!
- 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.
+ 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.
]]>
diff --git a/addons/sale/sale_data.xml b/addons/sale/sale_data.xml
index 6f4ed76614e..3fe03966da2 100644
--- a/addons/sale/sale_data.xml
+++ b/addons/sale/sale_data.xml
@@ -38,10 +38,10 @@
mail.groupnotification
+ Sales Management application installed!
- 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 <i>CRM</i> application may be useful. Use the Settings menu to install it.
+ 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 CRM application may be useful. Use the Settings menu to install it.
diff --git a/addons/stock/stock.py b/addons/stock/stock.py
index d18a55ea49a..859cda8ce94 100644
--- a/addons/stock/stock.py
+++ b/addons/stock/stock.py
@@ -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,
diff --git a/addons/stock/stock_data.xml b/addons/stock/stock_data.xml
index 77c82989a21..a1ce136e304 100644
--- a/addons/stock/stock_data.xml
+++ b/addons/stock/stock_data.xml
@@ -6,9 +6,10 @@
mail.groupnotification
+ Warehouse Management application installed!
- 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).
+ 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).]]>
diff --git a/addons/stock/stock_view.xml b/addons/stock/stock_view.xml
index 9c2a672caf7..a08597df60b 100644
--- a/addons/stock/stock_view.xml
+++ b/addons/stock/stock_view.xml
@@ -283,10 +283,11 @@
stock.trackingchild_ids
-
+
+
@@ -913,7 +914,7 @@