[MERGE] forward port branch saas-14 up to 8c692aac88

This commit is contained in:
Christophe Simonis
2018-02-21 18:09:17 +01:00
11 changed files with 65 additions and 19 deletions
+6
View File
@@ -181,6 +181,12 @@ msgid "<br><br>\n"
" You can insert canned responses in your message by typing <b>:shortcut</b>.<br>" " You can insert canned responses in your message by typing <b>:shortcut</b>.<br>"
msgstr "" msgstr ""
#. module: mail
#: code:addons/mail/models/mail_channel.py:475
#, python-format
msgid "<div class=\"o_mail_notification\">%(author)s invited %(new_partner)s to <a href=\"#\" class=\"o_channel_redirect\" data-oe-id=\"%(channel_id)s\">#%(channel_name)s</a></div>"
msgstr ""
#. module: mail #. module: mail
#: code:addons/mail/models/mail_channel.py:552 #: code:addons/mail/models/mail_channel.py:552
#, python-format #, python-format
+9 -1
View File
@@ -472,7 +472,15 @@ class Channel(models.Model):
partners_to_add = partners - channel.channel_partner_ids partners_to_add = partners - channel.channel_partner_ids
channel.write({'channel_last_seen_partner_ids': [(0, 0, {'partner_id': partner_id}) for partner_id in partners_to_add.ids]}) channel.write({'channel_last_seen_partner_ids': [(0, 0, {'partner_id': partner_id}) for partner_id in partners_to_add.ids]})
for partner in partners_to_add: for partner in partners_to_add:
notification = _('<div class="o_mail_notification">joined <a href="#" class="o_channel_redirect" data-oe-id="%s">#%s</a></div>') % (self.id, self.name,) if partner.id != self.env.user.partner_id.id:
notification = _('<div class="o_mail_notification">%(author)s invited %(new_partner)s to <a href="#" class="o_channel_redirect" data-oe-id="%(channel_id)s">#%(channel_name)s</a></div>') % {
'author': self.env.user.display_name,
'new_partner': partner.display_name,
'channel_id': channel.id,
'channel_name': channel.name,
}
else:
notification = _('<div class="o_mail_notification">joined <a href="#" class="o_channel_redirect" data-oe-id="%s">#%s</a></div>') % (channel.id, channel.name,)
self.message_post(body=notification, message_type="notification", subtype="mail.mt_comment", author_id=partner.id) self.message_post(body=notification, message_type="notification", subtype="mail.mt_comment", author_id=partner.id)
# broadcast the channel header to the added partner # broadcast the channel header to the added partner
+4
View File
@@ -199,6 +199,10 @@ var Thread = Widget.extend({
}); });
}, },
on_click_redirect: function (event) { on_click_redirect: function (event) {
// ignore inherited branding
if ($(event.target).data('oe-field') !== undefined) {
return;
}
var id = $(event.target).data('oe-id'); var id = $(event.target).data('oe-id');
if (id) { if (id) {
event.preventDefault(); event.preventDefault();
+5
View File
@@ -82,6 +82,11 @@ class MrpBom(models.Model):
if self.product_tmpl_id: if self.product_tmpl_id:
self.product_uom_id = self.product_tmpl_id.uom_id.id self.product_uom_id = self.product_tmpl_id.uom_id.id
@api.onchange('routing_id')
def onchange_routing_id(self):
for line in self.bom_line_ids:
line.operation_id = False
@api.multi @api.multi
def name_get(self): def name_get(self):
return [(bom.id, '%s%s' % (bom.code and '%s: ' % bom.code or '', bom.product_tmpl_id.display_name)) for bom in self] return [(bom.id, '%s%s' % (bom.code and '%s: ' % bom.code or '', bom.product_tmpl_id.display_name)) for bom in self]
+2 -4
View File
@@ -409,13 +409,11 @@ class Task(models.Model):
@api.onchange('project_id') @api.onchange('project_id')
def _onchange_project(self): def _onchange_project(self):
default_partner_id = self.env.context.get('default_partner_id')
default_partner = self.env['res.partner'].browse(default_partner_id) if default_partner_id else self.env['res.partner']
if self.project_id: if self.project_id:
self.partner_id = self.project_id.partner_id or default_partner if self.project_id.partner_id:
self.partner_id = self.project_id.partner_id
self.stage_id = self.stage_find(self.project_id.id, [('fold', '=', False)]) self.stage_id = self.stage_find(self.project_id.id, [('fold', '=', False)])
else: else:
self.partner_id = default_partner
self.stage_id = False self.stage_id = False
@api.onchange('user_id') @api.onchange('user_id')
+1 -1
View File
@@ -116,7 +116,7 @@ class SaleOrder(models.Model):
validity_date = fields.Date(string='Expiration Date', readonly=True, copy=False, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, validity_date = fields.Date(string='Expiration Date', readonly=True, copy=False, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]},
help="Manually set the expiration date of your quotation (offer), or it will set the date automatically based on the template if online quotation is installed.") help="Manually set the expiration date of your quotation (offer), or it will set the date automatically based on the template if online quotation is installed.")
create_date = fields.Datetime(string='Creation Date', readonly=True, index=True, help="Date on which sales order is created.") create_date = fields.Datetime(string='Creation Date', readonly=True, index=True, help="Date on which sales order is created.")
confirmation_date = fields.Datetime(string='Confirmation Date', readonly=True, index=True, help="Date on which the sales order is confirmed.", oldname="date_confirm") confirmation_date = fields.Datetime(string='Confirmation Date', readonly=True, index=True, help="Date on which the sales order is confirmed.", oldname="date_confirm", copy=False)
user_id = fields.Many2one('res.users', string='Salesperson', index=True, track_visibility='onchange', default=lambda self: self.env.user) user_id = fields.Many2one('res.users', string='Salesperson', index=True, track_visibility='onchange', default=lambda self: self.env.user)
partner_id = fields.Many2one('res.partner', string='Customer', readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, required=True, change_default=True, index=True, track_visibility='always') partner_id = fields.Many2one('res.partner', string='Customer', readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, required=True, change_default=True, index=True, track_visibility='always')
partner_invoice_id = fields.Many2one('res.partner', string='Invoice Address', readonly=True, required=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, help="Invoice address for current sales order.") partner_invoice_id = fields.Many2one('res.partner', string='Invoice Address', readonly=True, required=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, help="Invoice address for current sales order.")
+4 -2
View File
@@ -30,7 +30,7 @@ class StockHistory(models.Model):
# on the individual lines. # on the individual lines.
res = super(StockHistory, self).read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy) res = super(StockHistory, self).read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy)
if 'inventory_value' in fields: if 'inventory_value' in fields:
groupby_list = groupby if not lazy else groupby[:-1] groupby_list = groupby[:1] if lazy else groupby
date = self._context.get('history_date', fieldsDatetime.now()) date = self._context.get('history_date', fieldsDatetime.now())
# Step 2: retrieve the stock history lines. The result contains the 'expanded' # Step 2: retrieve the stock history lines. The result contains the 'expanded'
@@ -39,7 +39,9 @@ class StockHistory(models.Model):
fields_2 = set( fields_2 = set(
['id', 'product_id', 'price_unit_on_quant', 'company_id', 'quantity'] + groupby_list ['id', 'product_id', 'price_unit_on_quant', 'company_id', 'quantity'] + groupby_list
) )
tables, where_clause, where_clause_params = self._where_calc(domain).get_sql() query = self._where_calc(domain)
self._apply_ir_rules(query, 'read')
tables, where_clause, where_clause_params = query.get_sql()
select = "SELECT %s FROM %s WHERE %s " select = "SELECT %s FROM %s WHERE %s "
query = select % (','.join(fields_2), tables, where_clause) query = select % (','.join(fields_2), tables, where_clause)
self._cr.execute(query, where_clause_params) self._cr.execute(query, where_clause_params)
@@ -504,6 +504,17 @@ function swap(array, elem1, elem2) {
array[i1] = elem2; array[i1] = elem2;
} }
function is_email(value, allow_mailto) {
// http://stackoverflow.com/questions/46155/validate-email-address-in-javascript
var re;
if (allow_mailto) {
re = /^(mailto:)?(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i;
} else {
re = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i;
}
return re.test(value);
}
function toBoolElse (str, elseValues, trueValues, falseValues) { function toBoolElse (str, elseValues, trueValues, falseValues) {
var ret = _.str.toBool(str, trueValues, falseValues); var ret = _.str.toBool(str, trueValues, falseValues);
if (_.isUndefined(ret)) { if (_.isUndefined(ret)) {
@@ -569,6 +580,7 @@ return {
reject_after: reject_after, reject_after: reject_after,
delay: delay, delay: delay,
swap: swap, swap: swap,
is_email: is_email,
toBoolElse: toBoolElse, toBoolElse: toBoolElse,
async_when: async_when, async_when: async_when,
}; };
+10 -3
View File
@@ -5,6 +5,7 @@ var core = require('web.core');
var ajax = require('web.ajax'); var ajax = require('web.ajax');
var Dialog = require('web.Dialog'); var Dialog = require('web.Dialog');
var Widget = require('web.Widget'); var Widget = require('web.Widget');
var utils = require('web.utils');
var base = require('web_editor.base'); var base = require('web_editor.base');
var rte = require('web_editor.rte'); var rte = require('web_editor.rte');
@@ -1048,6 +1049,7 @@ var LinkDialog = Dialog.extend({
if (!$e.length) { if (!$e.length) {
$e = this.$('input.url-source:first'); $e = this.$('input.url-source:first');
} }
$e.closest('.form-group').removeClass('has-error');
var val = $e.val(); var val = $e.val();
var label = this.$('#o_link_dialog_label_input').val() || val; var label = this.$('#o_link_dialog_label_input').val() || val;
@@ -1068,8 +1070,7 @@ var LinkDialog = Dialog.extend({
var size = this.$("select.link-style").val() || ''; var size = this.$("select.link-style").val() || '';
var classes = (this.data.className || "") + (style && style.length ? " btn " : "") + style + " " + size; var classes = (this.data.className || "") + (style && style.length ? " btn " : "") + style + " " + size;
var isNewWindow = this.$('input.window-new').prop('checked'); var isNewWindow = this.$('input.window-new').prop('checked');
if ($e.hasClass('email-address') && (_.str.startsWith(val, 'mailto:') || (val.indexOf("@") !== -1 && !_.str.startsWith(val, 'http') && !_.str.startsWith(val, 'www')))) {
if ($e.hasClass('email-address') && $e.val().indexOf("@") !== -1) {
self.get_data_buy_mail(def, $e, isNewWindow, label, classes, test); self.get_data_buy_mail(def, $e, isNewWindow, label, classes, test);
} else { } else {
self.get_data_buy_url(def, $e, isNewWindow, label, classes, test); self.get_data_buy_url(def, $e, isNewWindow, label, classes, test);
@@ -1078,7 +1079,13 @@ var LinkDialog = Dialog.extend({
}, },
get_data_buy_mail: function (def, $e, isNewWindow, label, classes, test) { get_data_buy_mail: function (def, $e, isNewWindow, label, classes, test) {
var val = $e.val(); var val = $e.val();
def.resolve(val.indexOf("mailto:") === 0 ? val : 'mailto:' + val, isNewWindow, label, classes); if (utils.is_email(val, true)) {
def.resolve(val.indexOf("mailto:") === 0 ? val : 'mailto:' + val, isNewWindow, label, classes);
} else {
$e.closest('.form-group').addClass('has-error');
$e.focus();
def.reject();
}
}, },
get_data_buy_url: function (def, $e, isNewWindow, label, classes, test) { get_data_buy_url: function (def, $e, isNewWindow, label, classes, test) {
def.resolve($e.val(), isNewWindow, label, classes); def.resolve($e.val(), isNewWindow, label, classes);
+8 -1
View File
@@ -74,7 +74,14 @@ class SaleOrder(models.Model):
(0, 'Not mandatory on website quote validation'), (0, 'Not mandatory on website quote validation'),
(1, 'Immediate after website order validation'), (1, 'Immediate after website order validation'),
(2, 'Immediate after website order validation and save a token'), (2, 'Immediate after website order validation and save a token'),
], 'Payment', help="Require immediate payment by the customer when validating the order from the website quote") ], 'Payment', help="Require immediate payment by the customer when validating the order from the website quote", compute='_compute_require_payment', store=True)
@api.one
@api.depends('template_id')
def _compute_require_payment(self):
# Do not overwrite if the field is already set
if self.template_id and (self.require_payment is None or self.require_payment is False):
self.require_payment = self.template_id.require_payment
@api.multi @api.multi
def copy(self, default=None): def copy(self, default=None):
+4 -7
View File
@@ -617,14 +617,11 @@
<input type="hidden" t-if="len(product.product_variant_ids) == 1" class="product_id" name="product_id" t-att-value="product.product_variant_id.id"/> <input type="hidden" t-if="len(product.product_variant_ids) == 1" class="product_id" name="product_id" t-att-value="product.product_variant_id.id"/>
<t t-if="len(product.product_variant_ids) &gt; 1"> <t t-if="len(product.product_variant_ids) &gt; 1">
<label label-default="label-default" class="radio" t-foreach="product.product_variant_ids" t-as="variant_id"> <label label-default="label-default" class="radio" t-foreach="product.product_variant_ids" t-as="variant_id">
<input type="radio" name="product_id" class="js_product_change" t-att-checked="'checked' if variant_id_index == 0 else None" t-att-value="variant_id.id" t-att-data-lst_price="variant_id.lst_price" t-att-data-price="variant_id.price"/> <input type="radio" name="product_id" class="js_product_change" t-att-checked="'checked' if variant_id_index == 0 else ''" t-att-value="variant_id.id" t-att-data-lst_price="compute_currency(variant_id.lst_price)" t-att-data-price="variant_id.price"/>
<span t-esc="variant_id.name_get()[0][1]"/> <span t-esc="variant_id.name_get()[0][1]"/>
<span class="badge" t-if="variant_id.price_extra"> <t t-set="diff_price" t-value="variant_id.price - variant_id.product_tmpl_id.price"/>
<t t-esc="variant_id.price_extra > 0 and '+' or ''"/><span t-field="variant_id.price_extra" style="white-space: nowrap;" t-options='{ <span class="badge" t-if="diff_price != 0">
"widget": "monetary", <t t-esc="diff_price > 0 and '+' or '-'"/><span t-esc="abs(diff_price)" t-esc-options='{"widget": "monetary", "display_currency": "website.currency_id"}'/>
"from_currency": product.currency_id,
"display_currency": website.currency_id
}'/>
</span> </span>
</label> </label>
</t> </t>