diff --git a/addons/account/account.py b/addons/account/account.py index 75936320e58..71b1be3574e 100644 --- a/addons/account/account.py +++ b/addons/account/account.py @@ -1447,6 +1447,8 @@ class account_move(osv.osv): def unlink(self, cr, uid, ids, context=None, check=True): if context is None: context = {} + if isinstance(ids, (int, long)): + ids = [ids] toremove = [] obj_move_line = self.pool.get('account.move.line') for move in self.browse(cr, uid, ids, context=context): diff --git a/addons/account/account_move_line.py b/addons/account/account_move_line.py index 0fc9d9e2227..ed8fb8185e7 100644 --- a/addons/account/account_move_line.py +++ b/addons/account/account_move_line.py @@ -311,13 +311,13 @@ class account_move_line(osv.osv): context = {} c = context.copy() c['initital_bal'] = True - sql = """SELECT l2.id, SUM(l1.debit-l1.credit) - FROM account_move_line l1, account_move_line l2 - WHERE l2.account_id = l1.account_id - AND l1.id <= l2.id - AND l2.id IN %s AND """ + \ - self._query_get(cr, uid, obj='l1', context=c) + \ - " GROUP BY l2.id" + sql = """SELECT l1.id, COALESCE(SUM(l2.debit-l2.credit), 0) + FROM account_move_line l1 LEFT JOIN account_move_line l2 + ON (l1.account_id = l2.account_id + AND l2.id <= l1.id + AND """ + \ + self._query_get(cr, uid, obj='l2', context=c) + \ + ") WHERE l1.id IN %s GROUP BY l1.id" cr.execute(sql, [tuple(ids)]) return dict(cr.fetchall()) diff --git a/addons/account/wizard/account_invoice_refund.py b/addons/account/wizard/account_invoice_refund.py index 4b7a7fd5314..8a583b79383 100644 --- a/addons/account/wizard/account_invoice_refund.py +++ b/addons/account/wizard/account_invoice_refund.py @@ -52,10 +52,19 @@ class account_invoice_refund(osv.osv_memory): journal = obj_journal.search(cr, uid, [('type', '=', type), ('company_id','=',company_id)], limit=1, context=context) return journal and journal[0] or False + def _get_reason(self, cr, uid, context=None): + active_id = context and context.get('active_id', False) + if active_id: + inv = self.pool.get('account.invoice').browse(cr, uid, active_id, context=context) + return inv.name + else: + return '' + _defaults = { 'date': lambda *a: time.strftime('%Y-%m-%d'), 'journal_id': _get_journal, 'filter_refund': 'refund', + 'description': _get_reason, } def fields_view_get(self, cr, uid, view_id=None, view_type=False, context=None, toolbar=False, submenu=False): diff --git a/addons/auth_signup/static/src/js/auth_signup.js b/addons/auth_signup/static/src/js/auth_signup.js index b825d683099..d9edb44d65f 100644 --- a/addons/auth_signup/static/src/js/auth_signup.js +++ b/addons/auth_signup/static/src/js/auth_signup.js @@ -39,12 +39,6 @@ openerp.auth_signup = function(instance) { delete self.params.error_message; } - // in case of a signup, retrieve the user information from the token - if (dbname && self.params.token) { - self.rpc("/auth_signup/retrieve", {dbname: dbname, token: self.params.token}) - .done(self.on_token_loaded) - .fail(self.on_token_failed); - } if (dbname && self.params.login) { self.$("form input[name=login]").val(self.params.login); } @@ -53,7 +47,7 @@ openerp.auth_signup = function(instance) { self.$('a.oe_signup_reset_password').click(self.do_reset_password); if (dbname) { - self.rpc("/auth_signup/get_config", {dbname: dbname}).done(function(result) { + self.rpc("/auth_signup/get_config", {dbname: dbname}).then(function(result) { self.signup_enabled = result.signup; self.reset_password_enabled = result.reset_password; if (!self.signup_enabled || self.$("form input[name=login]").val()){ @@ -61,6 +55,13 @@ openerp.auth_signup = function(instance) { } else { self.set('login_mode', 'signup'); } + + // in case of a signup, retrieve the user information from the token + if (self.params.token) { + self.rpc("/auth_signup/retrieve", {dbname: dbname, token: self.params.token}) + .then(self.on_token_loaded, self.on_token_failed); + } + }); } else { // TODO: support multiple database mode diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index 9eaddc9fc0e..df4cff03fb0 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -836,9 +836,11 @@ class crm_lead(format_address, osv.osv): model_data = self.pool.get('ir.model.data') phonecall_dict = {} if not categ_id: - res_id = model_data._get_id(cr, uid, 'crm', 'categ_phone2') - if res_id: + try: + res_id = model_data._get_id(cr, uid, 'crm', 'categ_phone2') categ_id = model_data.browse(cr, uid, res_id, context=context).res_id + except ValueError: + pass for lead in self.browse(cr, uid, ids, context=context): if not section_id: section_id = lead.section_id and lead.section_id.id or False @@ -945,6 +947,23 @@ class crm_lead(format_address, osv.osv): vals.update(onchange_stage_values) return super(crm_lead, self).write(cr, uid, ids, vals, context=context) + def copy(self, cr, uid, id, default=None, context=None): + if not default: + default = {} + if not context: + context = {} + lead = self.browse(cr, uid, id, context=context) + local_context = dict(context) + local_context.setdefault('default_type', lead.type) + local_context.setdefault('default_section_id', lead.section_id) + if lead.type == 'opportunity': + default['date_open'] = fields.datetime.now() + else: + default['date_open'] = False + default['date_closed'] = False + default['stage_id'] = self._get_default_stage_id(cr, uid, local_context) + return super(crm_lead, self).copy(cr, uid, id, default, context=context) + # ---------------------------------------- # Mail Gateway # ---------------------------------------- diff --git a/addons/crm/crm_lead_view.xml b/addons/crm/crm_lead_view.xml index 5a3a0aa34fe..d9db16c2211 100644 --- a/addons/crm/crm_lead_view.xml +++ b/addons/crm/crm_lead_view.xml @@ -323,7 +323,7 @@ crm.lead - + diff --git a/addons/crm/crm_phonecall.py b/addons/crm/crm_phonecall.py index 1e67c50a2c3..e74fecc9bdf 100644 --- a/addons/crm/crm_phonecall.py +++ b/addons/crm/crm_phonecall.py @@ -117,9 +117,11 @@ class crm_phonecall(osv.osv): model_data = self.pool.get('ir.model.data') phonecall_dict = {} if not categ_id: - res_id = model_data._get_id(cr, uid, 'crm', 'categ_phone2') - if res_id: + try: + res_id = model_data._get_id(cr, uid, 'crm', 'categ_phone2') categ_id = model_data.browse(cr, uid, res_id, context=context).res_id + except ValueError: + pass for call in self.browse(cr, uid, ids, context=context): if not section_id: section_id = call.section_id and call.section_id.id or False diff --git a/addons/crm/wizard/crm_opportunity_to_phonecall.py b/addons/crm/wizard/crm_opportunity_to_phonecall.py index bb1ac2fdce6..5183773b618 100644 --- a/addons/crm/wizard/crm_opportunity_to_phonecall.py +++ b/addons/crm/wizard/crm_opportunity_to_phonecall.py @@ -34,9 +34,11 @@ class crm_opportunity2phonecall(osv.osv_memory): opp_obj = self.pool.get('crm.lead') categ_id = False data_obj = self.pool.get('ir.model.data') - res_id = data_obj._get_id(cr, uid, 'crm', 'categ_phone2') - if res_id: + try: + res_id = data_obj._get_id(cr, uid, 'crm', 'categ_phone2') categ_id = data_obj.browse(cr, uid, res_id, context=context).res_id + except ValueError: + pass record_ids = context and context.get('active_ids', []) or [] res = {} diff --git a/addons/crm/wizard/crm_phonecall_to_phonecall.py b/addons/crm/wizard/crm_phonecall_to_phonecall.py index 7e1da41a29f..804b3c7cb0f 100644 --- a/addons/crm/wizard/crm_phonecall_to_phonecall.py +++ b/addons/crm/wizard/crm_phonecall_to_phonecall.py @@ -78,9 +78,11 @@ class crm_phonecall2phonecall(osv.osv_memory): categ_id = False data_obj = self.pool.get('ir.model.data') - res_id = data_obj._get_id(cr, uid, 'crm', 'categ_phone2') - if res_id: + try: + res_id = data_obj._get_id(cr, uid, 'crm', 'categ_phone2') categ_id = data_obj.browse(cr, uid, res_id, context=context).res_id + except ValueError: + pass if 'name' in fields: res.update({'name': phonecall.name}) diff --git a/addons/crm_claim/crm_claim.py b/addons/crm_claim/crm_claim.py index c655ce2c12b..dfa06989118 100644 --- a/addons/crm_claim/crm_claim.py +++ b/addons/crm_claim/crm_claim.py @@ -108,7 +108,7 @@ class crm_claim(osv.osv): _defaults = { 'user_id': lambda s, cr, uid, c: uid, 'section_id': lambda s, cr, uid, c: s._get_default_section_id(cr, uid, c), - 'date': fields.datetime.now(), + 'date': fields.datetime.now, 'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.case', context=c), 'priority': lambda *a: crm.AVAILABLE_PRIORITIES[2][0], 'active': lambda *a: 1, @@ -172,7 +172,8 @@ class crm_claim(osv.osv): through message_process. This override updates the document according to the email. """ - if custom_values is None: custom_values = {} + if custom_values is None: + custom_values = {} desc = html2plaintext(msg.get('body')) if msg.get('body') else '' defaults = { 'name': msg.get('subject') or _("No Subject"), @@ -184,33 +185,7 @@ class crm_claim(osv.osv): if msg.get('priority'): 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 - through message_process. - This method updates the document according to the email. - """ - if isinstance(ids, (str, int, long)): - ids = [ids] - if update_vals is None: update_vals = {} - - if msg.get('priority') in dict(crm.AVAILABLE_PRIORITIES): - update_vals['priority'] = msg.get('priority') - - maps = { - 'cost':'planned_cost', - 'revenue': 'planned_revenue', - 'probability':'probability' - } - for line in msg['body'].split('\n'): - line = line.strip() - res = tools.command_re.match(line) - if res and maps.get(res.group(1).lower()): - key = maps.get(res.group(1).lower()) - update_vals[key] = res.group(2).lower() - - return super(crm_claim,self).message_update(cr, uid, ids, msg, update_vals=update_vals, context=context) + return super(crm_claim, self).message_new(cr, uid, msg, custom_values=defaults, context=context) class res_partner(osv.osv): _inherit = 'res.partner' diff --git a/addons/crm_helpdesk/crm_helpdesk.py b/addons/crm_helpdesk/crm_helpdesk.py index 03e6a243851..87932514ada 100644 --- a/addons/crm_helpdesk/crm_helpdesk.py +++ b/addons/crm_helpdesk/crm_helpdesk.py @@ -80,7 +80,7 @@ class crm_helpdesk(osv.osv): 'active': lambda *a: 1, 'user_id': lambda s, cr, uid, c: uid, 'state': lambda *a: 'draft', - 'date': lambda *a: fields.datetime.now(), + 'date': fields.datetime.now, 'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.helpdesk', context=c), 'priority': lambda *a: crm.AVAILABLE_PRIORITIES[2][0], } @@ -126,7 +126,8 @@ class crm_helpdesk(osv.osv): through message_process. This override updates the document according to the email. """ - if custom_values is None: custom_values = {} + if custom_values is None: + custom_values = {} desc = html2plaintext(msg.get('body')) if msg.get('body') else '' defaults = { 'name': msg.get('subject') or _("No Subject"), @@ -137,32 +138,6 @@ class crm_helpdesk(osv.osv): 'partner_id': msg.get('author_id', False), } 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 - through message_process. - This method updates the document according to the email. - """ - if isinstance(ids, (str, int, long)): - ids = [ids] - if update_vals is None: update_vals = {} - - if msg.get('priority') in dict(crm.AVAILABLE_PRIORITIES): - update_vals['priority'] = msg.get('priority') - - maps = { - 'cost':'planned_cost', - 'revenue': 'planned_revenue', - 'probability':'probability' - } - for line in msg['body'].split('\n'): - line = line.strip() - res = tools.command_re.match(line) - if res and maps.get(res.group(1).lower()): - key = maps.get(res.group(1).lower()) - update_vals[key] = res.group(2).lower() - - return super(crm_helpdesk,self).message_update(cr, uid, ids, msg, update_vals=update_vals, context=context) + return super(crm_helpdesk, self).message_new(cr, uid, msg, custom_values=defaults, context=context) # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/delivery/stock.py b/addons/delivery/stock.py index 95e87eb45ab..42c24b4a27d 100644 --- a/addons/delivery/stock.py +++ b/addons/delivery/stock.py @@ -187,6 +187,9 @@ class stock_move(osv.osv): # Redefinition of the new fields in order to update the model stock.picking.out in the orm # FIXME: this is a temporary workaround because of a framework bug (ref: lp996816). It should be removed as soon as # the bug is fixed + +# TODO in trunk: Remove the duplication below using a mixin class! + class stock_picking_out(osv.osv): _inherit = 'stock.picking.out' @@ -212,6 +215,7 @@ class stock_picking_out(osv.osv): }), 'carrier_tracking_ref': fields.char('Carrier Tracking Ref', size=32), 'number_of_packages': fields.integer('Number of Packages'), + 'weight_uom_id': fields.many2one('product.uom', 'Unit of Measure', required=True,readonly="1",help="Unit of measurement for Weight",), } class stock_picking_in(osv.osv): @@ -224,6 +228,8 @@ class stock_picking_in(osv.osv): return self.pool.get('stock.picking')._get_picking_line(cr, uid, ids, context=context) _columns = { + 'carrier_id':fields.many2one("delivery.carrier","Carrier"), + 'volume': fields.float('Volume'), 'weight': fields.function(_cal_weight, type='float', string='Weight', digits_compute= dp.get_precision('Stock Weight'), multi='_cal_weight', store={ 'stock.picking': (lambda self, cr, uid, ids, c={}: ids, ['move_lines'], 20), @@ -234,6 +240,9 @@ class stock_picking_in(osv.osv): 'stock.picking': (lambda self, cr, uid, ids, c={}: ids, ['move_lines'], 20), 'stock.move': (_get_picking_line, ['product_id','product_qty','product_uom','product_uos_qty'], 20), }), + 'carrier_tracking_ref': fields.char('Carrier Tracking Ref', size=32), + 'number_of_packages': fields.integer('Number of Packages'), + 'weight_uom_id': fields.many2one('product.uom', 'Unit of Measure', required=True,readonly="1",help="Unit of measurement for Weight",), } # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/document/static/src/js/document.js b/addons/document/static/src/js/document.js index 23f1375e8c8..e4bce2da76e 100644 --- a/addons/document/static/src/js/document.js +++ b/addons/document/static/src/js/document.js @@ -9,7 +9,7 @@ openerp.document = function (instance) { on_attachments_loaded: function(attachments) { //to display number in name if more then one attachment which has same name. var self = this; - _.chain(attachments.reverse()) + _.chain(attachments) .groupBy(function(attachment) { return attachment.name}) .each(function(attachment){ if(attachment.length > 1) diff --git a/addons/hr_recruitment/hr_recruitment.py b/addons/hr_recruitment/hr_recruitment.py index 780c4390a09..9d94b079fb5 100644 --- a/addons/hr_recruitment/hr_recruitment.py +++ b/addons/hr_recruitment/hr_recruitment.py @@ -333,7 +333,8 @@ class hr_applicant(osv.Model): through message_process. This override updates the document according to the email. """ - if custom_values is None: custom_values = {} + if custom_values is None: + custom_values = {} val = msg.get('from').split('<')[0] defaults = { 'name': msg.get('subject') or _("No Subject"), @@ -346,38 +347,7 @@ class hr_applicant(osv.Model): if msg.get('priority'): 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 - through message_process. - This method updates the document according to the email. - """ - if isinstance(ids, (str, int, long)): - ids = [ids] - if update_vals is None: - update_vals = {} - - update_vals.update({ - 'email_from': msg.get('from'), - 'email_cc': msg.get('cc'), - }) - if msg.get('priority'): - update_vals['priority'] = msg.get('priority') - - maps = { - 'cost': 'planned_cost', - 'revenue': 'planned_revenue', - 'probability': 'probability', - } - for line in msg.get('body', '').split('\n'): - line = line.strip() - res = tools.command_re.match(line) - if res and maps.get(res.group(1).lower(), False): - key = maps.get(res.group(1).lower()) - update_vals[key] = res.group(2).lower() - - return super(hr_applicant, self).message_update(cr, uid, ids, msg, update_vals=update_vals, context=context) + return super(hr_applicant, self).message_new(cr, uid, msg, custom_values=defaults, context=context) def create(self, cr, uid, vals, context=None): if context is None: diff --git a/addons/l10n_be/wizard/l10n_be_account_vat_declaration.py b/addons/l10n_be/wizard/l10n_be_account_vat_declaration.py index 0576e1d5f8f..2ef1a81fef2 100644 --- a/addons/l10n_be/wizard/l10n_be_account_vat_declaration.py +++ b/addons/l10n_be/wizard/l10n_be_account_vat_declaration.py @@ -185,7 +185,7 @@ class l10n_be_vat_declaration(osv.osv_memory): for item in cases_list: grid_amount_data = { 'code': str(int(item['code'])), - 'amount': str(abs(item['sum_period'])), + 'amount': '%.2f' % abs(item['sum_period']), } data_of_file += '\n\t\t\t%(amount)s' % (grid_amount_data) diff --git a/addons/l10n_in_hr_payroll/data/hr.salary.rule.csv b/addons/l10n_in_hr_payroll/data/hr.salary.rule.csv index 2fe1ba739f4..043ba8f0522 100644 --- a/addons/l10n_in_hr_payroll/data/hr.salary.rule.csv +++ b/addons/l10n_in_hr_payroll/data/hr.salary.rule.csv @@ -1,5 +1,5 @@ -"id","amount_select","condition_range_min","condition_range_max","amount_percentage","amount_fix","name","category_id","sequence","code","parent_rule_id/id","condition_select","condition_range","amount_percentage_base" -1,"fix",1,1,,100,"Education Allowance For One Child","Allowance",23,"CHEAONE","hr_payroll_rule_child1","range","employee.children", -2,"fix",2,10,,200,"Education Allowance For Two Child","Allowance",24,"CHEATWO","hr_payroll_rule_child1","range","employee.children", -3,"fix",1,1,,300,"Child Hostel Allowance For One Child","Allowance",26,"CHOONE","hr_payroll_rule_child2","range","employee.children", -4,"fix",2,10,,600,"Child Hostel Allowance For Two Child","Allowance",27,"CHOTWO","hr_payroll_rule_child2","range","employee.children", +"id","amount_select","condition_range_min","condition_range_max","amount_percentage","amount_fix","name","category_id/id","sequence","code","parent_rule_id/id","condition_select","condition_range","amount_percentage_base" +1,"fix",1,1,,100,"Education Allowance For One Child",hr_payroll.ALW,23,"CHEAONE","hr_payroll_rule_child1","range","employee.children", +2,"fix",2,10,,200,"Education Allowance For Two Child",hr_payroll.ALW,24,"CHEATWO","hr_payroll_rule_child1","range","employee.children", +3,"fix",1,1,,300,"Child Hostel Allowance For One Child",hr_payroll.ALW,26,"CHOONE","hr_payroll_rule_child2","range","employee.children", +4,"fix",2,10,,600,"Child Hostel Allowance For Two Child",hr_payroll.ALW,27,"CHOTWO","hr_payroll_rule_child2","range","employee.children", diff --git a/addons/l10n_multilang/l10n_multilang.py b/addons/l10n_multilang/l10n_multilang.py index b7564a9960a..937ba332694 100644 --- a/addons/l10n_multilang/l10n_multilang.py +++ b/addons/l10n_multilang/l10n_multilang.py @@ -33,6 +33,7 @@ class wizard_multi_charts_accounts(osv.osv_memory): """ _inherit = 'wizard.multi.charts.accounts' + # FIXME: in trunk, drop the force_write param entirely def process_translations(self, cr, uid, langs, in_obj, in_field, in_ids, out_obj, out_ids, force_write=False, context=None): """ This method copies translations values of templates into new Accounts/Taxes/Journals for languages selected @@ -45,8 +46,7 @@ class wizard_multi_charts_accounts(osv.osv_memory): :param in_ids: List of ids of source object :param out_obj: Destination object for which translation is to be copied :param out_ids: List of ids of destination object - :param force_write: boolean that depicts if we need to create a translation OR simply replace the actual value - with the translation in the uid's language by doing a write (in case it's TRUE) + :param force_write: Deprecated as of 7.0, do not use :param context: usual context information. May contain the key 'lang', which is the language of the user running the wizard, that will be used if force_write is True @@ -65,26 +65,25 @@ class wizard_multi_charts_accounts(osv.osv_memory): for j in range(len(in_ids)): in_id = in_ids[j] if value[in_id]: - if not force_write: - #copy Translation from Source to Destination object - xlat_obj.create(cr, uid, { - 'name': out_obj._name + ',' + in_field, - 'type': 'model', - 'res_id': out_ids[j], - 'lang': lang, - 'src': src[in_id], - 'value': value[in_id], + #copy Translation from Source to Destination object + xlat_obj.create(cr, uid, { + 'name': out_obj._name + ',' + in_field, + 'type': 'model', + 'res_id': out_ids[j], + 'lang': lang, + 'src': src[in_id], + 'value': value[in_id], }) - else: - #replace the value in the destination object only if it's the user lang - if context.get('lang') == lang: - self.pool[out_obj._name].write(cr, uid, out_ids[j], {in_field: value[in_id]}) else: _logger.info('Language: %s. Translation from template: there is no translation available for %s!' %(lang, src[in_id]))#out_obj._name)) return True def execute(self, cr, uid, ids, context=None): - res = super(wizard_multi_charts_accounts, self).execute(cr, uid, ids, context=context) + if not context: + context = {} + # remove the lang to get the untranslated value + ctx = dict(context, lang=None) + res = super(wizard_multi_charts_accounts, self).execute(cr, uid, ids, context=ctx) obj_multi = self.browse(cr, uid, ids[0], context=context) company_id = obj_multi.company_id.id @@ -125,7 +124,7 @@ class wizard_multi_charts_accounts(osv.osv_memory): acc_root_id = obj_acc.search(cr, uid, [('company_id', '=', company_id), ('parent_id', '=', None)])[0] in_ids = obj_acc_template.search(cr, uid, [('id', 'child_of', [acc_template_root_id])], order='id')[1:] out_ids = obj_acc.search(cr, uid, [('id', 'child_of', [acc_root_id])], order='id')[1:] - return self.process_translations(cr, uid, langs, obj_acc_template, field, in_ids, obj_acc, out_ids, force_write=True, context=context) + return self.process_translations(cr, uid, langs, obj_acc_template, field, in_ids, obj_acc, out_ids, context=context) def _process_tax_codes_translations(self, cr, uid, obj_multi, company_id, langs, field, context=None): obj_tax_code_template = self.pool.get('account.tax.code.template') @@ -134,21 +133,21 @@ class wizard_multi_charts_accounts(osv.osv_memory): tax_code_root_id = obj_tax_code.search(cr, uid, [('company_id', '=', company_id), ('parent_id', '=', None)])[0] in_ids = obj_tax_code_template.search(cr, uid, [('id', 'child_of', [tax_code_template_root_id])], order='id')[1:] out_ids = obj_tax_code.search(cr, uid, [('id', 'child_of', [tax_code_root_id])], order='id')[1:] - return self.process_translations(cr, uid, langs, obj_tax_code_template, field, in_ids, obj_tax_code, out_ids, force_write=False, context=context) + return self.process_translations(cr, uid, langs, obj_tax_code_template, field, in_ids, obj_tax_code, out_ids, context=context) def _process_taxes_translations(self, cr, uid, obj_multi, company_id, langs, field, context=None): obj_tax_template = self.pool.get('account.tax.template') obj_tax = self.pool.get('account.tax') in_ids = sorted([x.id for x in obj_multi.chart_template_id.tax_template_ids]) out_ids = obj_tax.search(cr, uid, [('company_id', '=', company_id)], order='id') - return self.process_translations(cr, uid, langs, obj_tax_template, field, in_ids, obj_tax, out_ids, force_write=False, context=context) + return self.process_translations(cr, uid, langs, obj_tax_template, field, in_ids, obj_tax, out_ids, context=context) def _process_fiscal_pos_translations(self, cr, uid, obj_multi, company_id, langs, field, context=None): obj_fiscal_position_template = self.pool.get('account.fiscal.position.template') obj_fiscal_position = self.pool.get('account.fiscal.position') in_ids = obj_fiscal_position_template.search(cr, uid, [('chart_template_id', '=', obj_multi.chart_template_id.id)], order='id') out_ids = obj_fiscal_position.search(cr, uid, [('company_id', '=', company_id)], order='id') - return self.process_translations(cr, uid, langs, obj_fiscal_position_template, field, in_ids, obj_fiscal_position, out_ids, force_write=False, context=context) + return self.process_translations(cr, uid, langs, obj_fiscal_position_template, field, in_ids, obj_fiscal_position, out_ids, context=context) # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 9ed63ae14fa..0d432342751 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -33,6 +33,7 @@ from openerp import tools from openerp import SUPERUSER_ID from openerp.addons.mail.mail_message import decode from openerp.osv import fields, osv, orm +from openerp.osv.orm import browse_record, browse_null from openerp.tools.safe_eval import safe_eval as eval from openerp.tools.translate import _ @@ -328,11 +329,11 @@ class mail_thread(osv.AbstractModel): if not context.get('mail_create_nosubscribe'): self.message_subscribe_users(cr, uid, [thread_id], [uid], context=context) # auto_subscribe: take values and defaults into account - create_values = set(values.keys()) + create_values = dict(values) for key, val in context.iteritems(): if key.startswith('default_'): - create_values.add(key[8:]) - self.message_auto_subscribe(cr, uid, [thread_id], list(create_values), context=context) + create_values[key[8:]] = val + self.message_auto_subscribe(cr, uid, [thread_id], create_values.keys(), context=context, values=create_values) # track values tracked_fields = self._get_tracked_fields(cr, uid, values.keys(), context=context) @@ -353,7 +354,7 @@ class mail_thread(osv.AbstractModel): # Perform write, update followers result = super(mail_thread, self).write(cr, uid, ids, values, context=context) - self.message_auto_subscribe(cr, uid, ids, values.keys(), context=context) + self.message_auto_subscribe(cr, uid, ids, values.keys(), context=context, values=values) # Perform the tracking if tracked_fields: @@ -1539,75 +1540,100 @@ class mail_thread(osv.AbstractModel): user_field_lst.append(name) return user_field_lst - def message_auto_subscribe(self, cr, uid, ids, updated_fields, context=None): - """ - 1. fetch project subtype related to task (parent_id.res_model = 'project.task') - 2. for each project subtype: subscribe the follower to the task + def message_auto_subscribe(self, cr, uid, ids, updated_fields, context=None, values=None): + """ Handle auto subscription. Two methods for auto subscription exist: + + - tracked res.users relational fields, such as user_id fields. Those fields + must be relation fields toward a res.users record, and must have the + track_visilibity attribute set. + - using subtypes parent relationship: check if the current model being + modified has an header record (such as a project for tasks) whose followers + can be added as followers of the current records. Example of structure + with project and task: + + - st_project_1.parent_id = st_task_1 + - st_project_1.res_model = 'project.project' + - st_project_1.relation_field = 'project_id' + - st_task_1.model = 'project.task' + + :param list updated_fields: list of updated fields to track + :param dict values: updated values; if None, the first record will be browsed + to get the values. Added after releasing 7.0, therefore + not merged with updated_fields argumment. """ subtype_obj = self.pool.get('mail.message.subtype') follower_obj = self.pool.get('mail.followers') + new_followers = dict() - # fetch auto_follow_fields + # fetch auto_follow_fields: res.users relation fields whose changes are tracked for subscription user_field_lst = self._message_get_auto_subscribe_fields(cr, uid, updated_fields, context=context) - # fetch related record subtypes - related_subtype_ids = subtype_obj.search(cr, uid, ['|', ('res_model', '=', False), ('parent_id.res_model', '=', self._name)], context=context) - subtypes = subtype_obj.browse(cr, uid, related_subtype_ids, context=context) - default_subtypes = [subtype for subtype in subtypes if subtype.res_model == False] - related_subtypes = [subtype for subtype in subtypes if subtype.res_model != False] - relation_fields = set([subtype.relation_field for subtype in subtypes if subtype.relation_field != False]) - if (not related_subtypes or not any(relation in updated_fields for relation in relation_fields)) and not user_field_lst: + # fetch header subtypes + header_subtype_ids = subtype_obj.search(cr, uid, ['|', ('res_model', '=', False), ('parent_id.res_model', '=', self._name)], context=context) + subtypes = subtype_obj.browse(cr, uid, header_subtype_ids, context=context) + + # if no change in tracked field or no change in tracked relational field: quit + relation_fields = set([subtype.relation_field for subtype in subtypes if subtype.relation_field is not False]) + if not any(relation in updated_fields for relation in relation_fields) and not user_field_lst: return True - for record in self.browse(cr, uid, ids, context=context): - new_followers = dict() - parent_res_id = False - parent_model = False - for subtype in related_subtypes: - if not subtype.relation_field or not subtype.parent_id: - continue - if not subtype.relation_field in self._columns or not getattr(record, subtype.relation_field, False): - continue - parent_res_id = getattr(record, subtype.relation_field).id - parent_model = subtype.res_model - follower_ids = follower_obj.search(cr, SUPERUSER_ID, [ - ('res_model', '=', parent_model), - ('res_id', '=', parent_res_id), - ('subtype_ids', 'in', [subtype.id]) - ], context=context) - for follower in follower_obj.browse(cr, SUPERUSER_ID, follower_ids, context=context): - new_followers.setdefault(follower.partner_id.id, set()).add(subtype.parent_id.id) + # legacy behavior: if values is not given, compute the values by browsing + # @TDENOTE: remove me in 8.0 + if values is None: + record = self.browse(cr, uid, ids[0], context=context) + for updated_field in updated_fields: + field_value = getattr(record, updated_field) + if isinstance(field_value, browse_record): + field_value = field_value.id + elif isinstance(field_value, browse_null): + field_value = False + values[updated_field] = field_value - if parent_res_id and parent_model: - for subtype in default_subtypes: - follower_ids = follower_obj.search(cr, SUPERUSER_ID, [ - ('res_model', '=', parent_model), - ('res_id', '=', parent_res_id), - ('subtype_ids', 'in', [subtype.id]) - ], context=context) - for follower in follower_obj.browse(cr, SUPERUSER_ID, follower_ids, context=context): - new_followers.setdefault(follower.partner_id.id, set()).add(subtype.id) + # find followers of headers, update structure for new followers + headers = set() + for subtype in subtypes: + if subtype.relation_field and values.get(subtype.relation_field): + headers.add((subtype.res_model, values.get(subtype.relation_field))) + if headers: + header_domain = ['|'] * (len(headers) - 1) + for header in headers: + header_domain += ['&', ('res_model', '=', header[0]), ('res_id', '=', header[1])] + header_follower_ids = follower_obj.search( + cr, SUPERUSER_ID, + header_domain, + context=context + ) + for header_follower in follower_obj.browse(cr, SUPERUSER_ID, header_follower_ids, context=context): + for subtype in header_follower.subtype_ids: + if subtype.res_model and subtype.parent_id: + new_followers.setdefault(header_follower.partner_id.id, set()).add(subtype.parent_id.id) + elif subtype.res_model is False: + new_followers.setdefault(header_follower.partner_id.id, set()).add(subtype.id) - # add followers coming from res.users relational fields that are tracked - user_ids = [getattr(record, name).id for name in user_field_lst if getattr(record, name)] - user_id_partner_ids = [user.partner_id.id for user in self.pool.get('res.users').browse(cr, SUPERUSER_ID, user_ids, context=context)] - for partner_id in user_id_partner_ids: - new_followers.setdefault(partner_id, None) + # add followers coming from res.users relational fields that are tracked + user_ids = [values[name] for name in user_field_lst if values.get(name)] + user_pids = [user.partner_id.id for user in self.pool.get('res.users').browse(cr, SUPERUSER_ID, user_ids, context=context)] + for partner_id in user_pids: + new_followers.setdefault(partner_id, None) - for pid, subtypes in new_followers.items(): - subtypes = list(subtypes) if subtypes is not None else None - self.message_subscribe(cr, uid, [record.id], [pid], subtypes, context=context) + for pid, subtypes in new_followers.items(): + subtypes = list(subtypes) if subtypes is not None else None + self.message_subscribe(cr, uid, ids, [pid], subtypes, context=context) - # find first email message, set it as unread for auto_subscribe fields for them to have a notification - if user_id_partner_ids: - msg_ids = self.pool.get('mail.message').search(cr, uid, [ - ('model', '=', self._name), - ('res_id', '=', record.id), - ('type', '=', 'email')], limit=1, context=context) - if not msg_ids and record.message_ids: - msg_ids = [record.message_ids[-1].id] + # find first email message, set it as unread for auto_subscribe fields for them to have a notification + if user_pids: + for record_id in ids: + message_obj = self.pool.get('mail.message') + msg_ids = message_obj.search(cr, SUPERUSER_ID, [ + ('model', '=', self._name), + ('res_id', '=', record_id), + ('type', '=', 'email')], limit=1, context=context) + if not msg_ids: + msg_ids = message_obj.search(cr, SUPERUSER_ID, [ + ('model', '=', self._name), + ('res_id', '=', record_id)], limit=1, context=context) if msg_ids: - self.pool.get('mail.notification')._notify(cr, uid, msg_ids[0], partners_to_notify=user_id_partner_ids, context=context) + self.pool.get('mail.notification')._notify(cr, uid, msg_ids[0], partners_to_notify=user_pids, context=context) return True diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py index 1d0a0c98d48..4ef2a6a4f4c 100644 --- a/addons/mrp/mrp.py +++ b/addons/mrp/mrp.py @@ -965,7 +965,10 @@ class mrp_production(osv.osv): partner_id = routing_loc.partner_id and routing_loc.partner_id.id or False # Take next Sequence number of shipment base on type - pick_name = ir_sequence.get(cr, uid, 'stock.picking.' + pick_type) + if pick_type!='internal': + pick_name = ir_sequence.get(cr, uid, 'stock.picking.' + pick_type) + else: + pick_name = ir_sequence.get(cr, uid, 'stock.picking') picking_id = stock_picking.create(cr, uid, { 'name': pick_name, diff --git a/addons/mrp_byproduct/mrp_byproduct.py b/addons/mrp_byproduct/mrp_byproduct.py index 2425c2d8fea..38058abf071 100644 --- a/addons/mrp_byproduct/mrp_byproduct.py +++ b/addons/mrp_byproduct/mrp_byproduct.py @@ -80,11 +80,11 @@ class mrp_production(osv.osv): _inherit= 'mrp.production' - def action_confirm(self, cr, uid, ids): + def action_confirm(self, cr, uid, ids, context=None): """ Confirms production order and calculates quantity based on subproduct_type. @return: Newly generated picking Id. """ - picking_id = super(mrp_production,self).action_confirm(cr, uid, ids) + picking_id = super(mrp_production,self).action_confirm(cr, uid, ids, context=context) product_uom_obj = self.pool.get('product.uom') for production in self.browse(cr, uid, ids): source = production.product_id.property_stock_production.id diff --git a/addons/pad/pad.py b/addons/pad/pad.py index 4cd9e91b76e..474321edb1d 100644 --- a/addons/pad/pad.py +++ b/addons/pad/pad.py @@ -39,7 +39,11 @@ class pad_common(osv.osv_memory): #if create with content if "field_name" in context and "model" in context and "object_id" in context: myPad = EtherpadLiteClient( pad["key"], pad["server"]+'/api') - myPad.createPad(path) + try: + myPad.createPad(path) + except urllib2.URLError: + raise osv.except_osv(_("Error"), _("Pad creation failed, \ + either there is a problem with your pad server URL or with your connection.")) #get attr on the field model model = self.pool[context["model"]] diff --git a/addons/pad/pad_demo.xml b/addons/pad/pad_demo.xml index 99c4b38481c..5fd76f65e21 100644 --- a/addons/pad/pad_demo.xml +++ b/addons/pad/pad_demo.xml @@ -2,7 +2,7 @@ - pad.openerp.com + https://pad.openerp.com diff --git a/addons/point_of_sale/point_of_sale.py b/addons/point_of_sale/point_of_sale.py index d32b8e91d3a..a7bc2f5f59e 100644 --- a/addons/point_of_sale/point_of_sale.py +++ b/addons/point_of_sale/point_of_sale.py @@ -694,7 +694,7 @@ class pos_order(osv.osv): def create_picking(self, cr, uid, ids, context=None): """Create a picking for each order and validate it.""" - picking_obj = self.pool.get('stock.picking') + picking_obj = self.pool.get('stock.picking.out') partner_obj = self.pool.get('res.partner') move_obj = self.pool.get('stock.move') diff --git a/addons/point_of_sale/point_of_sale_view.xml b/addons/point_of_sale/point_of_sale_view.xml index 7202b57a1eb..0f26a7c85b9 100644 --- a/addons/point_of_sale/point_of_sale_view.xml +++ b/addons/point_of_sale/point_of_sale_view.xml @@ -56,7 +56,7 @@ diff --git a/addons/portal/mail_message.py b/addons/portal/mail_message.py index 9699b3a9ef6..4429df3be8b 100644 --- a/addons/portal/mail_message.py +++ b/addons/portal/mail_message.py @@ -19,6 +19,7 @@ # ############################################################################## +from openerp import SUPERUSER_ID from openerp.osv import osv, orm from openerp.tools.translate import _ @@ -32,6 +33,9 @@ class mail_message(osv.Model): """ Override that adds specific access rights of mail.message, to remove all internal notes if uid is a non-employee """ + if uid == SUPERUSER_ID: + return super(mail_message, self)._search(cr, uid, args, offset=offset, limit=limit, order=order, + context=context, count=False, access_rights_uid=access_rights_uid) group_ids = self.pool.get('res.users').browse(cr, uid, uid, context=context).groups_id group_user_id = self.pool.get("ir.model.data").get_object_reference(cr, uid, 'base', 'group_user')[1] if group_user_id not in [group.id for group in group_ids]: @@ -45,6 +49,8 @@ class mail_message(osv.Model): - read: - raise if the type is comment and subtype NULL (internal note) """ + if uid == SUPERUSER_ID: + return super(mail_message, self).check_access_rule(cr, uid, ids=ids, operation=operation, context=context) group_ids = self.pool.get('res.users').browse(cr, uid, uid, context=context).groups_id group_user_id = self.pool.get("ir.model.data").get_object_reference(cr, uid, 'base', 'group_user')[1] if group_user_id not in [group.id for group in group_ids]: diff --git a/addons/portal/tests/test_portal.py b/addons/portal/tests/test_portal.py index f5eeba0aa62..12c64d7588c 100644 --- a/addons/portal/tests/test_portal.py +++ b/addons/portal/tests/test_portal.py @@ -73,6 +73,9 @@ class test_portal(TestMail): for message in chell_pigs.message_ids: trigger_read = message.subject for partner in chell_pigs.message_follower_ids: + if partner.id == self.partner_chell_id: + # Chell can read her own partner record + continue with self.assertRaises(except_orm): trigger_read = partner.name diff --git a/addons/portal_claim/security/portal_security.xml b/addons/portal_claim/security/portal_security.xml index af5261c408b..1f96da4ef9e 100644 --- a/addons/portal_claim/security/portal_security.xml +++ b/addons/portal_claim/security/portal_security.xml @@ -1,17 +1,15 @@ - - + Portal Personal Claims - [('message_follower_ids','in', [user.partner_id.id])] + ['|', ('message_follower_ids','in', [user.partner_id.id]), ('partner_id','=', user.partner_id.id)] - - + + - + - diff --git a/addons/procurement/procurement.py b/addons/procurement/procurement.py index 032952aa511..c2878df69cb 100644 --- a/addons/procurement/procurement.py +++ b/addons/procurement/procurement.py @@ -181,10 +181,6 @@ class procurement_order(osv.osv): """ return all(procurement.move_id.state == 'cancel' for procurement in self.browse(cr, uid, ids, context=context)) - #This Function is create to avoid a server side Error Like 'ERROR:tests.mrp:name 'check_move' is not defined' - def check_move(self, cr, uid, ids, context=None): - pass - def check_move_done(self, cr, uid, ids, context=None): """ Checks if move is done or not. @return: True or False. @@ -297,6 +293,12 @@ class procurement_order(osv.osv): """ return False + def check_move(self, cr, uid, ids, context=None): + """ Check whether the given procurement can be satisfied by an internal move, + typically a pulled flow. By default, it's False. Overwritten by the `stock_location` module. + """ + return False + def check_conditions_confirm2wait(self, cr, uid, ids): """ condition on the transition to go from 'confirm' activity to 'confirm_wait' activity """ return not self.test_cancel(cr, uid, ids) diff --git a/addons/procurement/procurement_workflow.xml b/addons/procurement/procurement_workflow.xml index 76b54370ef2..d4068a6eada 100644 --- a/addons/procurement/procurement_workflow.xml +++ b/addons/procurement/procurement_workflow.xml @@ -147,13 +147,15 @@ - not check_produce() and not check_buy() + not check_produce() and not check_buy() and not check_move() diff --git a/addons/procurement/schedulers.py b/addons/procurement/schedulers.py index 6f326ccf1c5..10c3bc2b083 100644 --- a/addons/procurement/schedulers.py +++ b/addons/procurement/schedulers.py @@ -194,6 +194,7 @@ class procurement_order(osv.osv): 'company_id': orderpoint.company_id.id, 'product_uom': orderpoint.product_uom.id, 'location_id': orderpoint.location_id.id, + 'warehouse_id': orderpoint.warehouse_id.id, 'procure_method': 'make_to_order', 'origin': orderpoint.name} diff --git a/addons/product_visible_discount/product_visible_discount.py b/addons/product_visible_discount/product_visible_discount.py index a2f0a41847f..bd43028b36a 100644 --- a/addons/product_visible_discount/product_visible_discount.py +++ b/addons/product_visible_discount/product_visible_discount.py @@ -86,78 +86,13 @@ class sale_order_line(osv.osv): pricelists = pricelist_obj.read(cr,uid,[pricelist],['visible_discount']) new_list_price = get_real_price(list_price, product.id, qty, uom, pricelist) - if(len(pricelists)>0 and pricelists[0]['visible_discount'] and list_price[pricelist] != 0): + if len(pricelists)>0 and pricelists[0]['visible_discount'] and list_price[pricelist] != 0 and new_list_price != 0: discount = (new_list_price - price) / new_list_price * 100 - result['price_unit'] = new_list_price - result['discount'] = discount + if discount > 0: + result['price_unit'] = new_list_price + result['discount'] = discount + else: + result['discount'] = 0.0 else: result['discount'] = 0.0 return res - - -class account_invoice_line(osv.osv): - _inherit = "account.invoice.line" - - def product_id_change(self, cr, uid, ids, product, uom_id, qty=0, name='', type='out_invoice', partner_id=False, fposition_id=False, price_unit=False, currency_id=False, context=None, company_id=None): - res = super(account_invoice_line, self).product_id_change(cr, uid, ids, product, uom_id, qty, name, type, partner_id, fposition_id, price_unit,currency_id, context=context, company_id=company_id) - - def get_real_price(res_dict, product_id, qty, uom_id, pricelist): - item_obj = self.pool.get('product.pricelist.item') - price_type_obj = self.pool.get('product.price.type') - product_obj = self.pool.get('product.product') - field_name = 'list_price' - - if res_dict.get('item_id',False) and res_dict['item_id'].get(pricelist,False): - item = res_dict['item_id'].get(pricelist,False) - item_read = item_obj.read(cr, uid, [item], ['base']) - if item_read: - item_base = item_read[0]['base'] - if item_base > 0: - field_name = price_type_obj.browse(cr, uid, item_base).field - - product = product_obj.browse(cr, uid, product_id, context) - product_read = product_obj.read(cr, uid, product_id, [field_name], context=context) - - factor = 1.0 - if uom_id and uom_id != product.uom_id.id: - product_uom_obj = self.pool.get('product.uom') - uom_data = product_uom_obj.browse(cr, uid, product.uom_id.id) - factor = uom_data.factor - return product_read[field_name] * factor - - if product: - pricelist_obj = self.pool.get('product.pricelist') - partner_obj = self.pool.get('res.partner') - product = self.pool.get('product.product').browse(cr, uid, product, context=context) - result = res['value'] - pricelist = False - real_price = 0.00 - if type in ('in_invoice', 'in_refund'): - if not price_unit and partner_id: - pricelist =partner_obj.browse(cr, uid, partner_id).property_product_pricelist_purchase.id - if not pricelist: - raise osv.except_osv(_('No Purchase Pricelist Found!'),_("You must first define a pricelist on the supplier form!")) - price_unit_res = pricelist_obj.price_get(cr, uid, [pricelist], product.id, qty or 1.0, partner_id, {'uom': uom_id}) - price_unit = price_unit_res[pricelist] - real_price = get_real_price(price_unit_res, product.id, qty, uom_id, pricelist) - else: - if partner_id: - pricelist = partner_obj.browse(cr, uid, partner_id).property_product_pricelist.id - if not pricelist: - raise osv.except_osv(_('No Sale Pricelist Found!'),_("You must first define a pricelist on the customer form!")) - price_unit_res = pricelist_obj.price_get(cr, uid, [pricelist], product.id, qty or 1.0, partner_id, {'uom': uom_id}) - price_unit = price_unit_res[pricelist] - - real_price = get_real_price(price_unit_res, product.id, qty, uom_id, pricelist) - if pricelist: - pricelists=pricelist_obj.read(cr,uid,[pricelist],['visible_discount']) - if(len(pricelists)>0 and pricelists[0]['visible_discount'] and real_price != 0): - discount=(real_price-price_unit) / real_price * 100 - result['price_unit'] = real_price - result['discount'] = discount - else: - result['discount']=0.0 - return res - - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/project/project.py b/addons/project/project.py index 9173318366e..3cba9b7833f 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -1131,7 +1131,8 @@ class task(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 = {} + if custom_values is None: + custom_values = {} defaults = { 'name': msg.get('subject'), 'planned_hours': 0.0, @@ -1141,10 +1142,10 @@ class task(osv.osv): def message_update(self, cr, uid, ids, msg, update_vals=None, context=None): """ Override to update the task according to the email. """ - if update_vals is None: update_vals = {} - act = False + if update_vals is None: + update_vals = {} maps = { - 'cost':'planned_hours', + 'cost': 'planned_hours', } for line in msg['body'].split('\n'): line = line.strip() @@ -1157,9 +1158,7 @@ class task(osv.osv): update_vals[field] = float(res.group(2).lower()) except (ValueError, TypeError): pass - if act: - getattr(self,act)(cr, uid, ids, context=context) - return super(task,self).message_update(cr, uid, ids, msg, update_vals=update_vals, context=context) + return super(task, self).message_update(cr, uid, ids, msg, update_vals=update_vals, context=context) class project_work(osv.osv): _name = "project.task.work" diff --git a/addons/project_issue/project_issue.py b/addons/project_issue/project_issue.py index 4de3c9f54ad..12776ce1940 100644 --- a/addons/project_issue/project_issue.py +++ b/addons/project_issue/project_issue.py @@ -519,40 +519,10 @@ class project_issue(osv.Model): 'partner_id': msg.get('author_id', False), 'user_id': False, } - if msg.get('priority'): - defaults['priority'] = msg.get('priority') - 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): - """ Overrides mail_thread message_update that is called by the mailgateway - through message_process. - This method updates the document according to the email. - """ - if isinstance(ids, (str, int, long)): - ids = [ids] - if update_vals is None: update_vals = {} - - # Update doc values according to the message - if msg.get('priority'): - update_vals['priority'] = msg.get('priority') - # Parse 'body' to find values to update - maps = { - 'cost': 'planned_cost', - 'revenue': 'planned_revenue', - 'probability': 'probability', - } - for line in msg.get('body', '').split('\n'): - line = line.strip() - res = tools.command_re.match(line) - if res and maps.get(res.group(1).lower(), False): - key = maps.get(res.group(1).lower()) - update_vals[key] = res.group(2).lower() - - return super(project_issue, self).message_update(cr, uid, ids, msg, update_vals=update_vals, context=context) - def message_post(self, cr, uid, thread_id, body='', subject=None, type='notification', subtype=None, parent_id=False, attachments=None, context=None, content_subtype='html', **kwargs): """ Overrides mail_thread message_post so that we can set the date of last action field when a new message is posted on the issue. diff --git a/addons/purchase/purchase_view.xml b/addons/purchase/purchase_view.xml index 6bed8bcbf9c..4a301d3fa7b 100644 --- a/addons/purchase/purchase_view.xml +++ b/addons/purchase/purchase_view.xml @@ -36,6 +36,9 @@ + - + diff --git a/addons/sale_stock/report/sale_report.py b/addons/sale_stock/report/sale_report.py index 0feb3ee2392..bdcce410a5f 100644 --- a/addons/sale_stock/report/sale_report.py +++ b/addons/sale_stock/report/sale_report.py @@ -42,6 +42,8 @@ class sale_report(osv.osv): def init(self, cr): tools.drop_view_if_exists(cr, 'sale_report') + # TODO: make parent view extensible similarly to invoice analysis and + # remove the duplication cr.execute(""" create or replace view sale_report as ( select @@ -50,7 +52,7 @@ class sale_report(osv.osv): t.uom_id as product_uom, sum(l.product_uom_qty / u.factor * u2.factor) as product_uom_qty, sum(l.product_uom_qty * l.price_unit * (100.0-l.discount) / 100.0) as price_total, - 1 as nbr, + count(*) as nbr, s.date_order as date, s.date_confirm as date_confirm, to_char(s.date_order, 'YYYY') as year, @@ -68,15 +70,14 @@ class sale_report(osv.osv): s.pricelist_id as pricelist_id, s.project_id as analytic_account_id from - sale_order s - join sale_order_line l on (s.id=l.order_id) + sale_order_line l + join sale_order s on (l.order_id=s.id) left join product_product p on (l.product_id=p.id) left join product_template t on (p.product_tmpl_id=t.id) left join product_uom u on (u.id=l.product_uom) left join product_uom u2 on (u2.id=t.uom_id) group by l.product_id, - l.product_uom_qty, l.order_id, t.uom_id, t.categ_id, diff --git a/addons/sale_stock/stock.py b/addons/sale_stock/stock.py index ad19684c4cf..ccece846390 100644 --- a/addons/sale_stock/stock.py +++ b/addons/sale_stock/stock.py @@ -62,6 +62,15 @@ class stock_picking(osv.osv): return picking.note or picking.sale_id.note return super(stock_picking, self)._get_comment_invoice(cursor, user, picking) + def _prepare_invoice_group(self, cr, uid, picking, partner, invoice, context=None): + """ Inherit the original function of the 'stock' module in order to override name field + to pass the customer reference form the sales order + """ + invoice_vals = super(stock_picking, self)._prepare_invoice_group(cr, uid, picking, partner, invoice, context) + if picking.sale_id: + invoice_vals['name'] = (invoice.name or '') + ', ' + (picking.sale_id.client_order_ref or '') + return invoice_vals + def _prepare_invoice(self, cr, uid, picking, partner, inv_type, journal_id, context=None): """ Inherit the original function of the 'stock' module in order to override some values if the picking has been generated by a sales order diff --git a/addons/stock/product_view.xml b/addons/stock/product_view.xml index 5388e76fe6d..7c0d3ac201b 100644 --- a/addons/stock/product_view.xml +++ b/addons/stock/product_view.xml @@ -224,12 +224,18 @@ - + Receptions - + + Reception + + Deliveries + + Delivery +
  • On hand:
  • diff --git a/addons/stock/stock.py b/addons/stock/stock.py index af70faeef41..a432ddccab8 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -243,6 +243,9 @@ class stock_location(osv.osv): if location.chained_location_type == 'customer': if partner: result = partner.property_stock_customer + else: + loc_id = self.pool['res.partner'].default_get(cr, uid, ['property_stock_customer'], context=context)['property_stock_customer'] + result = self.pool['stock.location'].browse(cr, uid, loc_id, context=context) elif location.chained_location_type == 'fixed': result = location.chained_location_id if result: @@ -1267,17 +1270,17 @@ class stock_picking(osv.osv): context['currency_id'] = move_currency_id qty = uom_obj._compute_qty(cr, uid, product_uom, product_qty, product.uom_id.id) - if product.id in product_avail: - product_avail[product.id] += qty - else: + if product.id not in product_avail: + # keep track of stock on hand including processed lines not yet marked as done product_avail[product.id] = product.qty_available if qty > 0: new_price = currency_obj.compute(cr, uid, product_currency, - move_currency_id, product_price) + move_currency_id, product_price, round=False) new_price = uom_obj._compute_price(cr, uid, product_uom, new_price, product.uom_id.id) - if product.qty_available <= 0: + if product_avail[product.id] <= 0: + product_avail[product.id] = 0 new_std_price = new_price else: # Get the standard price @@ -1293,6 +1296,9 @@ class stock_picking(osv.osv): {'price_unit': product_price, 'price_currency_id': product_currency}) + product_avail[product.id] += qty + + for move in too_few: product_qty = move_product_qty[move.id] @@ -2359,7 +2365,7 @@ class stock_move(osv.osv): { 'journal_id': j_id, 'line_id': move_lines, - 'ref': move.picking_id and move.picking_id.name}) + 'ref': move.picking_id and move.picking_id.name}, context=context) def action_done(self, cr, uid, ids, context=None): """ Makes the move done and if all moves are done, it will finish the picking. @@ -2697,7 +2703,7 @@ class stock_move(osv.osv): qty = uom_obj._compute_qty(cr, uid, product_uom, product_qty, product.uom_id.id) if qty > 0: new_price = currency_obj.compute(cr, uid, product_currency, - move_currency_id, product_price) + move_currency_id, product_price, round=False) new_price = uom_obj._compute_price(cr, uid, product_uom, new_price, product.uom_id.id) if product.qty_available <= 0: @@ -3031,6 +3037,13 @@ class stock_picking_in(osv.osv): """Send the unsubscribe action on stock.picking model to match with subscribe""" return self.pool.get('stock.picking').message_unsubscribe(*args, **kwargs) + def default_get(self, cr, uid, fields_list, context=None): + # merge defaults from stock.picking with possible defaults defined on stock.picking.in + defaults = self.pool['stock.picking'].default_get(cr, uid, fields_list, context=context) + out_defaults = super(stock_picking_in, self).default_get(cr, uid, fields_list, context=context) + defaults.update(in_defaults) + return defaults + _columns = { 'backorder_id': fields.many2one('stock.picking.in', 'Back Order of', states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}, help="If this shipment was split, then this field links to the shipment which contains the already processed part.", select=True), 'state': fields.selection( @@ -3104,6 +3117,13 @@ class stock_picking_out(osv.osv): """Send the unsubscribe action on stock.picking model to match with subscribe""" return self.pool.get('stock.picking').message_unsubscribe(*args, **kwargs) + def default_get(self, cr, uid, fields_list, context=None): + # merge defaults from stock.picking with possible defaults defined on stock.picking.out + defaults = self.pool['stock.picking'].default_get(cr, uid, fields_list, context=context) + out_defaults = super(stock_picking_out, self).default_get(cr, uid, fields_list, context=context) + defaults.update(out_defaults) + return defaults + _columns = { 'backorder_id': fields.many2one('stock.picking.out', 'Back Order of', states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}, help="If this shipment was split, then this field links to the shipment which contains the already processed part.", select=True), 'state': fields.selection( diff --git a/addons/stock/stock_view.xml b/addons/stock/stock_view.xml index c48a7cf0f2b..99f2e738709 100644 --- a/addons/stock/stock_view.xml +++ b/addons/stock/stock_view.xml @@ -1251,7 +1251,7 @@ - + diff --git a/addons/stock/wizard/stock_partial_picking.py b/addons/stock/wizard/stock_partial_picking.py index 8c2c5839989..50ddc2b88ed 100644 --- a/addons/stock/wizard/stock_partial_picking.py +++ b/addons/stock/wizard/stock_partial_picking.py @@ -51,7 +51,7 @@ class stock_partial_picking_line(osv.TransientModel): 'move_id' : fields.many2one('stock.move', "Move", ondelete='CASCADE'), 'wizard_id' : fields.many2one('stock.partial.picking', string="Wizard", ondelete='CASCADE'), 'update_cost': fields.boolean('Need cost update'), - 'cost' : fields.float("Cost", help="Unit Cost for this product line"), + 'cost' : fields.float("Cost", help="Unit Cost for this product line", digits_compute=dp.get_precision('Product Price')), 'currency' : fields.many2one('res.currency', string="Currency", help="Currency in which Unit cost is expressed", ondelete='CASCADE'), 'tracking': fields.function(_tracking, string='Tracking', type='boolean'), }