[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:
Olivier Dony 2013-11-05 13:26:34 +01:00
commit 465c241338
15 changed files with 96 additions and 190 deletions

View File

@ -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

View File

@ -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]

View File

@ -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'

View File

@ -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:

View File

@ -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):

View File

@ -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)

View File

@ -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:

View File

@ -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:

View File

@ -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'):

View File

@ -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.

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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:

View File

@ -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'),
}