")).then(function () {
self.$searchview_buttons = self.searchview.$buttons.contents();
+ // manually call do_search to generate the initial domain and filter
+ // the messages in the default channel
+ self.searchview.do_search();
});
this.renderSidebar();
@@ -681,7 +684,12 @@ var ChatAction = Widget.extend(ControlPanelMixin, {
contexts: [session.user_context],
});
this.domain = result.domain;
- this.fetch_and_render_thread();
+ if (this.channel) {
+ // initially (when _onSearch is called manually), there is no
+ // channel set yet, so don't try to fetch and render the thread as
+ // this will be done as soon as the default channel is set
+ this.fetch_and_render_thread();
+ }
},
});
diff --git a/addons/mail/static/src/xml/activity.xml b/addons/mail/static/src/xml/activity.xml
index 4cab7bff9ad..ba81df81a20 100644
--- a/addons/mail/static/src/xml/activity.xml
+++ b/addons/mail/static/src/xml/activity.xml
@@ -21,10 +21,7 @@
Edit |
diff --git a/addons/mrp/models/stock_move.py b/addons/mrp/models/stock_move.py
index 56ae367c27b..2ffae162cf4 100644
--- a/addons/mrp/models/stock_move.py
+++ b/addons/mrp/models/stock_move.py
@@ -282,7 +282,7 @@ class StockMove(models.Model):
preferred_domain_list = [preferred_domain] + [fallback_domain] + [fallback_domain2]
if move.has_tracking == 'none':
quants = quant_obj.quants_get_preferred_domain(move.product_qty, move, domain=main_domain, preferred_domain_list=preferred_domain_list)
- self.env['stock.quant'].quants_move(quants, move, move.location_dest_id)
+ self.env['stock.quant'].quants_move(quants, move, move.location_dest_id, owner_id=move.restrict_partner_id.id)
else:
for movelot in move.active_move_lot_ids:
if float_compare(movelot.quantity_done, 0, precision_rounding=rounding) > 0:
@@ -290,7 +290,7 @@ class StockMove(models.Model):
raise UserError(_('You need to supply a lot/serial number.'))
qty = move.product_uom._compute_quantity(movelot.quantity_done, move.product_id.uom_id)
quants = quant_obj.quants_get_preferred_domain(qty, move, lot_id=movelot.lot_id.id, domain=main_domain, preferred_domain_list=preferred_domain_list)
- self.env['stock.quant'].quants_move(quants, move, move.location_dest_id, lot_id = movelot.lot_id.id)
+ self.env['stock.quant'].quants_move(quants, move, move.location_dest_id, lot_id = movelot.lot_id.id, owner_id=move.restrict_partner_id.id)
moves_to_unreserve |= move
# Next move in production order
if move.move_dest_id and move.move_dest_id.state not in ('done', 'cancel'):
diff --git a/addons/purchase/models/purchase.py b/addons/purchase/models/purchase.py
index 385f04d403d..14edec1a3e8 100644
--- a/addons/purchase/models/purchase.py
+++ b/addons/purchase/models/purchase.py
@@ -1168,11 +1168,15 @@ class ProductCategory(models.Model):
class MailComposeMessage(models.TransientModel):
_inherit = 'mail.compose.message'
+ @api.multi
+ def mail_purchase_order_on_send(self):
+ if not self.filtered('subtype_id.internal'):
+ order = self.env['purchase.order'].browse(self._context['default_res_id'])
+ if order.state == 'draft':
+ order.state = 'sent'
+
@api.multi
def send_mail(self, auto_commit=False):
if self._context.get('default_model') == 'purchase.order' and self._context.get('default_res_id'):
- if not self.filtered('subtype_id.internal'):
- order = self.env['purchase.order'].browse([self._context['default_res_id']])
- if order.state == 'draft':
- order.state = 'sent'
+ self.mail_purchase_order_on_send()
return super(MailComposeMessage, self.with_context(mail_post_autofollow=True)).send_mail(auto_commit=auto_commit)
diff --git a/addons/purchase/views/account_invoice_views.xml b/addons/purchase/views/account_invoice_views.xml
index a85974931f4..7766d2b7c59 100644
--- a/addons/purchase/views/account_invoice_views.xml
+++ b/addons/purchase/views/account_invoice_views.xml
@@ -59,7 +59,7 @@
-
diff --git a/addons/sale/models/sale.py b/addons/sale/models/sale.py
index 563536a66c3..ee1e1336275 100644
--- a/addons/sale/models/sale.py
+++ b/addons/sale/models/sale.py
@@ -737,6 +737,18 @@ class SaleOrderLine(models.Model):
msg += _("Invoiced Quantity") + ": %s
" % (line.qty_invoiced,)
msg += ""
order.message_post(body=msg)
+
+ # Prevent writing on a locked SO.
+ protected_fields = self._get_protected_fields()
+ if 'done' in self.mapped('order_id.state') and any(f in values.keys() for f in protected_fields):
+ fields = self.env['ir.model.fields'].search([
+ ('name', 'in', protected_fields), ('model', '=', self._name)
+ ])
+ raise UserError(
+ _('It is forbidden to modify the following fields in a locked order:\n%s')
+ % '\n'.join(fields.mapped('field_description'))
+ )
+
result = super(SaleOrderLine, self).write(values)
if lines:
lines._action_procurement_create()
@@ -995,6 +1007,12 @@ class SaleOrderLine(models.Model):
return product[field_name] * uom_factor * cur_factor, currency_id.id
+ def _get_protected_fields(self):
+ return [
+ 'product_id', 'name', 'price_unit', 'product_uom', 'product_uom_qty',
+ 'tax_id', 'analytic_tag_ids'
+ ]
+
@api.onchange('product_id', 'price_unit', 'product_uom', 'product_uom_qty', 'tax_id')
def _onchange_discount(self):
self.discount = 0.0
diff --git a/addons/sale/wizard/sale_make_invoice_advance.py b/addons/sale/wizard/sale_make_invoice_advance.py
index 2b9caf659bb..ac7d9587d22 100644
--- a/addons/sale/wizard/sale_make_invoice_advance.py
+++ b/addons/sale/wizard/sale_make_invoice_advance.py
@@ -76,12 +76,14 @@ class SaleAdvancePaymentInv(models.TransientModel):
if self.amount <= 0.00:
raise UserError(_('The value of the down payment amount must be positive.'))
+ context = {'lang': order.partner_id.lang}
if self.advance_payment_method == 'percentage':
amount = order.amount_untaxed * self.amount / 100
name = _("Down payment of %s%%") % (self.amount,)
else:
amount = self.amount
name = _('Down Payment')
+ del context
taxes = self.product_id.taxes_id.filtered(lambda r: not order.company_id or r.company_id == order.company_id)
if order.fiscal_position_id and taxes:
tax_ids = order.fiscal_position_id.map_tax(taxes).ids
@@ -152,6 +154,7 @@ class SaleAdvancePaymentInv(models.TransientModel):
tax_ids = order.fiscal_position_id.map_tax(taxes).ids
else:
tax_ids = taxes.ids
+ context = {'lang': order.partner_id.lang}
so_line = sale_line_obj.create({
'name': _('Advance: %s') % (time.strftime('%m %Y'),),
'price_unit': amount,
@@ -163,6 +166,7 @@ class SaleAdvancePaymentInv(models.TransientModel):
'tax_id': [(6, 0, tax_ids)],
'is_downpayment': True,
})
+ del context
self._create_invoice(order, so_line, amount)
if self._context.get('open_invoices', False):
return sale_orders.action_view_invoice()
diff --git a/addons/stock/i18n/stock.pot b/addons/stock/i18n/stock.pot
index bd191d7f713..3e55cf043af 100644
--- a/addons/stock/i18n/stock.pot
+++ b/addons/stock/i18n/stock.pot
@@ -15,6 +15,22 @@ msgstr ""
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
+#. module: stock
+#: code:addons/stock/models/stock_move.py:230
+#, python-format
+msgid "\n"
+"\n"
+"%s --> Product UoM is %s (%s) - Move UoM is %s (%s)"
+msgstr ""
+
+#. module: stock
+#: code:addons/stock/models/stock_move.py:231
+#, python-format
+msgid "\n"
+"\n"
+"Blocking: %s"
+msgstr ""
+
#. module: stock
#: code:addons/stock/models/stock_move.py:214
#, python-format
diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py
index a6ec6b86359..a5b031f8205 100644
--- a/addons/stock/models/stock_move.py
+++ b/addons/stock/models/stock_move.py
@@ -223,10 +223,12 @@ class StockMove(models.Model):
@api.constrains('product_uom')
def _check_uom(self):
- moves_error = self.filtered(lambda move: move.product_id.uom_id.category_id.id != move.product_uom.category_id.id)
+ moves_error = self.filtered(lambda move: move.product_id.uom_id.category_id != move.product_uom.category_id)
if moves_error:
user_warning = _('You try to move a product using a UoM that is not compatible with the UoM of the product moved. Please use an UoM in the same UoM category.')
- user_warning += '\n\nBlocking: %s' % ' ,'.join(moves_error.mapped('name'))
+ for move in moves_error:
+ user_warning += _('\n\n%s --> Product UoM is %s (%s) - Move UoM is %s (%s)') % (move.product_id.display_name, move.product_id.uom_id.name, move.product_id.uom_id.category_id.name, move.product_uom.name, move.product_uom.category_id.name)
+ user_warning += _('\n\nBlocking: %s') % ' ,'.join(moves_error.mapped('name'))
raise UserError(user_warning)
@api.model_cr
diff --git a/addons/stock/models/stock_warehouse.py b/addons/stock/models/stock_warehouse.py
index 4769846760e..8a0fc23a7fe 100644
--- a/addons/stock/models/stock_warehouse.py
+++ b/addons/stock/models/stock_warehouse.py
@@ -457,6 +457,7 @@ class Warehouse(models.Model):
self.Routing(warehouse.lot_stock_id, warehouse.wh_pack_stock_loc_id, warehouse.pick_type_id),
self.Routing(warehouse.wh_pack_stock_loc_id, warehouse.wh_output_stock_loc_id, warehouse.pack_type_id),
self.Routing(warehouse.wh_output_stock_loc_id, customer_loc, warehouse.out_type_id)],
+ 'company_id': warehouse.company_id.id,
}) for warehouse in self)
@api.multi
@@ -466,6 +467,7 @@ class Warehouse(models.Model):
'product_categ_selectable': True,
'product_selectable': False,
'sequence': 10,
+ 'company_id': self.company_id.id,
}
@api.model
@@ -485,7 +487,8 @@ class Warehouse(models.Model):
'product_selectable': True,
'product_categ_selectable': True,
'supplied_wh_id': self.id,
- 'supplier_wh_id': supplier_warehouse.id}
+ 'supplier_wh_id': supplier_warehouse.id,
+ 'company_id': self.company_id.id}
def _get_crossdock_route_values(self):
return {
@@ -494,7 +497,8 @@ class Warehouse(models.Model):
'product_selectable': True,
'product_categ_selectable': True,
'active': self.delivery_steps != 'ship_only' and self.reception_steps != 'one_step',
- 'sequence': 20}
+ 'sequence': 20,
+ 'company_id': self.company_id.id}
# Pull / Push tools
# ------------------------------------------------------------
diff --git a/addons/stock/views/stock_quant_views.xml b/addons/stock/views/stock_quant_views.xml
index ad1f07d22b9..47bf98b9cc4 100644
--- a/addons/stock/views/stock_quant_views.xml
+++ b/addons/stock/views/stock_quant_views.xml
@@ -116,6 +116,7 @@
+
diff --git a/addons/stock_account/models/product.py b/addons/stock_account/models/product.py
index 1e4ac7ffbe1..751d182d30d 100644
--- a/addons/stock_account/models/product.py
+++ b/addons/stock_account/models/product.py
@@ -97,7 +97,9 @@ class ProductProduct(models.Model):
""" Changes the Standard Price of Product and creates an account move accordingly."""
AccountMove = self.env['account.move']
- locations = self.env['stock.location'].search([('usage', '=', 'internal'), ('company_id', '=', self.env.user.company_id.id)])
+ quant_locs = self.env['stock.quant'].sudo().read_group([('product_id', 'in', self.ids)], ['location_id'], ['location_id'])
+ quant_loc_ids = [loc['location_id'][0] for loc in quant_locs]
+ locations = self.env['stock.location'].search([('usage', '=', 'internal'), ('company_id', '=', self.env.user.company_id.id), ('id', 'in', quant_loc_ids)])
product_accounts = {product.id: product.product_tmpl_id.get_product_accounts() for product in self}
diff --git a/addons/website_forum/models/forum.py b/addons/website_forum/models/forum.py
index f77d8dca4fd..7864b95b72f 100644
--- a/addons/website_forum/models/forum.py
+++ b/addons/website_forum/models/forum.py
@@ -442,7 +442,7 @@ class Post(models.Model):
elif post.parent_id and not post.can_answer:
raise KarmaError('Not enough karma to answer to a question')
if not post.parent_id and not post.can_post:
- post.state = 'pending'
+ post.sudo().state = 'pending'
# add karma for posting new questions
if not post.parent_id and post.state == 'active':
@@ -471,11 +471,18 @@ class Post(models.Model):
@api.multi
def write(self, vals):
+ trusted_keys = ['active', 'is_correct', 'tag_ids'] # fields where security is checked manually
if 'content' in vals:
vals['content'] = self._update_content(vals['content'], self.forum_id.id)
if 'state' in vals:
- if vals['state'] in ['active', 'close'] and any(not post.can_close for post in self):
- raise KarmaError('Not enough karma to close or reopen a post.')
+ if vals['state'] in ['active', 'close']:
+ if any(not post.can_close for post in self):
+ raise KarmaError('Not enough karma to close or reopen a post.')
+ trusted_keys += ['state', 'closed_uid', 'closed_date', 'closed_reason_id']
+ elif vals['state'] == 'flagged':
+ if any(not post.can_flag for post in self):
+ raise KarmaError('Not enough karma to flag a post.')
+ trusted_keys += ['state', 'flag_user_id']
if 'active' in vals:
if any(not post.can_unlink for post in self):
raise KarmaError('Not enough karma to delete or reactivate a post')
@@ -492,7 +499,7 @@ class Post(models.Model):
tag_ids = set(tag.get('id') for tag in self.resolve_2many_commands('tag_ids', vals['tag_ids']))
if any(set(post.tag_ids) != tag_ids for post in self) and any(self.env.user.karma < post.forum_id.karma_edit_retag for post in self):
raise KarmaError(_('Not enough karma to retag.'))
- if any(key not in ['state', 'active', 'is_correct', 'closed_uid', 'closed_date', 'closed_reason_id', 'tag_ids'] for key in vals.keys()) and any(not post.can_edit for post in self):
+ if any(key not in trusted_keys for key in vals) and any(not post.can_edit for post in self):
raise KarmaError('Not enough karma to edit a post.')
res = super(Post, self).write(vals)
diff --git a/addons/website_forum/views/ir_qweb.xml b/addons/website_forum/views/ir_qweb.xml
index 671ae21944d..f823262d91b 100644
--- a/addons/website_forum/views/ir_qweb.xml
+++ b/addons/website_forum/views/ir_qweb.xml
@@ -5,9 +5,9 @@
diff --git a/addons/website_portal_sale/models/payment.py b/addons/website_portal_sale/models/payment.py
index 176f041847a..ace38093a69 100644
--- a/addons/website_portal_sale/models/payment.py
+++ b/addons/website_portal_sale/models/payment.py
@@ -12,6 +12,7 @@ class PaymentTransaction(models.Model):
# link with the sales order
sale_order_id = fields.Many2one('sale.order', string='Sales Order', auto_join=True)
+ so_state = fields.Selection('sale.order', string='Sale Order State', related='sale_order_id.state')
def _generate_and_pay_invoice(self, tx, acquirer_name):
tx.sale_order_id._force_lines_to_invoice_policy_order()
diff --git a/addons/website_quote/models/sale_order.py b/addons/website_quote/models/sale_order.py
index 6958fa11519..3fb4112240a 100644
--- a/addons/website_quote/models/sale_order.py
+++ b/addons/website_quote/models/sale_order.py
@@ -263,7 +263,8 @@ class SaleOrderOption(models.Model):
order_line = order.order_line.filtered(lambda line: line.product_id == self.product_id)
if order_line:
- order_line[0].product_uom_qty += 1
+ order_line = order_line[0]
+ order_line.product_uom_qty += 1
else:
vals = {
'price_unit': self.price_unit,