[MERGE] Forward-port of latest 7.0 bugfixes, up to rev. 9567 rev-id: odo@openerp.com-20131105103011-vkix07lsb6q3y9fd
bzr revid: dle@openerp.com-20131031142609-jinks18n2ju7usm4 bzr revid: dle@openerp.com-20131031162241-goga1hsvwgyqigzd bzr revid: odo@openerp.com-20131105122634-joau6mg9jqpvbauz
This commit is contained in:
commit
465c241338
|
@ -51,7 +51,12 @@ openerp.base_import = function (instance) {
|
|||
type: 'ir.actions.client',
|
||||
tag: 'import',
|
||||
params: {
|
||||
model: self.dataset.model
|
||||
model: self.dataset.model,
|
||||
// self.dataset.get_context() could be a compound?
|
||||
// not sure. action's context should be evaluated
|
||||
// so safer bet. Odd that timezone & al in it
|
||||
// though
|
||||
context: self.getParent().action.context,
|
||||
}
|
||||
}, {
|
||||
on_reverse_breadcrumb: function () {
|
||||
|
@ -127,6 +132,7 @@ openerp.base_import = function (instance) {
|
|||
var self = this;
|
||||
this._super.apply(this, arguments);
|
||||
this.res_model = action.params.model;
|
||||
this.parent_context = action.params.context || {};
|
||||
// import object id
|
||||
this.id = null;
|
||||
this.Import = new instance.web.Model('base_import.import');
|
||||
|
@ -353,11 +359,12 @@ openerp.base_import = function (instance) {
|
|||
},
|
||||
|
||||
//- import itself
|
||||
call_import: function (options) {
|
||||
call_import: function (kwargs) {
|
||||
var fields = this.$('.oe_import_fields input.oe_import_match_field').map(function (index, el) {
|
||||
return $(el).select2('val') || false;
|
||||
}).get();
|
||||
return this.Import.call('do', [this.id, fields, this.import_options()], options)
|
||||
kwargs.context = this.parent_context;
|
||||
return this.Import.call('do', [this.id, fields, this.import_options()], kwargs)
|
||||
.then(undefined, function (error, event) {
|
||||
// In case of unexpected exception, convert
|
||||
// "JSON-RPC error" to an import failure, and
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
# Copyright (C) 2010-2012 OpenERP s.a. (<http://openerp.com>).
|
||||
# Copyright (C) 2010-2013 OpenERP s.a. (<http://openerp.com>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
|
@ -49,6 +49,7 @@ class board_board(osv.osv):
|
|||
('value', 'in', refs),
|
||||
], context=context)
|
||||
menu_ids = map(itemgetter('res_id'), IrValues.read(cr, uid, irv_ids, ['res_id'], context=context))
|
||||
menu_ids = Menus._filter_visible_menus(cr, uid, menu_ids, context=context)
|
||||
menu_names = Menus.name_get(cr, uid, menu_ids, context=context)
|
||||
return [dict(id=m[0], name=m[1]) for m in menu_names]
|
||||
|
||||
|
|
|
@ -188,7 +188,8 @@ class crm_claim(base_stage, 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"),
|
||||
|
@ -200,33 +201,7 @@ class crm_claim(base_stage, 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'
|
||||
|
|
|
@ -98,7 +98,8 @@ class crm_helpdesk(base_state, base_stage, 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"),
|
||||
|
@ -109,32 +110,6 @@ class crm_helpdesk(base_state, base_stage, 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:
|
||||
|
|
|
@ -168,6 +168,12 @@ class crm_lead(osv.osv):
|
|||
return res
|
||||
|
||||
def assign_geo_localize(self, cr, uid, ids, latitude=False, longitude=False, context=None):
|
||||
if latitude and longitude:
|
||||
self.write(cr, uid, ids, {
|
||||
'partner_latitude': latitude,
|
||||
'partner_longitude': longitude
|
||||
}, context=context)
|
||||
return True
|
||||
# Don't pass context to browse()! We need country name in english below
|
||||
for lead in self.browse(cr, uid, ids):
|
||||
if not lead.country_id:
|
||||
|
@ -177,14 +183,11 @@ class crm_lead(osv.osv):
|
|||
city=lead.city,
|
||||
state=lead.state_id.name,
|
||||
country=lead.country_id.name))
|
||||
if not latitude and result:
|
||||
latitude = result[0]
|
||||
if not longitude and result:
|
||||
longitude = result[1]
|
||||
self.write(cr, uid, [lead.id], {
|
||||
'partner_latitude': latitude,
|
||||
'partner_longitude': longitude
|
||||
}, context=context)
|
||||
if result:
|
||||
self.write(cr, uid, [lead.id], {
|
||||
'partner_latitude': result[0],
|
||||
'partner_longitude': result[1]
|
||||
}, context=context)
|
||||
return True
|
||||
|
||||
def search_geo_partner(self, cr, uid, ids, context=None):
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -352,7 +352,8 @@ class hr_applicant(base_stage, 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 = {}
|
||||
desc = html2plaintext(msg.get('body')) if msg.get('body') else ''
|
||||
defaults = {
|
||||
'name': msg.get('subject') or _("No Subject"),
|
||||
|
@ -365,38 +366,7 @@ class hr_applicant(base_stage, 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:
|
||||
|
|
|
@ -45,8 +45,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 +64,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 +123,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 +132,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:
|
||||
|
|
|
@ -1232,7 +1232,8 @@ 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 = {}
|
||||
if custom_values is None:
|
||||
custom_values = {}
|
||||
defaults = {
|
||||
'name': msg.get('subject'),
|
||||
'planned_hours': 0.0,
|
||||
|
@ -1242,10 +1243,10 @@ class task(base_stage, 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()
|
||||
|
@ -1258,12 +1259,7 @@ class task(base_stage, osv.osv):
|
|||
update_vals[field] = float(res.group(2).lower())
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
elif match.lower() == 'state' \
|
||||
and res.group(2).lower() in ['cancel','close','draft','open','pending']:
|
||||
act = 'do_%s' % res.group(2).lower()
|
||||
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)
|
||||
|
||||
def project_task_reevaluate(self, cr, uid, ids, context=None):
|
||||
if self.pool.get('res.users').has_group(cr, uid, 'project.group_time_work_estimation_tasks'):
|
||||
|
|
|
@ -537,8 +537,10 @@ class project_issue(base_stage, osv.osv):
|
|||
through message_process.
|
||||
This override updates the document according to the email.
|
||||
"""
|
||||
if custom_values is None: custom_values = {}
|
||||
if context is None: context = {}
|
||||
if custom_values is None:
|
||||
custom_values = {}
|
||||
if context is None:
|
||||
context = {}
|
||||
context['state_to'] = 'draft'
|
||||
|
||||
desc = html2plaintext(msg.get('body')) if msg.get('body') else ''
|
||||
|
@ -551,40 +553,10 @@ class project_issue(base_stage, osv.osv):
|
|||
'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.
|
||||
|
|
|
@ -94,23 +94,20 @@ class purchase_report(osv.osv):
|
|||
extract(epoch from age(s.date_approve,s.date_order))/(24*60*60)::decimal(16,2) as delay,
|
||||
extract(epoch from age(l.date_planned,s.date_order))/(24*60*60)::decimal(16,2) as delay_pass,
|
||||
count(*) as nbr,
|
||||
(l.price_unit*l.product_qty)::decimal(16,2) as price_total,
|
||||
sum(l.price_unit*l.product_qty)::decimal(16,2) as price_total,
|
||||
avg(100.0 * (l.price_unit*l.product_qty) / NULLIF(t.standard_price*l.product_qty/u.factor*u2.factor, 0.0))::decimal(16,2) as negociation,
|
||||
|
||||
sum(t.standard_price*l.product_qty/u.factor*u2.factor)::decimal(16,2) as price_standard,
|
||||
(sum(l.product_qty*l.price_unit)/NULLIF(sum(l.product_qty/u.factor*u2.factor),0.0))::decimal(16,2) as price_average
|
||||
from purchase_order s
|
||||
left join purchase_order_line l on (s.id=l.order_id)
|
||||
from purchase_order_line l
|
||||
join purchase_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)
|
||||
where l.product_id is not null
|
||||
group by
|
||||
s.company_id,
|
||||
s.create_uid,
|
||||
s.partner_id,
|
||||
l.product_qty,
|
||||
u.factor,
|
||||
s.location_id,
|
||||
l.price_unit,
|
||||
|
|
|
@ -71,7 +71,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,
|
||||
|
@ -87,15 +87,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,
|
||||
|
|
|
@ -41,6 +41,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
|
||||
|
@ -49,7 +51,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,
|
||||
|
@ -67,15 +69,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,
|
||||
|
|
|
@ -399,15 +399,17 @@ class stock_location(osv.osv):
|
|||
uom_rounding = self.pool.get('product.product').browse(cr, uid, product_id, context=context).uom_id.rounding
|
||||
if context.get('uom'):
|
||||
uom_rounding = uom_obj.browse(cr, uid, context.get('uom'), context=context).rounding
|
||||
prodlot_id = context.get('prodlot_id', False)
|
||||
|
||||
locations_ids = self.search(cr, uid, [('location_id', 'child_of', ids)])
|
||||
if locations_ids:
|
||||
# Fetch only the locations in which this product has ever been processed (in or out)
|
||||
cr.execute("""SELECT l.id FROM stock_location l WHERE l.id in %s AND
|
||||
EXISTS (SELECT 1 FROM stock_move m WHERE m.product_id = %s
|
||||
AND (NOT BOOL(%s) OR m.prodlot_id=%s)
|
||||
AND ((state = 'done' AND m.location_dest_id = l.id)
|
||||
OR (state in ('done','assigned') AND m.location_id = l.id)))
|
||||
""", (tuple(locations_ids), product_id,))
|
||||
""", (tuple(locations_ids), product_id, prodlot_id, prodlot_id or None))
|
||||
locations_ids = [i for (i,) in cr.fetchall()]
|
||||
for id in locations_ids:
|
||||
if lock:
|
||||
|
@ -419,6 +421,7 @@ class stock_location(osv.osv):
|
|||
cr.execute("SAVEPOINT stock_location_product_reserve")
|
||||
cr.execute("""SELECT id FROM stock_move
|
||||
WHERE product_id=%s AND
|
||||
(NOT BOOL(%s) OR prodlot_id=%s) AND
|
||||
(
|
||||
(location_dest_id=%s AND
|
||||
location_id<>%s AND
|
||||
|
@ -428,7 +431,7 @@ class stock_location(osv.osv):
|
|||
location_dest_id<>%s AND
|
||||
state in ('done', 'assigned'))
|
||||
)
|
||||
FOR UPDATE of stock_move NOWAIT""", (product_id, id, id, id, id), log_exceptions=False)
|
||||
FOR UPDATE of stock_move NOWAIT""", (product_id, prodlot_id, prodlot_id or None, id, id, id, id), log_exceptions=False)
|
||||
except Exception:
|
||||
# Here it's likely that the FOR UPDATE NOWAIT failed to get the LOCK,
|
||||
# so we ROLLBACK to the SAVEPOINT to restore the transaction to its earlier
|
||||
|
@ -444,20 +447,22 @@ class stock_location(osv.osv):
|
|||
WHERE location_dest_id=%s AND
|
||||
location_id<>%s AND
|
||||
product_id=%s AND
|
||||
(NOT BOOL(%s) OR prodlot_id=%s) AND
|
||||
state='done'
|
||||
GROUP BY product_uom
|
||||
""",
|
||||
(id, id, product_id))
|
||||
(id, id, product_id, prodlot_id, prodlot_id or None))
|
||||
results = cr.dictfetchall()
|
||||
cr.execute("""SELECT product_uom,-sum(product_qty) AS product_qty
|
||||
FROM stock_move
|
||||
WHERE location_id=%s AND
|
||||
location_dest_id<>%s AND
|
||||
product_id=%s AND
|
||||
(NOT BOOL(%s) OR prodlot_id=%s) AND
|
||||
state in ('done', 'assigned')
|
||||
GROUP BY product_uom
|
||||
""",
|
||||
(id, id, product_id))
|
||||
(id, id, product_id, prodlot_id, prodlot_id or None))
|
||||
results += cr.dictfetchall()
|
||||
total = 0.0
|
||||
results2 = 0.0
|
||||
|
@ -1263,17 +1268,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
|
||||
|
@ -1289,6 +1294,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]
|
||||
|
@ -2166,8 +2174,12 @@ class stock_move(osv.osv):
|
|||
pickings[move.picking_id.id] = 1
|
||||
continue
|
||||
if move.state in ('confirmed', 'waiting'):
|
||||
ctx = context.copy()
|
||||
ctx.update({'uom': move.product_uom.id})
|
||||
if move.prodlot_id:
|
||||
ctx.update({'prodlot_id': move.prodlot_id.id})
|
||||
# Important: we must pass lock=True to _product_reserve() to avoid race conditions and double reservations
|
||||
res = self.pool.get('stock.location')._product_reserve(cr, uid, [move.location_id.id], move.product_id.id, move.product_qty, {'uom': move.product_uom.id}, lock=True)
|
||||
res = self.pool.get('stock.location')._product_reserve(cr, uid, [move.location_id.id], move.product_id.id, move.product_qty, context=ctx, lock=True)
|
||||
if res:
|
||||
#_product_available_test depends on the next status for correct functioning
|
||||
#the test does not work correctly if the same product occurs multiple times
|
||||
|
@ -2693,7 +2705,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:
|
||||
|
|
|
@ -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'),
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue