[MERGE] forward port branch saas-11 up to 2e972578b9
This commit is contained in:
@@ -265,12 +265,12 @@ class AccountBankStatement(models.Model):
|
||||
""" Changes statement state to Running."""
|
||||
for statement in self:
|
||||
if not statement.name:
|
||||
context = {'ir_sequence_date', statement.date}
|
||||
context = {'ir_sequence_date': statement.date}
|
||||
if statement.journal_id.sequence_id:
|
||||
st_number = statement.journal_id.sequence_id.with_context(context).next_by_id()
|
||||
st_number = statement.journal_id.sequence_id.with_context(**context).next_by_id()
|
||||
else:
|
||||
SequenceObj = self.env['ir.sequence']
|
||||
st_number = SequenceObj.with_context(context).next_by_code('account.bank.statement')
|
||||
st_number = SequenceObj.with_context(**context).next_by_code('account.bank.statement')
|
||||
statement.name = st_number
|
||||
statement.state = 'open'
|
||||
|
||||
|
||||
@@ -181,6 +181,8 @@ var DashBoard = form_common.FormWidget.extend({
|
||||
action = result,
|
||||
view_mode = action_attrs.view_mode;
|
||||
|
||||
if (!action) { return; }
|
||||
|
||||
// evaluate action_attrs context and domain
|
||||
action_attrs.context_string = action_attrs.context;
|
||||
action_attrs.context = pyeval.eval(
|
||||
|
||||
@@ -20,6 +20,8 @@ _logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def format_date(env, date, pattern=False):
|
||||
if not date:
|
||||
return ''
|
||||
date = datetime.datetime.strptime(date[:10], tools.DEFAULT_SERVER_DATE_FORMAT)
|
||||
lang_code = env.context.get('lang') or 'en_US'
|
||||
if not pattern:
|
||||
|
||||
@@ -1368,9 +1368,9 @@ class MailThread(models.AbstractModel):
|
||||
to_remove.append(node)
|
||||
if node.tag == 'img' and node.get('src', '').startswith('cid:'):
|
||||
cid = node.get('src').split(':', 1)[1]
|
||||
related_attachment = [attach for attach in attachments if len(attach) == 2 and attach[2] == cid]
|
||||
related_attachment = [attach for attach in attachments if attach[2] and attach[2].get('cid') == cid]
|
||||
if related_attachment:
|
||||
node.set('data-filename', related_attachment[0])
|
||||
node.set('data-filename', related_attachment[0][0])
|
||||
postprocessed = True
|
||||
|
||||
for node in to_remove:
|
||||
|
||||
@@ -59,8 +59,9 @@ function _parse_and_transform(nodes, transform_function) {
|
||||
}).join("");
|
||||
}
|
||||
|
||||
// suggested regexp (gruber url matching regexp, adapted to js, see https://gist.github.com/gruber/8891611)
|
||||
var url_regexp = /\b((?:https?:\/\/|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))/gi;
|
||||
// Suggested URL Javascript regex of http://stackoverflow.com/questions/3809401/what-is-a-good-regular-expression-to-match-a-url
|
||||
// Adapted to make http(s):// not required if (and only if) www. is given. So `should.notmatch` does not match.
|
||||
var url_regexp = /\b(?:https?:\/\/|(www\.))[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,13}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/gi;
|
||||
function linkify(text, attrs) {
|
||||
attrs = attrs || {};
|
||||
if (attrs.target === undefined) {
|
||||
|
||||
@@ -10,3 +10,4 @@ access_mass_mailing_system,mail.mass_mailing.system,model_mail_mass_mailing,base
|
||||
access_mail_mail_statistics_user,mail.mail.statistics,model_mail_mail_statistics,base.group_user,1,1,1,1
|
||||
access_mail_mail_statistics_mass_mailing_user,mail.mail.statistics,model_mail_mail_statistics,mass_mailing.group_mass_mailing_user,1,1,1,1
|
||||
access_mail_statistics_report,mail.statistics.report,model_mail_statistics_report,mass_mailing.group_mass_mailing_user,1,1,1,1
|
||||
access_utm_source,access_utm_source,utm.model_utm_source,mass_mailing.group_mass_mailing_user,1,1,1,0
|
||||
|
@@ -25,16 +25,16 @@
|
||||
</t>
|
||||
</t>
|
||||
<t t-jquery="tbody tr.paymentline.selected">
|
||||
this.removeAttr("class");
|
||||
this.attr('t-attf-class', 'paymentline selected #{line.mercury_swipe_pending ? "o_pos_mercury_swipe_pending" : ""}');
|
||||
this.removeAttr('class');
|
||||
this.attr('t-attf-class', 'paymentline selected #{line.mercury_swipe_pending ? \'o_pos_mercury_swipe_pending\' : \'\'}');
|
||||
</t>
|
||||
<t t-jquery="tbody tr.paymentline[t-att-data-cid*='line.cid']">
|
||||
this.removeAttr("class");
|
||||
this.attr('t-attf-class', 'paymentline #{line.mercury_swipe_pending ? "o_pos_mercury_swipe_pending" : ""}');
|
||||
this.removeAttr('class');
|
||||
this.attr('t-attf-class', 'paymentline #{line.mercury_swipe_pending ? \'o_pos_mercury_swipe_pending\' : \'\'}');
|
||||
</t>
|
||||
<t t-jquery="tbody tr td.col-tendered.edit">
|
||||
this.removeAttr("class");
|
||||
this.attr('t-attf-class', 'col-tendered edit #{line.mercury_swipe_pending ? "o_pos_mercury_swipe_pending" : ""}');
|
||||
this.removeAttr('class');
|
||||
this.attr('t-attf-class', 'col-tendered edit #{line.mercury_swipe_pending ? \'o_pos_mercury_swipe_pending\' : \'\'}');
|
||||
</t>
|
||||
</t>
|
||||
|
||||
|
||||
@@ -112,8 +112,9 @@ class SaleOrderLine(models.Model):
|
||||
def _compute_qty_delivered_updateable(self):
|
||||
for line in self:
|
||||
if line.product_id.type not in ('consu', 'product'):
|
||||
return super(SaleOrderLine, self)._compute_qty_delivered_updateable()
|
||||
line.qty_delivered_updateable = False
|
||||
super(SaleOrderLine, line)._compute_qty_delivered_updateable()
|
||||
else:
|
||||
line.qty_delivered_updateable = False
|
||||
|
||||
@api.onchange('product_id')
|
||||
def _onchange_product_id_set_customer_lead(self):
|
||||
|
||||
@@ -639,11 +639,11 @@ var FormView = View.extend(common.FieldManagerMixin, {
|
||||
}
|
||||
},
|
||||
disable_button: function () {
|
||||
this.$('.oe_form_buttons').add(this.$buttons).find('button').addClass('o_disabled').prop('disabled', true);
|
||||
this.$('.oe_form_buttons,.o_statusbar_buttons').add(this.$buttons).find('button').addClass('o_disabled').prop('disabled', true);
|
||||
this.is_disabled = true;
|
||||
},
|
||||
enable_button: function () {
|
||||
this.$('.oe_form_buttons').add(this.$buttons).find('button.o_disabled').removeClass('o_disabled').prop('disabled', false);
|
||||
this.$('.oe_form_buttons,.o_statusbar_buttons').add(this.$buttons).find('button.o_disabled').removeClass('o_disabled').prop('disabled', false);
|
||||
this.is_disabled = false;
|
||||
},
|
||||
on_button_save: function() {
|
||||
@@ -658,8 +658,10 @@ var FormView = View.extend(common.FieldManagerMixin, {
|
||||
self.to_view_mode();
|
||||
core.bus.trigger('do_reload_needaction');
|
||||
core.bus.trigger('form_view_saved', self);
|
||||
}).always(function() {
|
||||
self.enable_button();
|
||||
});
|
||||
}).always(function(){
|
||||
}).fail(function(){
|
||||
self.enable_button();
|
||||
});
|
||||
},
|
||||
|
||||
@@ -38,7 +38,7 @@ class WebsiteEventTrackController(http.Controller):
|
||||
for loc in locations.keys():
|
||||
if locations[loc] and (locations[loc][-1][2] > start_date):
|
||||
locations[loc][-1][3] += 1
|
||||
elif not locations[loc] or locations[loc][-1][2] < start_date:
|
||||
elif not locations[loc] or locations[loc][-1][2] <= start_date:
|
||||
locations[loc].append([False, locations[loc] and locations[loc][-1][2] or dates[0][0], start_date, 1])
|
||||
dates[-1][1][loc] = locations[loc][-1]
|
||||
forcetr = not bool(location)
|
||||
|
||||
@@ -306,6 +306,13 @@ actual arch.
|
||||
if view.type == 'qweb' and view.groups_id:
|
||||
raise ValidationError(_("Qweb view cannot have 'Groups' define on the record. Use 'groups' attributes inside the view definition"))
|
||||
|
||||
@api.constrains('inherit_id')
|
||||
def _check_000_inheritance(self):
|
||||
# NOTE: constraints methods are check alphabetically. Always ensure this method will be
|
||||
# called before other constraint metheods to avoid infinite loop in `read_combined`.
|
||||
if not self._check_recursion(parent='inherit_id'):
|
||||
raise ValidationError(_('You cannot create recursive inherited views.'))
|
||||
|
||||
_sql_constraints = [
|
||||
('inheritance_mode',
|
||||
"CHECK (mode != 'extension' OR inherit_id IS NOT NULL)",
|
||||
|
||||
@@ -8,6 +8,7 @@ from lxml import etree
|
||||
from lxml.builder import E
|
||||
from psycopg2 import IntegrityError
|
||||
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.tests import common
|
||||
from odoo.tools import mute_logger
|
||||
|
||||
@@ -231,6 +232,24 @@ class TestViewInheritance(ViewCase):
|
||||
self.assertFalse(self.View.default_view(model='does.not.exist', view_type='form'))
|
||||
self.assertFalse(self.View.default_view(model=self.model, view_type='graph'))
|
||||
|
||||
def test_no_recursion(self):
|
||||
r1 = self.makeView('R1')
|
||||
with self.assertRaises(ValidationError), self.cr.savepoint():
|
||||
r1.write({'inherit_id': r1.id})
|
||||
|
||||
r2 = self.makeView('R2', r1.id)
|
||||
r3 = self.makeView('R3', r2.id)
|
||||
with self.assertRaises(ValidationError), self.cr.savepoint():
|
||||
r2.write({'inherit_id': r3.id})
|
||||
|
||||
with self.assertRaises(ValidationError), self.cr.savepoint():
|
||||
r1.write({'inherit_id': r3.id})
|
||||
|
||||
with self.assertRaises(ValidationError), self.cr.savepoint():
|
||||
r1.write({
|
||||
'inherit_id': r1.id,
|
||||
'arch': self.arch_for('itself', parent=True),
|
||||
})
|
||||
|
||||
class TestApplyInheritanceSpecs(ViewCase):
|
||||
""" Applies a sequence of inheritance specification nodes to a base
|
||||
@@ -1249,4 +1268,4 @@ class TestQWebRender(ViewCase):
|
||||
content1 = self.env['ir.qweb'].with_context(check_view_ids=[view1.id, view2.id, view3.id]).render('base.dummy')
|
||||
content3 = self.env['ir.qweb'].with_context(check_view_ids=[view1.id, view2.id, view3.id]).render('base.dummy_primary_ext')
|
||||
|
||||
self.assertNotEqual(content1, content3)
|
||||
self.assertNotEqual(content1, content3)
|
||||
|
||||
Reference in New Issue
Block a user