[MERGE] forward port of branch saas-9 up to 68f5163
This commit is contained in:
@@ -695,6 +695,9 @@ class AccountInvoice(models.Model):
|
|||||||
line2[tmp]['credit'] = (am < 0) and -am or 0.0
|
line2[tmp]['credit'] = (am < 0) and -am or 0.0
|
||||||
line2[tmp]['amount_currency'] += l['amount_currency']
|
line2[tmp]['amount_currency'] += l['amount_currency']
|
||||||
line2[tmp]['analytic_line_ids'] += l['analytic_line_ids']
|
line2[tmp]['analytic_line_ids'] += l['analytic_line_ids']
|
||||||
|
qty = l.get('quantity')
|
||||||
|
if qty:
|
||||||
|
line2[tmp]['quantity'] = line2[tmp].get('quantity', 0.0) + qty
|
||||||
else:
|
else:
|
||||||
line2[tmp] = l
|
line2[tmp] = l
|
||||||
line = []
|
line = []
|
||||||
|
|||||||
@@ -1091,8 +1091,11 @@ class AccountMoveLine(models.Model):
|
|||||||
}
|
}
|
||||||
bank = self.env["account.bank.statement"].browse(vals.get('statement_id'))
|
bank = self.env["account.bank.statement"].browse(vals.get('statement_id'))
|
||||||
if bank.currency_id != bank.company_id.currency_id:
|
if bank.currency_id != bank.company_id.currency_id:
|
||||||
|
ctx = {}
|
||||||
|
if 'date' in vals:
|
||||||
|
ctx['date'] = vals['date']
|
||||||
temp['currency_id'] = bank.currency_id.id
|
temp['currency_id'] = bank.currency_id.id
|
||||||
temp['amount_currency'] = bank.company_id.currency_id.compute(tax_vals['amount'], bank.currency_id, round=True)
|
temp['amount_currency'] = bank.company_id.currency_id.with_context(ctx).compute(tax_vals['amount'], bank.currency_id, round=True)
|
||||||
tax_lines_vals.append(temp)
|
tax_lines_vals.append(temp)
|
||||||
|
|
||||||
new_line = super(AccountMoveLine, self).create(vals)
|
new_line = super(AccountMoveLine, self).create(vals)
|
||||||
|
|||||||
@@ -41,7 +41,8 @@
|
|||||||
<field name="price_unit" widget="monetary"/>
|
<field name="price_unit" widget="monetary"/>
|
||||||
<field name="price_subtotal" invisible="1" widget="monetary"/>
|
<field name="price_subtotal" invisible="1" widget="monetary"/>
|
||||||
<field name="price_subtotal_incl" invisible="1" widget="monetary"/>
|
<field name="price_subtotal_incl" invisible="1" widget="monetary"/>
|
||||||
<field name="tax_ids" widget="many2many_tags"/>
|
<field name="tax_ids_after_fiscal_position" widget="many2many_tags"/>
|
||||||
|
<field name="tax_ids" invisible="1"/>
|
||||||
<field name="notice"/>
|
<field name="notice"/>
|
||||||
</group>
|
</group>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -711,8 +711,9 @@ class product_template(osv.osv):
|
|||||||
def copy(self, cr, uid, id, default=None, context=None):
|
def copy(self, cr, uid, id, default=None, context=None):
|
||||||
if default is None:
|
if default is None:
|
||||||
default = {}
|
default = {}
|
||||||
template = self.browse(cr, uid, id, context=context)
|
if 'name' not in default:
|
||||||
default['name'] = _("%s (copy)") % (template['name'])
|
template = self.browse(cr, uid, id, context=context)
|
||||||
|
default['name'] = _("%s (copy)") % (template['name'])
|
||||||
return super(product_template, self).copy(cr, uid, id, default=default, context=context)
|
return super(product_template, self).copy(cr, uid, id, default=default, context=context)
|
||||||
|
|
||||||
_defaults = {
|
_defaults = {
|
||||||
|
|||||||
@@ -4107,6 +4107,7 @@ class stock_location_path(osv.osv):
|
|||||||
'propagate': rule.propagate,
|
'propagate': rule.propagate,
|
||||||
'push_rule_id': rule.id,
|
'push_rule_id': rule.id,
|
||||||
'warehouse_id': rule.warehouse_id and rule.warehouse_id.id or False,
|
'warehouse_id': rule.warehouse_id and rule.warehouse_id.id or False,
|
||||||
|
'procurement_id': False,
|
||||||
}
|
}
|
||||||
|
|
||||||
def _apply(self, cr, uid, rule, move, context=None):
|
def _apply(self, cr, uid, rule, move, context=None):
|
||||||
|
|||||||
@@ -241,7 +241,7 @@ with directly by external objects or search view controls
|
|||||||
.. js:class:: openerp.web.search.Facet
|
.. js:class:: openerp.web.search.Facet
|
||||||
|
|
||||||
A `backbone model`_ representing a single facet of the current
|
A `backbone model`_ representing a single facet of the current
|
||||||
research. May map to a search field, or to a more complex or
|
search. May map to a search field, or to a more complex or
|
||||||
fuzzier input (e.g. a custom filter or an advanced search).
|
fuzzier input (e.g. a custom filter or an advanced search).
|
||||||
|
|
||||||
.. js:attribute:: category
|
.. js:attribute:: category
|
||||||
|
|||||||
@@ -69,7 +69,42 @@ Tour.register({
|
|||||||
waitFor: '.tab-pane:last tr:has(.oe_list_field_cell):not(:has(.oe_list_record_selector)):contains(user_test)',
|
waitFor: '.tab-pane:last tr:has(.oe_list_field_cell):not(:has(.oe_list_record_selector)):contains(user_test)',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// add ourself as participant
|
||||||
|
{
|
||||||
|
title: "change tab to Participants",
|
||||||
|
element: '[data-toggle="tab"]:contains(Participants)'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "click to add participants",
|
||||||
|
element: '.tab-pane:eq(2).active .oe_form_field_x2many_list_row_add a'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "select Admin",
|
||||||
|
element: '.modal .oe_list_content tr:has(td[data-field="name"]:containsExact(Administrator)) .oe_list_record_selector input[type="checkbox"]'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "save selected participants",
|
||||||
|
waitFor: '.modal .oe_list_content tr:has(td[data-field="name"]:containsExact(Administrator)) .oe_list_record_selector input[type="checkbox"]:propChecked',
|
||||||
|
element: '.o_selectcreatepopup_search_select'
|
||||||
|
},
|
||||||
|
|
||||||
|
// save
|
||||||
|
{
|
||||||
|
title: "save discussion",
|
||||||
|
waitFor: '.oe_form_field_many2many tbody tr td.oe_list_field_char:containsExact(Administrator)',
|
||||||
|
element: 'button.oe_form_button_save'
|
||||||
|
},
|
||||||
|
// edit
|
||||||
|
{
|
||||||
|
title: "edit discussion",
|
||||||
|
element: 'button.oe_form_button_edit'
|
||||||
|
},
|
||||||
|
|
||||||
// add message a
|
// add message a
|
||||||
|
{
|
||||||
|
title: "Select First Tab",
|
||||||
|
element: 'a[role=tab]:first',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: "create new message a",
|
title: "create new message a",
|
||||||
element: '.oe_form_field_x2many_list_row_add:first a'
|
element: '.oe_form_field_x2many_list_row_add:first a'
|
||||||
@@ -167,15 +202,10 @@ Tour.register({
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "click to add participants",
|
title: "click to add participants",
|
||||||
element: '.tab-pane:eq(1).active .oe_form_field_x2many_list_row_add a'
|
element: '.tab-pane:eq(2).active .oe_form_field_x2many_list_row_add a'
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "select Admin",
|
|
||||||
element: '.modal .oe_list_content tr:has(td[data-field="name"]:containsExact(Administrator)) .oe_list_record_selector input[type="checkbox"]'
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "select Demo User",
|
title: "select Demo User",
|
||||||
waitFor: '.modal .oe_list_content tr:has(td[data-field="name"]:containsExact(Administrator)) .oe_list_record_selector input[type="checkbox"]:propChecked',
|
|
||||||
element: '.modal .oe_list_content tr:has(td[data-field="name"]:containsExact(Demo User)) .oe_list_record_selector input[type="checkbox"]'
|
element: '.modal .oe_list_content tr:has(td[data-field="name"]:containsExact(Demo User)) .oe_list_record_selector input[type="checkbox"]'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -214,7 +244,7 @@ Tour.register({
|
|||||||
element: 'button.oe_form_button_edit'
|
element: 'button.oe_form_button_edit'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "change tab to Participants",
|
title: "change tab to Messages",
|
||||||
waitFor: '.oe_form_editable',
|
waitFor: '.oe_form_editable',
|
||||||
element: '[data-toggle="tab"]:contains(Messages)'
|
element: '[data-toggle="tab"]:contains(Messages)'
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
Austria, 2016-06-16
|
||||||
|
|
||||||
|
Seekda GmbH agrees to the terms of the Odoo Corporate Contributor License
|
||||||
|
Agreement v1.0.
|
||||||
|
|
||||||
|
I declare that I am authorized and able to make this agreement and sign this
|
||||||
|
declaration.
|
||||||
|
|
||||||
|
Signed,
|
||||||
|
|
||||||
|
Holger Lausen holger.lausen@seekda.com https://github.com/holgerlausen
|
||||||
|
|
||||||
|
List of contributors:
|
||||||
|
|
||||||
|
Holger Lausen holger.lausen@seekda.com https://github.com/holgerlausen
|
||||||
|
Florian Kisser florian.kisser@seekda.com https://github.com/floriankisser
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
Nicaragua, Jun 16th, 2016
|
||||||
|
|
||||||
|
I hereby agree to the terms of the Odoo Individual Contributor License Agreement v1.0.
|
||||||
|
|
||||||
|
I declare that I am authorized and able to make this agreement and sign this declaration.
|
||||||
|
|
||||||
|
Signed,
|
||||||
|
|
||||||
|
William Moreno williamjmorenor@gmail.com https://github.com/williamjmorenor
|
||||||
@@ -641,7 +641,7 @@ Model Reference
|
|||||||
.. automethod:: read
|
.. automethod:: read
|
||||||
.. automethod:: read_group
|
.. automethod:: read_group
|
||||||
|
|
||||||
.. rubric:: Research
|
.. rubric:: Searching
|
||||||
|
|
||||||
.. automethod:: search
|
.. automethod:: search
|
||||||
.. automethod:: search_count
|
.. automethod:: search_count
|
||||||
|
|||||||
@@ -822,7 +822,7 @@ attributes:
|
|||||||
|
|
||||||
``default_group_by``
|
``default_group_by``
|
||||||
whether the kanban view should be grouped if no grouping is specified via
|
whether the kanban view should be grouped if no grouping is specified via
|
||||||
the action or the current research. Should be the name of the field to group
|
the action or the current search. Should be the name of the field to group
|
||||||
by when no grouping is otherwise specified
|
by when no grouping is otherwise specified
|
||||||
``default_order``
|
``default_order``
|
||||||
cards sorting order used if the user has not already sorted the records (via
|
cards sorting order used if the user has not already sorted the records (via
|
||||||
|
|||||||
@@ -106,7 +106,7 @@
|
|||||||
</group>
|
</group>
|
||||||
<group string="Advanced Properties">
|
<group string="Advanced Properties">
|
||||||
<field name="serialization_field_id"
|
<field name="serialization_field_id"
|
||||||
domain="[('ttype','=','serialized'), ('model_id', '=', model_id)]"
|
domain="[('ttype','=','serialized'), ('model_id', '=', parent.model)]"
|
||||||
attrs="{'readonly': [('state','=','base')]}"/>
|
attrs="{'readonly': [('state','=','base')]}"/>
|
||||||
<field name="related"/>
|
<field name="related"/>
|
||||||
<field name="depends"/>
|
<field name="depends"/>
|
||||||
|
|||||||
@@ -439,9 +439,8 @@ class QWeb(orm.AbstractModel):
|
|||||||
d = qwebcontext.copy()
|
d = qwebcontext.copy()
|
||||||
|
|
||||||
if 'lang' in template_attributes:
|
if 'lang' in template_attributes:
|
||||||
init_lang = d.context.get('lang', 'en_US')
|
|
||||||
lang = template_attributes['lang']
|
lang = template_attributes['lang']
|
||||||
d.context['lang'] = self.eval(lang, d) or lang
|
d.context = dict(d.context, lang=self.eval(lang, d) or lang)
|
||||||
if not self.pool['res.lang'].search(d.cr, d.uid, [('code', '=', d.context['lang'])], count=True, context=d.context):
|
if not self.pool['res.lang'].search(d.cr, d.uid, [('code', '=', d.context['lang'])], count=True, context=d.context):
|
||||||
d.context['lang'] = qwebcontext.get('res_company') and qwebcontext.get('res_company').partner_id.lang or 'en_US'
|
d.context['lang'] = qwebcontext.get('res_company') and qwebcontext.get('res_company').partner_id.lang or 'en_US'
|
||||||
_logger.info("'%s' is not a valid language code, is an empty field or is not installed, falling back to %s" % (lang, d.context['lang']))
|
_logger.info("'%s' is not a valid language code, is an empty field or is not installed, falling back to %s" % (lang, d.context['lang']))
|
||||||
@@ -459,10 +458,6 @@ class QWeb(orm.AbstractModel):
|
|||||||
d['generated_attributes'] = generated_attributes
|
d['generated_attributes'] = generated_attributes
|
||||||
res = self.render(cr, uid, template, d)
|
res = self.render(cr, uid, template, d)
|
||||||
|
|
||||||
# we need to reset the lang after the rendering
|
|
||||||
if 'lang' in template_attributes:
|
|
||||||
d.context['lang'] = init_lang
|
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def render_tag_call_assets(self, element, template_attributes, generated_attributes, qwebcontext):
|
def render_tag_call_assets(self, element, template_attributes, generated_attributes, qwebcontext):
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ access_test_new_api_bravo,access_test_new_api_bravo,model_test_new_api_bravo,,1,
|
|||||||
access_category,test_new_api_category,test_new_api.model_test_new_api_category,,1,1,1,1
|
access_category,test_new_api_category,test_new_api.model_test_new_api_category,,1,1,1,1
|
||||||
access_discussion,test_new_api_discussion,test_new_api.model_test_new_api_discussion,,1,1,1,1
|
access_discussion,test_new_api_discussion,test_new_api.model_test_new_api_discussion,,1,1,1,1
|
||||||
access_message,test_new_api_message,test_new_api.model_test_new_api_message,,1,1,1,1
|
access_message,test_new_api_message,test_new_api.model_test_new_api_message,,1,1,1,1
|
||||||
|
access_emailmessage,test_new_api_emailmessage,test_new_api.model_test_new_api_emailmessage,,1,1,1,1
|
||||||
access_multi,test_new_api_multi,test_new_api.model_test_new_api_multi,,1,1,1,1
|
access_multi,test_new_api_multi,test_new_api.model_test_new_api_multi,,1,1,1,1
|
||||||
access_multi_line,test_new_api_multi_line,test_new_api.model_test_new_api_multi_line,,1,1,1,1
|
access_multi_line,test_new_api_multi_line,test_new_api.model_test_new_api_multi_line,,1,1,1,1
|
||||||
access_mixed,test_new_api_mixed,test_new_api.model_test_new_api_mixed,,1,1,1,1
|
access_mixed,test_new_api_mixed,test_new_api.model_test_new_api_mixed,,1,1,1,1
|
||||||
|
|||||||
|
@@ -130,6 +130,9 @@ class Discussion(models.Model):
|
|||||||
message_concat = fields.Text(string='Message concatenate')
|
message_concat = fields.Text(string='Message concatenate')
|
||||||
important_messages = fields.One2many('test_new_api.message', 'discussion',
|
important_messages = fields.One2many('test_new_api.message', 'discussion',
|
||||||
domain=[('important', '=', True)])
|
domain=[('important', '=', True)])
|
||||||
|
emails = fields.One2many('test_new_api.emailmessage', 'discussion')
|
||||||
|
important_emails = fields.One2many('test_new_api.emailmessage', 'discussion',
|
||||||
|
domain=[('important', '=', True)])
|
||||||
|
|
||||||
@api.onchange('moderator')
|
@api.onchange('moderator')
|
||||||
def _onchange_moderator(self):
|
def _onchange_moderator(self):
|
||||||
@@ -210,6 +213,14 @@ class Message(models.Model):
|
|||||||
return [('author.partner_id', operator, value)]
|
return [('author.partner_id', operator, value)]
|
||||||
|
|
||||||
|
|
||||||
|
class EmailMessage(models.Model):
|
||||||
|
_name = 'test_new_api.emailmessage'
|
||||||
|
_inherits = {'test_new_api.message': 'message'}
|
||||||
|
|
||||||
|
message = fields.Many2one('test_new_api.message', 'Message',
|
||||||
|
required=True, ondelete='cascade')
|
||||||
|
email_to = fields.Char('To')
|
||||||
|
|
||||||
class Multi(models.Model):
|
class Multi(models.Model):
|
||||||
""" Model for testing multiple onchange methods in cascade that modify a
|
""" Model for testing multiple onchange methods in cascade that modify a
|
||||||
one2many field several times.
|
one2many field several times.
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ class TestOnChange(common.TransactionCase):
|
|||||||
super(TestOnChange, self).setUp()
|
super(TestOnChange, self).setUp()
|
||||||
self.Discussion = self.env['test_new_api.discussion']
|
self.Discussion = self.env['test_new_api.discussion']
|
||||||
self.Message = self.env['test_new_api.message']
|
self.Message = self.env['test_new_api.message']
|
||||||
|
self.EmailMessage = self.env['test_new_api.emailmessage']
|
||||||
|
|
||||||
def test_default_get(self):
|
def test_default_get(self):
|
||||||
""" checking values returned by default_get() """
|
""" checking values returned by default_get() """
|
||||||
@@ -88,7 +89,7 @@ class TestOnChange(common.TransactionCase):
|
|||||||
self.assertEqual(field_onchange.get('messages'), '1')
|
self.assertEqual(field_onchange.get('messages'), '1')
|
||||||
self.assertItemsEqual(
|
self.assertItemsEqual(
|
||||||
strip_prefix('messages.', field_onchange),
|
strip_prefix('messages.', field_onchange),
|
||||||
['author', 'body', 'name', 'size'],
|
['author', 'body', 'name', 'size', 'important'],
|
||||||
)
|
)
|
||||||
|
|
||||||
# modify discussion name
|
# modify discussion name
|
||||||
@@ -104,6 +105,7 @@ class TestOnChange(common.TransactionCase):
|
|||||||
'body': BODY,
|
'body': BODY,
|
||||||
'author': USER.id,
|
'author': USER.id,
|
||||||
'size': len(BODY),
|
'size': len(BODY),
|
||||||
|
'important': False,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
@@ -117,12 +119,14 @@ class TestOnChange(common.TransactionCase):
|
|||||||
'body': message.body,
|
'body': message.body,
|
||||||
'author': message.author.name_get()[0],
|
'author': message.author.name_get()[0],
|
||||||
'size': message.size,
|
'size': message.size,
|
||||||
|
'important': message.important,
|
||||||
}),
|
}),
|
||||||
(0, 0, {
|
(0, 0, {
|
||||||
'name': "[%s] %s" % ("Foo", USER.name),
|
'name': "[%s] %s" % ("Foo", USER.name),
|
||||||
'body': BODY,
|
'body': BODY,
|
||||||
'author': USER.name_get()[0],
|
'author': USER.name_get()[0],
|
||||||
'size': len(BODY),
|
'size': len(BODY),
|
||||||
|
'important': False,
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
|
|
||||||
@@ -223,3 +227,71 @@ class TestOnChange(common.TransactionCase):
|
|||||||
self.assertIn('message_concat', result['value'])
|
self.assertIn('message_concat', result['value'])
|
||||||
self.assertEqual(result['value']['message_concat'],
|
self.assertEqual(result['value']['message_concat'],
|
||||||
"\n".join(["%s:%s" % (m.name, m.body) for m in discussion.messages]))
|
"\n".join(["%s:%s" % (m.name, m.body) for m in discussion.messages]))
|
||||||
|
|
||||||
|
def test_onchange_one2many_with_domain_on_related_field(self):
|
||||||
|
""" test the value of the one2many field when defined with a domain on a related field"""
|
||||||
|
discussion = self.env.ref('test_new_api.discussion_0')
|
||||||
|
demo = self.env.ref('base.user_demo')
|
||||||
|
|
||||||
|
# mimic UI behaviour, so we get subfields
|
||||||
|
# (we need at least subfield: 'important_emails.important')
|
||||||
|
view_info = self.Discussion.fields_view_get(
|
||||||
|
view_id=self.env.ref('test_new_api.discussion_form').id,
|
||||||
|
view_type='form')
|
||||||
|
field_onchange = self.Discussion._onchange_spec(view_info=view_info)
|
||||||
|
self.assertEqual(field_onchange.get('messages'), '1')
|
||||||
|
|
||||||
|
BODY = "What a beautiful day!"
|
||||||
|
USER = self.env.user
|
||||||
|
|
||||||
|
# create standalone email
|
||||||
|
email = self.EmailMessage.create({
|
||||||
|
'discussion': discussion.id,
|
||||||
|
'name': "[%s] %s" % ('', USER.name),
|
||||||
|
'body': BODY,
|
||||||
|
'author': USER.id,
|
||||||
|
'important': False,
|
||||||
|
'email_to': demo.email,
|
||||||
|
})
|
||||||
|
|
||||||
|
# check if server-side cache is working correctly
|
||||||
|
self.env.invalidate_all()
|
||||||
|
self.assertIn(email, discussion.emails)
|
||||||
|
self.assertNotIn(email, discussion.important_emails)
|
||||||
|
email.important = True
|
||||||
|
self.assertIn(email, discussion.important_emails)
|
||||||
|
|
||||||
|
# check that when trigger an onchange, we don't reset important emails
|
||||||
|
# (force `invalidate_all` as but appear in onchange only when we get a
|
||||||
|
# cache miss)
|
||||||
|
self.env.invalidate_all()
|
||||||
|
self.assertEqual(len(discussion.messages), 4)
|
||||||
|
values = {
|
||||||
|
'name': "Foo Bar",
|
||||||
|
'moderator': demo.id,
|
||||||
|
'categories': [(4, cat.id) for cat in discussion.categories],
|
||||||
|
'messages': [(4, msg.id) for msg in discussion.messages],
|
||||||
|
'participants': [(4, usr.id) for usr in discussion.participants],
|
||||||
|
'message_changes': 0,
|
||||||
|
'important_messages': [(4, msg.id) for msg in discussion.important_messages],
|
||||||
|
'important_emails': [(4, eml.id) for eml in discussion.important_emails],
|
||||||
|
}
|
||||||
|
result = discussion.onchange(values, 'name', field_onchange)
|
||||||
|
|
||||||
|
# When one2many domain contains non-computed field, things are ok
|
||||||
|
self.assertEqual(result['value']['important_messages'],
|
||||||
|
[(5,)] + [(4, msg.id) for msg in discussion.important_messages])
|
||||||
|
|
||||||
|
# But here with commit 5676d81, we get value of: [(2, email.id)]
|
||||||
|
self.assertEqual(
|
||||||
|
result['value']['important_emails'],
|
||||||
|
[(5,),
|
||||||
|
(1, email.id, {
|
||||||
|
'name': u'[Foo Bar] %s' % USER.name,
|
||||||
|
'body': email.body,
|
||||||
|
'author': USER.name_get()[0],
|
||||||
|
'important': True,
|
||||||
|
'email_to': demo.email,
|
||||||
|
'size': email.size,
|
||||||
|
})]
|
||||||
|
)
|
||||||
|
|||||||
@@ -59,12 +59,35 @@
|
|||||||
<tree string="Messages">
|
<tree string="Messages">
|
||||||
<field name="name"/>
|
<field name="name"/>
|
||||||
<field name="body"/>
|
<field name="body"/>
|
||||||
|
<field name="important"/>
|
||||||
</tree>
|
</tree>
|
||||||
<form string="Message" version="7.0">
|
<form string="Message" version="7.0">
|
||||||
<group>
|
<group>
|
||||||
<field name="name"/>
|
<field name="name"/>
|
||||||
<field name="author"/>
|
<field name="author"/>
|
||||||
<field name="size"/>
|
<field name="size"/>
|
||||||
|
<field name="important"/>
|
||||||
|
</group>
|
||||||
|
<label for="body"/>
|
||||||
|
<field name="body"/>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</page>
|
||||||
|
<page string="Emails">
|
||||||
|
<field name="important_emails">
|
||||||
|
<tree name="Important Messages">
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="body"/>
|
||||||
|
<field name="important"/>
|
||||||
|
<field name="email_to"/>
|
||||||
|
</tree>
|
||||||
|
<form string="Important Message" version="7.0">
|
||||||
|
<group>
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="author"/>
|
||||||
|
<field name="size"/>
|
||||||
|
<field name="important"/>
|
||||||
|
<field name="email_to"/>
|
||||||
</group>
|
</group>
|
||||||
<label for="body"/>
|
<label for="body"/>
|
||||||
<field name="body"/>
|
<field name="body"/>
|
||||||
|
|||||||
@@ -1025,6 +1025,13 @@ class Field(object):
|
|||||||
# ``records``, except fields currently being computed
|
# ``records``, except fields currently being computed
|
||||||
spec = []
|
spec = []
|
||||||
for field, path in records._field_triggers[self]:
|
for field, path in records._field_triggers[self]:
|
||||||
|
if not field.compute:
|
||||||
|
# Note: do not invalidate non-computed fields. Such fields may
|
||||||
|
# require invalidation in general (like *2many fields with
|
||||||
|
# domains) but should not be invalidated in this case, because
|
||||||
|
# we would simply lose their values during an onchange!
|
||||||
|
continue
|
||||||
|
|
||||||
target = env[field.model_name]
|
target = env[field.model_name]
|
||||||
computed = target.browse(env.computed[field])
|
computed = target.browse(env.computed[field])
|
||||||
if path == 'id' and field.model_name == records._name:
|
if path == 'id' and field.model_name == records._name:
|
||||||
|
|||||||
+1
-1
@@ -2632,8 +2632,8 @@ class BaseModel(object):
|
|||||||
self._init_column(cr, k, context=context)
|
self._init_column(cr, k, context=context)
|
||||||
# add the NOT NULL constraint
|
# add the NOT NULL constraint
|
||||||
try:
|
try:
|
||||||
cr.execute('ALTER TABLE "%s" ALTER COLUMN "%s" SET NOT NULL' % (self._table, k), log_exceptions=False)
|
|
||||||
cr.commit()
|
cr.commit()
|
||||||
|
cr.execute('ALTER TABLE "%s" ALTER COLUMN "%s" SET NOT NULL' % (self._table, k), log_exceptions=False)
|
||||||
_schema.debug("Table '%s': column '%s': added NOT NULL constraint",
|
_schema.debug("Table '%s': column '%s': added NOT NULL constraint",
|
||||||
self._table, k)
|
self._table, k)
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|||||||
@@ -961,7 +961,10 @@ class expression(object):
|
|||||||
if right is not False:
|
if right is not False:
|
||||||
if isinstance(right, basestring):
|
if isinstance(right, basestring):
|
||||||
op = {'!=': '=', 'not like': 'like', 'not ilike': 'ilike'}.get(operator, operator)
|
op = {'!=': '=', 'not like': 'like', 'not ilike': 'ilike'}.get(operator, operator)
|
||||||
ids2 = [x[0] for x in comodel.name_search(cr, uid, right, [], op, context=context, limit=None)]
|
domain = column._domain
|
||||||
|
if callable(domain):
|
||||||
|
domain = domain(model)
|
||||||
|
ids2 = [x[0] for x in comodel.name_search(cr, uid, right, domain or [], op, context=context, limit=None)]
|
||||||
if ids2:
|
if ids2:
|
||||||
operator = 'not in' if operator in NEGATIVE_TERM_OPERATORS else 'in'
|
operator = 'not in' if operator in NEGATIVE_TERM_OPERATORS else 'in'
|
||||||
elif isinstance(right, collections.Iterable):
|
elif isinstance(right, collections.Iterable):
|
||||||
@@ -1012,7 +1015,10 @@ class expression(object):
|
|||||||
if right is not False:
|
if right is not False:
|
||||||
if isinstance(right, basestring):
|
if isinstance(right, basestring):
|
||||||
op = {'!=': '=', 'not like': 'like', 'not ilike': 'ilike'}.get(operator, operator)
|
op = {'!=': '=', 'not like': 'like', 'not ilike': 'ilike'}.get(operator, operator)
|
||||||
res_ids = [x[0] for x in comodel.name_search(cr, uid, right, [], op, context=context, limit=None)]
|
domain = column._domain
|
||||||
|
if callable(domain):
|
||||||
|
domain = domain(model)
|
||||||
|
res_ids = [x[0] for x in comodel.name_search(cr, uid, right, domain or [], op, context=context, limit=None)]
|
||||||
if res_ids:
|
if res_ids:
|
||||||
operator = 'not in' if operator in NEGATIVE_TERM_OPERATORS else 'in'
|
operator = 'not in' if operator in NEGATIVE_TERM_OPERATORS else 'in'
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ class configmanager(object):
|
|||||||
# Not exposed in the configuration file.
|
# Not exposed in the configuration file.
|
||||||
self.blacklist_for_save = set([
|
self.blacklist_for_save = set([
|
||||||
'publisher_warranty_url', 'load_language', 'root_path',
|
'publisher_warranty_url', 'load_language', 'root_path',
|
||||||
'init', 'save', 'config', 'update', 'stop_after_init'
|
'init', 'save', 'config', 'update', 'stop_after_init', 'dev_mode'
|
||||||
])
|
])
|
||||||
|
|
||||||
# dictionary mapping option destination (keys in self.options) to MyOptions.
|
# dictionary mapping option destination (keys in self.options) to MyOptions.
|
||||||
|
|||||||
Reference in New Issue
Block a user