Units Remaining
diff --git a/addons/account_followup/account_followup.py b/addons/account_followup/account_followup.py
index 9821030df0b..285a3529ee7 100644
--- a/addons/account_followup/account_followup.py
+++ b/addons/account_followup/account_followup.py
@@ -166,8 +166,8 @@ class res_partner(osv.osv):
action_text = partner.latest_followup_level_id_without_lit.manual_action_note or ''
#Check date: put the minimum date if it existed already
- action_date = (partner.payment_next_action_date and min(partner.payment_next_action_date, fields.date.context_today(cr, uid, context))
- ) or fields.date.context_today(cr, uid, context)
+ action_date = (partner.payment_next_action_date and min(partner.payment_next_action_date, fields.date.context_today(self, cr, uid, context=context))
+ ) or fields.date.context_today(self, cr, uid, context=context)
# Check responsible: if partner has not got a responsible already, take from follow-up
responsible_id = False
@@ -218,9 +218,9 @@ class res_partner(osv.osv):
unknown_mails = unknown_mails + 1
action_text = _("Email not sent because of email address of partner not filled in")
if partner.payment_next_action_date:
- payment_action_date = min(fields.date.context_today(cr, uid, ctx), partner.payment_next_action_date)
+ payment_action_date = min(fields.date.context_today(self, cr, uid, context=ctx), partner.payment_next_action_date)
else:
- payment_action_date = fields.date.context_today(cr, uid, ctx)
+ payment_action_date = fields.date.context_today(self, cr, uid, context=ctx)
if partner.payment_next_action:
payment_next_action = partner.payment_next_action + " \n " + action_text
else:
@@ -242,7 +242,7 @@ class res_partner(osv.osv):
followup_table = ''
if partner.unreconciled_aml_ids:
company = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id
- current_date = fields.date.context_today(cr, uid, context)
+ current_date = fields.date.context_today(self, cr, uid, context=context)
rml_parse = account_followup_print.report_rappel(cr, uid, "followup_rml_parser")
final_res = rml_parse._lines_get_with_partner(partner, company.id)
@@ -311,7 +311,7 @@ class res_partner(osv.osv):
'''
res = {}
company = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id
- current_date = fields.date.context_today(cr, uid, context)
+ current_date = fields.date.context_today(self, cr, uid, context=context)
for partner in self.browse(cr, uid, ids, context=context):
worst_due_date = False
amount_due = amount_overdue = 0.0
diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py
index 2fb81a005c0..4455663ca9a 100644
--- a/addons/crm/crm_lead.py
+++ b/addons/crm/crm_lead.py
@@ -87,12 +87,13 @@ class crm_lead(base_stage, format_address, osv.osv):
def create(self, cr, uid, vals, context=None):
if context is None:
context = {}
- if not vals.get('stage_id') and vals.get('section_id'):
+ if not vals.get('stage_id'):
ctx = context.copy()
- ctx['default_section_id'] = vals['section_id']
+ if vals.get('section_id'):
+ ctx['default_section_id'] = vals['section_id']
+ if vals.get('type'):
+ ctx['default_type'] = vals['type']
vals['stage_id'] = self._get_default_stage_id(cr, uid, context=ctx)
- elif not vals.get('stage_id') and context.get('default_section_id'):
- vals['stage_id'] = self._get_default_stage_id(cr, uid, context=context)
return super(crm_lead, self).create(cr, uid, vals, context=context)
def _get_default_section_id(self, cr, uid, context=None):
@@ -974,16 +975,17 @@ class crm_lead(base_stage, format_address, osv.osv):
if custom_values is None: custom_values = {}
desc = html2plaintext(msg.get('body')) if msg.get('body') else ''
- custom_values.update({
+ defaults = {
'name': msg.get('subject') or _("No Subject"),
'description': desc,
'email_from': msg.get('from'),
'email_cc': msg.get('cc'),
'user_id': False,
- })
+ }
if msg.get('priority') in dict(crm.AVAILABLE_PRIORITIES):
- custom_values['priority'] = msg.get('priority')
- return super(crm_lead, self).message_new(cr, uid, msg, custom_values=custom_values, context=context)
+ defaults['priority'] = msg.get('priority')
+ defaults.update(custom_values)
+ return super(crm_lead, self).message_new(cr, uid, msg, custom_values=defaults, context=context)
def message_update(self, cr, uid, ids, msg, update_vals=None, context=None):
""" Overrides mail_thread message_update that is called by the mailgateway
diff --git a/addons/crm_claim/crm_claim.py b/addons/crm_claim/crm_claim.py
index 5aaa6582e34..a724579f1e8 100644
--- a/addons/crm_claim/crm_claim.py
+++ b/addons/crm_claim/crm_claim.py
@@ -190,15 +190,16 @@ class crm_claim(base_stage, osv.osv):
"""
if custom_values is None: custom_values = {}
desc = html2plaintext(msg.get('body')) if msg.get('body') else ''
- custom_values.update({
+ defaults = {
'name': msg.get('subject') or _("No Subject"),
'description': desc,
'email_from': msg.get('from'),
'email_cc': msg.get('cc'),
- })
+ }
if msg.get('priority'):
- custom_values['priority'] = msg.get('priority')
- return super(crm_claim,self).message_new(cr, uid, msg, custom_values=custom_values, context=context)
+ defaults['priority'] = msg.get('priority')
+ defaults.update(custom_values)
+ return super(crm_claim,self).message_new(cr, uid, msg, custom_values=defaults, context=context)
def message_update(self, cr, uid, ids, msg, update_vals=None, context=None):
""" Overrides mail_thread message_update that is called by the mailgateway
diff --git a/addons/crm_helpdesk/crm_helpdesk.py b/addons/crm_helpdesk/crm_helpdesk.py
index a707787491d..5ed1c040627 100644
--- a/addons/crm_helpdesk/crm_helpdesk.py
+++ b/addons/crm_helpdesk/crm_helpdesk.py
@@ -100,14 +100,15 @@ class crm_helpdesk(base_state, base_stage, osv.osv):
"""
if custom_values is None: custom_values = {}
desc = html2plaintext(msg.get('body')) if msg.get('body') else ''
- custom_values.update({
+ defaults = {
'name': msg.get('subject') or _("No Subject"),
'description': desc,
'email_from': msg.get('from'),
'email_cc': msg.get('cc'),
'user_id': False,
- })
- return super(crm_helpdesk,self).message_new(cr, uid, msg, custom_values=custom_values, context=context)
+ }
+ defaults.update(custom_values)
+ return super(crm_helpdesk,self).message_new(cr, uid, msg, custom_values=defaults, context=context)
def message_update(self, cr, uid, ids, msg, update_vals=None, context=None):
""" Overrides mail_thread message_update that is called by the mailgateway
diff --git a/addons/hr_recruitment/hr_recruitment.py b/addons/hr_recruitment/hr_recruitment.py
index 33e32d94762..44d8912c5f1 100644
--- a/addons/hr_recruitment/hr_recruitment.py
+++ b/addons/hr_recruitment/hr_recruitment.py
@@ -347,16 +347,17 @@ class hr_applicant(base_stage, osv.Model):
"""
if custom_values is None: custom_values = {}
desc = html2plaintext(msg.get('body')) if msg.get('body') else ''
- custom_values.update({
+ defaults = {
'name': msg.get('subject') or _("No Subject"),
'description': desc,
'email_from': msg.get('from'),
'email_cc': msg.get('cc'),
'user_id': False,
- })
+ }
if msg.get('priority'):
- custom_values['priority'] = msg.get('priority')
- return super(hr_applicant,self).message_new(cr, uid, msg, custom_values=custom_values, context=context)
+ defaults['priority'] = msg.get('priority')
+ defaults.update(custom_values)
+ return super(hr_applicant,self).message_new(cr, uid, msg, custom_values=defaults, context=context)
def message_update(self, cr, uid, ids, msg, update_vals=None, context=None):
""" Override mail_thread message_update that is called by the mailgateway
diff --git a/addons/lunch/lunch.py b/addons/lunch/lunch.py
index f61ecc8eb7d..0f9033fce38 100644
--- a/addons/lunch/lunch.py
+++ b/addons/lunch/lunch.py
@@ -107,6 +107,7 @@ class lunch_order(osv.Model):
elif alert.alter_type == 'week':
#the alert is activated during some days of the week
return self.check_day(alert)
+ return True # alter_type == 'days' (every day)
def _default_alerts_get(self, cr, uid, context=None):
"""
diff --git a/addons/mail/mail_alias.py b/addons/mail/mail_alias.py
index ef204d7a8cb..d9c49d833ab 100644
--- a/addons/mail/mail_alias.py
+++ b/addons/mail/mail_alias.py
@@ -66,7 +66,7 @@ class mail_alias(osv.Model):
'alias_name': fields.char('Alias', required=True,
help="The name of the email alias, e.g. 'jobs' "
"if you want to catch emails for
",),
- 'alias_model_id': fields.many2one('ir.model', 'Aliased Model', required=True,
+ 'alias_model_id': fields.many2one('ir.model', 'Aliased Model', required=True, ondelete="cascade",
help="The model (OpenERP Document Kind) to which this alias "
"corresponds. Any incoming email that does not reply to an "
"existing record will cause the creation of a new record "
diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py
index 600c3c6d832..16587ae24fd 100644
--- a/addons/mail/mail_message.py
+++ b/addons/mail/mail_message.py
@@ -78,7 +78,7 @@ class mail_message(osv.Model):
for message in self.read(cr, uid, ids, ['model', 'res_id'], context=context):
if not message.get('model') or not message.get('res_id') or not self.pool.get(message['model']):
continue
- result[message['id']] = self._shorten_name(self.pool.get(message['model']).name_get(cr, SUPERUSER_ID, [message['res_id']], context=context)[0][1])
+ result[message['id']] = self.pool.get(message['model']).name_get(cr, SUPERUSER_ID, [message['res_id']], context=context)[0][1]
return result
def _get_to_read(self, cr, uid, ids, name, arg, context=None):
diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py
index f2cea9b4538..d75a9199369 100644
--- a/addons/mail/mail_thread.py
+++ b/addons/mail/mail_thread.py
@@ -839,6 +839,7 @@ class mail_thread(osv.AbstractModel):
ids = partner_obj.search(cr, SUPERUSER_ID, [('email', '=', email)], context=context)
if ids:
partner_ids.append(ids[0])
+ partner_id = ids[0]
else:
partner_id = partner_obj.create(cr, uid, {
'name': name or email,
diff --git a/addons/mail/res_users.py b/addons/mail/res_users.py
index 3f33f1dbca5..41b0a46c2b4 100644
--- a/addons/mail/res_users.py
+++ b/addons/mail/res_users.py
@@ -62,16 +62,6 @@ class res_users(osv.Model):
# create aliases for all users and avoid constraint errors
self.pool.get('mail.alias').migrate_to_alias(cr, self._name, self._table, super(res_users, self)._auto_init,
self._columns['alias_id'], 'login', alias_force_key='id', context=context)
- # make already existing users follow themselves, using SQL to avoid using the ORM during the auto_init
- cr.execute(""" SELECT p.id FROM res_partner p
- LEFT JOIN mail_followers n
- ON (n.partner_id = p.id AND n.res_model = 'res.partner' AND n.res_id = p.id)
- WHERE n.id IS NULL
- """)
- params = [(res[0], res[0]) for res in cr.fetchall()]
- cr.executemany(""" INSERT INTO mail_followers (partner_id, res_model, res_id)
- VALUES (%s, 'res.partner', %s)
- """, params)
def create(self, cr, uid, data, context=None):
# create default alias same as the login
@@ -81,12 +71,11 @@ class res_users(osv.Model):
mail_alias = self.pool.get('mail.alias')
alias_id = mail_alias.create_unique_alias(cr, uid, {'alias_name': data['login']}, model_name=self._name, context=context)
data['alias_id'] = alias_id
- data.pop('alias_name', None) # prevent errors during copy()
+ data.pop('alias_name', None) # prevent errors during copy()
- # create user that follows its related partner
+ # create user
user_id = super(res_users, self).create(cr, uid, data, context=context)
user = self.browse(cr, uid, user_id, context=context)
- self.pool.get('res.partner').message_subscribe(cr, uid, [user.partner_id.id], [user.partner_id.id], context=context)
# alias
mail_alias.write(cr, SUPERUSER_ID, [alias_id], {"alias_force_thread_id": user_id}, context)
# create a welcome message
@@ -150,6 +139,9 @@ class res_users(osv.Model):
self.pool.get('res.partner').message_subscribe(cr, uid, [partner_id], partner_ids, subtype_ids=subtype_ids, context=context)
return True
+ def message_create_partners_from_emails(self, cr, uid, emails, context=None):
+ return self.pool.get('res.partner').message_create_partners_from_emails(cr, uid, emails, context=context)
+
class res_users_mail_group(osv.Model):
""" Update of res.users class
diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js
index e08afdad217..e3986a390d6 100644
--- a/addons/mail/static/src/js/mail.js
+++ b/addons/mail/static/src/js/mail.js
@@ -580,6 +580,9 @@ openerp.mail = function (session) {
}
});
var deferred_check = $.Deferred();
+ if (emails.length == 0) {
+ return deferred_check.resolve(partners_from);
+ }
self.parent_thread.ds_thread._model.call('message_create_partners_from_emails', [emails]).then(function (partners) {
partners_from = _.clone(partners.partner_ids);
var deferreds = [];
diff --git a/addons/mail/tests/test_mail_message.py b/addons/mail/tests/test_mail_message.py
index 39bb99007ee..07a87a16910 100644
--- a/addons/mail/tests/test_mail_message.py
+++ b/addons/mail/tests/test_mail_message.py
@@ -365,11 +365,3 @@ class test_mail_access_rights(TestMailBase):
{'subject': 'Subject', 'body': 'Body text'},
{'default_composition_mode': 'reply', 'default_parent_id': pigs_msg_id})
mail_compose.send_mail(cr, user_raoul_id, [compose_id])
-
- # Do: Raoul writes on its own profile, ok because follower of its partner
- self.res_users.message_post(cr, user_raoul_id, user_raoul_id, body='I love Raoul')
- self.res_partner.message_post(cr, user_raoul_id, partner_raoul_id, body='I love Raoul')
- compose_id = mail_compose.create(cr, user_raoul_id,
- {'subject': 'Subject', 'body': 'Body text', 'partner_ids': []},
- {'default_composition_mode': 'comment', 'default_model': 'res.users', 'default_res_id': self.user_raoul_id})
- mail_compose.send_mail(cr, user_raoul_id, [compose_id])
diff --git a/addons/point_of_sale/static/src/js/db.js b/addons/point_of_sale/static/src/js/db.js
index 0df57759156..666c61919da 100644
--- a/addons/point_of_sale/static/src/js/db.js
+++ b/addons/point_of_sale/static/src/js/db.js
@@ -1,8 +1,34 @@
function openerp_pos_db(instance, module){
- /* PosLS is a LocalStorage based implementation of the point of sale database,
- it performs better for few products, but does not scale beyond 500 products.
- */
+ /* The db module was intended to be used to store all the data needed to run the Point
+ * of Sale in offline mode. (Products, Categories, Orders, ...) It would also use WebSQL
+ * or IndexedDB to make the searching and sorting products faster. It turned out not to be
+ * a so good idea after all.
+ *
+ * First it is difficult to make the Point of Sale truly independant of the server. A lot
+ * of functionality cannot realistically run offline, like generating invoices.
+ *
+ * IndexedDB turned out to be complicated and slow as hell, and loading all the data at the
+ * start made the point of sale take forever to load over small connections.
+ *
+ * LocalStorage has a hard 5.0MB on chrome. For those kind of sizes, it is just better
+ * to put the data in memory and it's not too big to download each time you launch the PoS.
+ *
+ * So at this point we are dropping the support for offline mode, and this module doesn't really
+ * make sense anymore. But if at some point you want to store millions of products and if at
+ * that point indexedDB has improved to the point it is usable, you can just implement this API.
+ *
+ * You would also need to change the way the models are loaded at the start to not reload all your
+ * product data.
+ */
+
+ /* PosLS is a localstorage based implementation of the point of sale database.
+ * FIXME: The Products definitions and categories are stored on the locastorage even tough they're
+ * always reloaded at launch. This could induce a slowdown because the data needs to be reparsed from
+ * JSON before each operation. If you have a huge amount of products (around 25000) it can also
+ * blow the 5.0MB localstorage limit.
+ */
+
module.PosLS = instance.web.Class.extend({
name: 'openerp_pos_ls', //the prefix of the localstorage data
limit: 100, // the maximum number of results returned by a search
@@ -110,6 +136,8 @@ function openerp_pos_db(instance, module){
},
/* saves a record store to the database */
save: function(store,data){
+ var str_data = JSON.stringify(data);
+ console.log('Storing '+ Math.round(str_data.length/1024.0)+' KB of data to store: '+store);
localStorage[this.name + '_' + store] = JSON.stringify(data);
this.cache[store] = data;
},
diff --git a/addons/point_of_sale/static/src/js/devices.js b/addons/point_of_sale/static/src/js/devices.js
index 55e75ebcf42..e7d0376938c 100644
--- a/addons/point_of_sale/static/src/js/devices.js
+++ b/addons/point_of_sale/static/src/js/devices.js
@@ -438,7 +438,7 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
// The barcode readers acts as a keyboard, we catch all keyup events and try to find a
// barcode sequence in the typed keys, then act accordingly.
$('body').delegate('','keyup', function (e){
- console.log('keyup:'+String.fromCharCode(e.keyCode)+' '+e.keyCode,e);
+ //console.log('keyup:'+String.fromCharCode(e.keyCode)+' '+e.keyCode,e);
//We only care about numbers
if (e.keyCode >= 48 && e.keyCode < 58){
diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js
index f533fa760ab..556ea482aad 100644
--- a/addons/point_of_sale/static/src/js/models.js
+++ b/addons/point_of_sale/static/src/js/models.js
@@ -125,7 +125,6 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
return self.fetch('res.partner', ['name','ean13'], [['ean13', '!=', false]]);
}).then(function(partners){
self.set('partner_list',partners);
- console.log('Loaded partners:',partners);
return self.fetch('account.tax', ['amount', 'price_include', 'type']);
}).then(function(taxes){
@@ -242,7 +241,6 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
// saves the order locally and try to send it to the backend. 'record' is a bizzarely defined JSON version of the Order
push_order: function(record) {
- console.log('PUSHING NEW ORDER:',record);
this.db.add_order(record);
this.flush();
},
@@ -259,7 +257,6 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
// it has been confirmed that they have been sent correctly.
flush: function() {
//TODO make the mutex work
- console.log('FLUSH');
//this makes sure only one _int_flush is called at the same time
/*
return this.flush_mutex.exec(_.bind(function() {
@@ -275,7 +272,6 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
var self = this;
var orders = this.db.get_orders();
self.set('nbr_pending_operations',orders.length);
- console.log('TRYING TO FLUSH ORDER:',index,'Of',orders.length);
var order = orders[index];
if(!order){
@@ -291,7 +287,6 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
})
.done(function(){
//remove from db if success
- console.log('Order successfully sent');
self.db.remove_order(order.id);
self._flush(index);
});
diff --git a/addons/point_of_sale/static/src/js/screens.js b/addons/point_of_sale/static/src/js/screens.js
index dd7f55efc37..f8e3382c242 100644
--- a/addons/point_of_sale/static/src/js/screens.js
+++ b/addons/point_of_sale/static/src/js/screens.js
@@ -864,6 +864,7 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
this.pos.bind('change:selectedOrder', this.change_selected_order, this);
this.bindPaymentLineEvents();
this.bind_orderline_events();
+ this.paymentlinewidgets = [];
},
show: function(){
this._super();
@@ -932,18 +933,24 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
},
addPaymentLine: function(newPaymentLine) {
var self = this;
- var x = new module.PaymentlineWidget(null, {
+ var l = new module.PaymentlineWidget(null, {
payment_line: newPaymentLine
});
- x.on('delete_payment_line', self, function(r) {
+ l.on('delete_payment_line', self, function(r) {
self.deleteLine(r);
});
- x.appendTo(this.$('#paymentlines'));
+ l.appendTo(this.$('#paymentlines'));
+ this.paymentlinewidgets.push(l);
this.$('.paymentline-amount input:last').focus();
},
renderElement: function() {
this._super();
this.$('#paymentlines').empty();
+ for(var i = 0, len = this.paymentlinewidgets.length; i < len; i++){
+ this.paymentlinewidgets[i].destroy();
+ }
+ this.paymentlinewidgets = [];
+
this.currentPaymentLines.each(_.bind( function(paymentLine) {
this.addPaymentLine(paymentLine);
}, this));
diff --git a/addons/point_of_sale/static/src/js/widgets.js b/addons/point_of_sale/static/src/js/widgets.js
index 135c00f198d..39ac2529a76 100644
--- a/addons/point_of_sale/static/src/js/widgets.js
+++ b/addons/point_of_sale/static/src/js/widgets.js
@@ -165,6 +165,7 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
this.set_numpad_state(options.numpadState);
this.pos.bind('change:selectedOrder', this.change_selected_order, this);
this.bind_orderline_events();
+ this.orderlinewidgets = [];
},
set_numpad_state: function(numpadState) {
if (this.numpadState) {
@@ -210,6 +211,16 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
var self = this;
this._super();
+ // freeing subwidgets
+
+ if(this.scrollbar){
+ this.scrollbar.destroy();
+ }
+ for(var i = 0, len = this.orderlinewidgets.length; i < len; i++){
+ this.orderlinewidgets[i].destroy();
+ }
+ this.orderlinewidgets = [];
+
if(this.display_mode === 'maximized'){
$('.point-of-sale .order-container').css({'bottom':'0px'});
}else if(this.display_mode === 'actionbar'){
@@ -227,6 +238,7 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
line.on('order_line_selected', self, self.update_numpad);
line.on('order_line_refreshed', self, self.update_summary);
line.appendTo($content);
+ self.orderlinewidgets.push(line);
}, this));
this.update_numpad();
this.update_summary();
@@ -571,7 +583,7 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
var self = this;
this._super(parent,options);
this.model = options.model;
- this.product_list = [];
+ this.productwidgets = [];
this.weight = options.weight || 0;
this.show_scale = options.show_scale || false;
this.next_screen = options.next_screen || false;
@@ -584,7 +596,17 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
renderElement: function() {
var self = this;
this._super();
- this.product_list = [];
+
+ // free subwidgets memory from previous renders
+
+ for(var i = 0, len = this.productwidgets.length; i < len; i++){
+ this.productwidgets[i].destroy();
+ }
+ this.productwidgets = [];
+ if(this.scrollbar){
+ this.scrollbar.destroy();
+ }
+
this.pos.get('products')
.chain()
.map(function(product) {
@@ -593,7 +615,7 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
weight: self.weight,
click_product_action: self.click_product_action,
})
- self.product_list.push(product);
+ self.productwidgets.push(product);
return product;
})
.invoke('appendTo', this.$('.product-list'));
diff --git a/addons/project/project.py b/addons/project/project.py
index 3c7c180ebb3..f89ce8391fc 100644
--- a/addons/project/project.py
+++ b/addons/project/project.py
@@ -1091,12 +1091,11 @@ class task(base_stage, osv.osv):
def create(self, cr, uid, vals, context=None):
if context is None:
context = {}
- if not vals.get('stage_id') and vals.get('project_id'):
+ if not vals.get('stage_id'):
ctx = context.copy()
- ctx['default_project_id'] = vals['project_id']
+ if vals.get('project_id'):
+ ctx['default_project_id'] = vals['project_id']
vals['stage_id'] = self._get_default_stage_id(cr, uid, context=ctx)
- elif not vals.get('stage_id') and context.get('default_project_id'):
- vals['stage_id'] = self._get_default_stage_id(cr, uid, context=context)
task_id = super(task, self).create(cr, uid, vals, context=context)
self._store_history(cr, uid, [task_id], context=context)
return task_id
@@ -1174,11 +1173,12 @@ class task(base_stage, osv.osv):
def message_new(self, cr, uid, msg, custom_values=None, context=None):
""" Override to updates the document according to the email. """
if custom_values is None: custom_values = {}
- custom_values.update({
+ defaults = {
'name': msg.get('subject'),
'planned_hours': 0.0,
- })
- return super(task,self).message_new(cr, uid, msg, custom_values=custom_values, context=context)
+ }
+ defaults.update(custom_values)
+ return super(task,self).message_new(cr, uid, msg, custom_values=defaults, context=context)
def message_update(self, cr, uid, ids, msg, update_vals=None, context=None):
""" Override to update the task according to the email. """
diff --git a/addons/project/project_view.xml b/addons/project/project_view.xml
index ade07f7cebb..b102c01193d 100644
--- a/addons/project/project_view.xml
+++ b/addons/project/project_view.xml
@@ -11,12 +11,56 @@
+
+ project.task.search.form
+ project.task
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
- project.task
- form
Tasks
- kanban,tree,form,calendar,graph
+ project.task
+ kanban,tree,form,calendar,gantt,graph
{'search_default_project_id': [active_id], 'default_project_id': active_id}
+
+
+
+ Click to create a new task.
+
+ OpenERP's project management allows you to manage the pipeline
+ of tasks in order to get things done efficiently. You can
+ track progress, discuss on tasks, attach documents, etc.
+
+
@@ -334,7 +378,6 @@
-
@@ -394,6 +437,15 @@
+
+
+
+
+
+
+
+
+
@@ -501,8 +553,8 @@
-
-
+
+
@@ -542,41 +594,6 @@
-
- project.task.search.form
- project.task
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
account.analytic.account.form.inherit
account.analytic.account
@@ -593,11 +610,7 @@
Tasks
project.task
- form
kanban,tree,form,calendar,gantt,graph
-
-
- {}
diff --git a/addons/project_issue/project_issue.py b/addons/project_issue/project_issue.py
index 5a757fdac39..b0b7193b7aa 100644
--- a/addons/project_issue/project_issue.py
+++ b/addons/project_issue/project_issue.py
@@ -67,12 +67,11 @@ class project_issue(base_stage, osv.osv):
def create(self, cr, uid, vals, context=None):
if context is None:
context = {}
- if not vals.get('stage_id') and vals.get('project_id'):
+ if not vals.get('stage_id'):
ctx = context.copy()
- ctx['default_project_id'] = vals['project_id']
+ if vals.get('project_id'):
+ ctx['default_project_id'] = vals['project_id']
vals['stage_id'] = self._get_default_stage_id(cr, uid, context=ctx)
- elif not vals.get('stage_id') and context.get('default_project_id'):
- vals['stage_id'] = self._get_default_stage_id(cr, uid, context=context)
return super(project_issue, self).create(cr, uid, vals, context=context)
def _get_default_project_id(self, cr, uid, context=None):
@@ -497,17 +496,18 @@ class project_issue(base_stage, osv.osv):
desc = html2plaintext(msg.get('body')) if msg.get('body') else ''
- custom_values.update({
+ defaults = {
'name': msg.get('subject') or _("No Subject"),
'description': desc,
'email_from': msg.get('from'),
'email_cc': msg.get('cc'),
'user_id': False,
- })
+ }
if msg.get('priority'):
- custom_values['priority'] = msg.get('priority')
+ defaults['priority'] = msg.get('priority')
- res_id = super(project_issue, self).message_new(cr, uid, msg, custom_values=custom_values, context=context)
+ defaults.update(custom_values)
+ res_id = super(project_issue, self).message_new(cr, uid, msg, custom_values=defaults, context=context)
return res_id
def message_update(self, cr, uid, ids, msg, update_vals=None, context=None):
diff --git a/addons/sale/res_config.py b/addons/sale/res_config.py
index f87841e1338..44733be3e39 100644
--- a/addons/sale/res_config.py
+++ b/addons/sale/res_config.py
@@ -98,13 +98,20 @@ Example: Product: this product is deprecated, do not purchase more than 5.
wizard = self.browse(cr, uid, ids)[0]
if wizard.time_unit:
- product = ir_model_data.get_object(cr, uid, 'product', 'product_product_consultant')
- product.write({'uom_id': wizard.time_unit.id, 'uom_po_id': wizard.time_unit.id})
+ product = False
+ try:
+ product = ir_model_data.get_object(cr, uid, 'product', 'product_product_consultant')
+ except:
+ #product with xml_id product_product_consultant has not been found. Don't do anything except logging the exception
+ import logging
+ _logger = logging.getLogger(__name__)
+ _logger.warning("Warning, product with xml_id 'product_product_consultant' hasn't been found")
+ if product:
+ product.write({'uom_id': wizard.time_unit.id, 'uom_po_id': wizard.time_unit.id})
if wizard.module_project and wizard.time_unit:
user = self.pool.get('res.users').browse(cr, uid, uid, context)
user.company_id.write({'project_time_mode_id': wizard.time_unit.id})
-
return {}
def onchange_task_work(self, cr, uid, ids, task_work, context=None):
diff --git a/addons/web_analytics/static/src/js/web_analytics.js b/addons/web_analytics/static/src/js/web_analytics.js
index 75bcf29a575..26171cb32aa 100644
--- a/addons/web_analytics/static/src/js/web_analytics.js
+++ b/addons/web_analytics/static/src/js/web_analytics.js
@@ -38,7 +38,8 @@ openerp.web_analytics = function(instance) {
},
/*
* This method MUST be overriden by saas_demo and saas_trial in order to
- * set the correct user type. By default, the user connected is local to the DB.
+ * set the correct user type. By default, the user connected is local to
+ * the DB (like in accounts).
*/
_get_user_type: function() {
return 'Local User';
@@ -67,22 +68,28 @@ openerp.web_analytics = function(instance) {
* stored in GA. Also other modules can override it to add new custom variables
*/
initialize_custom: function() {
- // Track User Access Level, Custom Variable 4 in GA with visitor level scope
- // Values: 'Admin User', 'Normal User', 'Portal User', 'Anonymous User'
- _gaq.push(['_setCustomVar', 4, 'User Access Level', this.user_access_level, 1]);
-
- // Track User Type Conversion, Custom Variable 3 in GA with session level scope
- // Values: 'Visitor', 'Demo', 'Online Trial', 'Online Paying', 'Local User'
- _gaq.push(['_setCustomVar', 1, 'User Type Conversion', this._get_user_type(), 2]);
-
+ var self = this;
return instance.session.rpc("/web/webclient/version_info", {})
.done(function(res) {
_gaq.push(['_setCustomVar', 5, 'Version', res.server_version, 3]);
+ // Track User Access Level, Custom Variable 4 in GA with visitor level scope
+ // Values: 'Admin User', 'Normal User', 'Portal User', 'Anonymous User'
+ _gaq.push(['_setCustomVar', 4, 'User Access Level', self.user_access_level, 1]);
+
+ // Track User Type Conversion, Custom Variable 3 in GA with session level scope
+ // Values: 'Visitor', 'Demo', 'Online Trial', 'Online Paying', 'Local User'
+ _gaq.push(['_setCustomVar', 1, 'User Type Conversion', self._get_user_type(), 2]);
_gaq.push(['_trackPageview']);
return;
});
},
/*
+ * Method called in order to send _trackPageview to GA
+ */
+ _push_pageview: function(url) {
+ _gaq.push(['_trackPageview', url]);
+ },
+ /*
* Method called in order to send _trackEvent to GA
*/
_push_event: function(options) {
@@ -155,6 +162,7 @@ openerp.web_analytics = function(instance) {
'category': r.model,
'action': 'form',
'label': url,
+ 'noninteraction': true,
});
});
this.on('record_saved', self, function(r) {
@@ -163,6 +171,7 @@ openerp.web_analytics = function(instance) {
'category': r.model,
'action': 'form',
'label': url,
+ 'noninteraction': true,
});
});
}
@@ -197,6 +206,7 @@ openerp.web_analytics = function(instance) {
'category': category,
'action': action,
'label': url,
+ 'noninteraction': true,
});
return this._super.apply(this, arguments);
},