[MERGE] forward port of branch saas-6 up to a576f2b
This commit is contained in:
+49
-60
@@ -1544,75 +1544,64 @@ class calendar_event(osv.Model):
|
||||
return super(calendar_event, self)._name_search(cr, user, name=name, args=args, operator=operator, context=context, limit=limit, name_get_uid=name_get_uid)
|
||||
|
||||
def write(self, cr, uid, ids, values, context=None):
|
||||
def _only_changes_to_apply_on_real_ids(field_names):
|
||||
''' return True if changes are only to be made on the real ids'''
|
||||
for field in field_names:
|
||||
if field in ['start', 'start_date', 'start_datetime', 'stop', 'stop_date', 'stop_datetime', 'active']:
|
||||
return True
|
||||
return False
|
||||
|
||||
context = context or {}
|
||||
if not isinstance(ids, (tuple, list)):
|
||||
ids = [ids]
|
||||
|
||||
context = context or {}
|
||||
self._set_date(cr, uid, values, id=ids[0], context=context)
|
||||
values0 = values
|
||||
|
||||
for one_ids in ids:
|
||||
if isinstance(one_ids, (basestring, int, long)):
|
||||
if len(str(one_ids).split('-')) == 1:
|
||||
ids = [int(one_ids)]
|
||||
else:
|
||||
ids = [one_ids]
|
||||
# process events one by one
|
||||
for event_id in ids:
|
||||
# make a copy, since _set_date() modifies values depending on event
|
||||
values = dict(values0)
|
||||
self._set_date(cr, uid, values, event_id, context=context)
|
||||
|
||||
res = False
|
||||
new_id = False
|
||||
|
||||
# Special write of complex IDS
|
||||
for event_id in list(ids):
|
||||
if len(str(event_id).split('-')) == 1:
|
||||
continue
|
||||
|
||||
ids.remove(event_id)
|
||||
real_event_id = calendar_id2real_id(event_id)
|
||||
|
||||
# if we are setting the recurrency flag to False or if we are only changing fields that
|
||||
# should be only updated on the real ID and not on the virtual (like message_follower_ids):
|
||||
# then set real ids to be updated.
|
||||
if not values.get('recurrency', True) or not _only_changes_to_apply_on_real_ids(values.keys()):
|
||||
ids.append(real_event_id)
|
||||
continue
|
||||
# special write of complex IDS
|
||||
real_ids = []
|
||||
new_ids = []
|
||||
if '-' not in str(event_id):
|
||||
real_ids = [int(event_id)]
|
||||
else:
|
||||
data = self.read(cr, uid, event_id, ['start', 'stop', 'rrule', 'duration'])
|
||||
if data.get('rrule'):
|
||||
new_id = self._detach_one_event(cr, uid, event_id, values, context=None)
|
||||
real_event_id = calendar_id2real_id(event_id)
|
||||
|
||||
res = super(calendar_event, self).write(cr, uid, [int(event_id) for event_id in ids], values, context=context)
|
||||
|
||||
# set end_date for calendar searching
|
||||
if values.get('recurrency', True) and values.get('end_type', 'count') in ('count', unicode('count')) and \
|
||||
(values.get('rrule_type') or values.get('count') or values.get('start') or values.get('stop')):
|
||||
for id in ids:
|
||||
final_date = self._get_recurrency_end_date(cr, uid, id, context=context)
|
||||
super(calendar_event, self).write(cr, uid, [id], {'final_date': final_date}, context=context)
|
||||
|
||||
attendees_create = False
|
||||
if values.get('partner_ids', False):
|
||||
attendees_create = self.create_attendees(cr, uid, ids, context)
|
||||
|
||||
if (values.get('start_date') or values.get('start_datetime', False)) and values.get('active', True):
|
||||
the_id = new_id or (ids and int(ids[0]))
|
||||
if the_id:
|
||||
if attendees_create:
|
||||
attendees_create = attendees_create[the_id]
|
||||
mail_to_ids = list(set(attendees_create['old_attendee_ids']) - set(attendees_create['removed_attendee_ids']))
|
||||
# if we are setting the recurrency flag to False or if we are only changing fields that
|
||||
# should be only updated on the real ID and not on the virtual (like message_follower_ids):
|
||||
# then set real ids to be updated.
|
||||
blacklisted = any(key in values for key in ('start', 'stop', 'active'))
|
||||
if not values.get('recurrency', True) or not blacklisted:
|
||||
real_ids = [real_event_id]
|
||||
else:
|
||||
mail_to_ids = [att.id for att in self.browse(cr, uid, the_id, context=context).attendee_ids]
|
||||
data = self.read(cr, uid, event_id, ['start', 'stop', 'rrule', 'duration'])
|
||||
if data.get('rrule'):
|
||||
new_ids = [self._detach_one_event(cr, uid, event_id, values, context=None)]
|
||||
|
||||
if mail_to_ids:
|
||||
current_user = self.pool['res.users'].browse(cr, uid, uid, context=context)
|
||||
if self.pool['calendar.attendee']._send_mail_to_attendees(cr, uid, mail_to_ids, template_xmlid='calendar_template_meeting_changedate', email_from=current_user.email, context=context):
|
||||
self.message_post(cr, uid, the_id, body=_("A email has been send to specify that the date has been changed !"), subtype="calendar.subtype_invitation", context=context)
|
||||
return res or True and False
|
||||
super(calendar_event, self).write(cr, uid, real_ids, values, context=context)
|
||||
|
||||
# set end_date for calendar searching
|
||||
if values.get('recurrency') and values.get('end_type', 'count') in ('count', unicode('count')) and \
|
||||
(values.get('rrule_type') or values.get('count') or values.get('start') or values.get('stop')):
|
||||
for id in real_ids:
|
||||
final_date = self._get_recurrency_end_date(cr, uid, id, context=context)
|
||||
super(calendar_event, self).write(cr, uid, [id], {'final_date': final_date}, context=context)
|
||||
|
||||
attendees_create = False
|
||||
if values.get('partner_ids', False):
|
||||
attendees_create = self.create_attendees(cr, uid, real_ids + new_ids, context)
|
||||
|
||||
if (values.get('start_date') or values.get('start_datetime')) and values.get('active', True):
|
||||
for the_id in real_ids + new_ids:
|
||||
if attendees_create:
|
||||
attendees_create = attendees_create[the_id]
|
||||
mail_to_ids = list(set(attendees_create['old_attendee_ids']) - set(attendees_create['removed_attendee_ids']))
|
||||
else:
|
||||
mail_to_ids = [att.id for att in self.browse(cr, uid, the_id, context=context).attendee_ids]
|
||||
|
||||
if mail_to_ids:
|
||||
current_user = self.pool['res.users'].browse(cr, uid, uid, context=context)
|
||||
if self.pool['calendar.attendee']._send_mail_to_attendees(cr, uid, mail_to_ids, template_xmlid='calendar_template_meeting_changedate', email_from=current_user.email, context=context):
|
||||
self.message_post(cr, uid, the_id, body=_("A email has been send to specify that the date has been changed !"), subtype="calendar.subtype_invitation", context=context)
|
||||
|
||||
return True
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
if context is None:
|
||||
|
||||
@@ -91,5 +91,12 @@
|
||||
meetings = self.browse(cr, uid, meeting_ids, context)
|
||||
for meeting in meetings:
|
||||
assert meeting.description == 'Review code of the module: sync_google_calendar.', 'Description not changed for id: %s' %meeting.id
|
||||
|
||||
|
||||
-
|
||||
I update the description of two meetings, and check that both have been updated
|
||||
-
|
||||
!python {model: calendar.event}: |
|
||||
DESCRIPTION = "Some description"
|
||||
ids = [ref('calendar_event_testmeeting0'), ref('calendar_event_sprintreview0')]
|
||||
self.write(cr, uid, ids, {'description': DESCRIPTION}, context=context)
|
||||
for i, event in enumerate(self.browse(cr, uid, ids, context)):
|
||||
assert event.description == DESCRIPTION, "Event %d has not been updated" % i
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<field name="name">Partner Review</field>
|
||||
<field name="model_id" ref="base.model_res_partner"/>
|
||||
<field name="filter_id" ref="filter_partner"/>
|
||||
<field name="google_drive_template_url">https://docs.google.com/spreadsheet/ccc?key=0Ah2qnrLAoZmUdGRvdVdmS1VoSDctWk1kd18taGZ4ckE#gid=0</field>
|
||||
<field name="google_drive_template_url">https://docs.google.com/spreadsheet/ccc?key=1eIM-q7PX9wp1vEUUdUvrmAe8V3Do60vXDETulNmI9mA#gid=0</field>
|
||||
<field name="name_template">Partner Review %(name)s</field>
|
||||
</record>
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ class hr_payslip(osv.osv):
|
||||
def onchange_contract_id(self, cr, uid, ids, date_from, date_to, employee_id=False, contract_id=False, context=None):
|
||||
contract_obj = self.pool.get('hr.contract')
|
||||
res = super(hr_payslip, self).onchange_contract_id(cr, uid, ids, date_from=date_from, date_to=date_to, employee_id=employee_id, contract_id=contract_id, context=context)
|
||||
journal_id = contract_id and contract_obj.browse(cr, uid, contract_id, context=context).journal_id.id or False
|
||||
journal_id = contract_id and contract_obj.browse(cr, uid, contract_id, context=context).journal_id.id or (not contract_id and self._get_default_journal(cr, uid, context=None))
|
||||
res['value'].update({'journal_id': journal_id})
|
||||
return res
|
||||
|
||||
|
||||
@@ -38,6 +38,8 @@ class MailMailStats(osv.Model):
|
||||
if not self.pool.get(stat.model):
|
||||
continue
|
||||
target = self.pool[stat.model].browse(cr, uid, stat.res_id, context=context)
|
||||
if not target or not target.exists():
|
||||
continue
|
||||
email = ''
|
||||
for email_field in ('email', 'email_from'):
|
||||
if email_field in target and target[email_field]:
|
||||
|
||||
@@ -443,6 +443,8 @@ var Chrome = PosBaseWidget.extend({
|
||||
this.logo_click_time = 0;
|
||||
this.logo_click_count = 0;
|
||||
|
||||
this.previous_touch_y_coordinate = -1;
|
||||
|
||||
this.widget = {}; // contains references to subwidgets instances
|
||||
|
||||
this.cleanup_dom();
|
||||
@@ -537,12 +539,40 @@ var Chrome = PosBaseWidget.extend({
|
||||
}
|
||||
},
|
||||
|
||||
_scrollable: function(element, scrolling_down){
|
||||
var $element = $(element);
|
||||
var scrollable = true;
|
||||
|
||||
if (! scrolling_down && $element.scrollTop() <= 0) {
|
||||
scrollable = false;
|
||||
} else if (scrolling_down && $element.scrollTop() + $element.height() >= element.scrollHeight) {
|
||||
scrollable = false;
|
||||
}
|
||||
|
||||
return scrollable;
|
||||
},
|
||||
|
||||
disable_rubberbanding: function(){
|
||||
var self = this;
|
||||
|
||||
document.body.addEventListener('touchstart', function(event){
|
||||
self.previous_touch_y_coordinate = event.touches[0].clientY;
|
||||
});
|
||||
|
||||
// prevent the pos body from being scrollable.
|
||||
document.body.addEventListener('touchmove',function(event){
|
||||
var node = event.target;
|
||||
var current_touch_y_coordinate = event.touches[0].clientY;
|
||||
var scrolling_down;
|
||||
|
||||
if (current_touch_y_coordinate < self.previous_touch_y_coordinate) {
|
||||
scrolling_down = true;
|
||||
} else {
|
||||
scrolling_down = false;
|
||||
}
|
||||
|
||||
while(node){
|
||||
if(node.classList && node.classList.contains('touch-scrollable')){
|
||||
if(node.classList && node.classList.contains('touch-scrollable') && self._scrollable(node, scrolling_down)){
|
||||
return;
|
||||
}
|
||||
node = node.parentNode;
|
||||
|
||||
@@ -757,6 +757,9 @@ class ProcurementOrder(models.Model):
|
||||
taxes = self.product_id.supplier_taxes_id
|
||||
fpos = po.fiscal_position_id
|
||||
taxes_id = fpos.map_tax(taxes).ids if fpos else []
|
||||
if taxes_id:
|
||||
companies = self.env['res.company'].search([('id', 'child_of', self.company_id.id)])
|
||||
taxes_id = taxes_id.filtered(lambda x: x.company_id.id in companies).ids
|
||||
|
||||
price_unit = self.env['account.tax']._fix_tax_included_price(seller.price, self.product_id.supplier_taxes_id, taxes_id) if seller else 0.0
|
||||
if price_unit and seller and po.currency_id and seller.currency_id != po.currency_id:
|
||||
@@ -802,6 +805,7 @@ class ProcurementOrder(models.Model):
|
||||
'partner_id': partner.id,
|
||||
'picking_type_id': self.rule_id.picking_type_id.id,
|
||||
'company_id': self.company_id.id,
|
||||
'currency_id': partner.property_purchase_currency_id.id or self.env.user.company_id.currency_id.id,
|
||||
'dest_address_id': self.partner_dest_id.id,
|
||||
'origin': self.origin,
|
||||
'payment_term_id': partner.property_supplier_payment_term_id.id,
|
||||
|
||||
+35
-9
@@ -1636,7 +1636,7 @@ class stock_picking(models.Model):
|
||||
"""
|
||||
if not context:
|
||||
context = {}
|
||||
|
||||
notrack_context = dict(context, mail_notrack=True)
|
||||
stock_move_obj = self.pool.get('stock.move')
|
||||
self.create_lots_for_picking(cr, uid, ids, context=context)
|
||||
for picking in self.browse(cr, uid, ids, context=context):
|
||||
@@ -1664,7 +1664,7 @@ class stock_picking(models.Model):
|
||||
todo_move_ids.append(move.id)
|
||||
elif float_compare(remaining_qty,0, precision_rounding = move.product_id.uom_id.rounding) > 0 and \
|
||||
float_compare(remaining_qty, move.product_qty, precision_rounding = move.product_id.uom_id.rounding) < 0:
|
||||
new_move = stock_move_obj.split(cr, uid, move, remaining_qty, context=context)
|
||||
new_move = stock_move_obj.split(cr, uid, move, remaining_qty, context=notrack_context)
|
||||
todo_move_ids.append(move.id)
|
||||
#Assign move as it was assigned before
|
||||
toassign_move_ids.append(new_move)
|
||||
@@ -1674,7 +1674,7 @@ class stock_picking(models.Model):
|
||||
self.rereserve_quants(cr, uid, picking, move_ids=todo_move_ids, context=context)
|
||||
self.do_recompute_remaining_quantities(cr, uid, [picking.id], context=context)
|
||||
if todo_move_ids and not context.get('do_only_split'):
|
||||
self.pool.get('stock.move').action_done(cr, uid, todo_move_ids, context=context)
|
||||
self.pool.get('stock.move').action_done(cr, uid, todo_move_ids, context=notrack_context)
|
||||
elif context.get('do_only_split'):
|
||||
context = dict(context, split=todo_move_ids)
|
||||
self._create_backorder(cr, uid, picking, context=context)
|
||||
@@ -2103,14 +2103,29 @@ class stock_move(osv.osv):
|
||||
self.pool['procurement.order'].run(cr, uid, res, context=context)
|
||||
return res
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
picking_obj = self.pool['stock.picking']
|
||||
track = not context.get('mail_notrack') and vals.get('picking_id')
|
||||
if track:
|
||||
picking = picking_obj.browse(cr, uid, vals['picking_id'], context=context)
|
||||
initial_values = {picking.id: {'state': picking.state}}
|
||||
res = super(stock_move, self).create(cr, uid, vals, context=context)
|
||||
if track:
|
||||
picking_obj.message_track(cr, uid, [vals['picking_id']], picking_obj.fields_get(cr, uid, ['state'], context=context), initial_values, context=context)
|
||||
return res
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
if isinstance(ids, (int, long)):
|
||||
ids = [ids]
|
||||
picking_obj = self.pool['stock.picking']
|
||||
# Check that we do not modify a stock.move which is done
|
||||
frozen_fields = set(['product_qty', 'product_uom', 'location_id', 'location_dest_id', 'product_id'])
|
||||
for move in self.browse(cr, uid, ids, context=context):
|
||||
moves = self.browse(cr, uid, ids, context=context)
|
||||
for move in moves:
|
||||
if move.state == 'done':
|
||||
if frozen_fields.intersection(vals):
|
||||
raise UserError(_('Quantities, Units of Measure, Products and Locations cannot be modified on stock moves that have already been processed (except by the Administrator).'))
|
||||
@@ -2147,7 +2162,18 @@ class stock_move(osv.osv):
|
||||
#Note that, for pulled moves we intentionally don't propagate on the procurement.
|
||||
if propagated_changes_dict:
|
||||
self.write(cr, uid, [move.move_dest_id.id], propagated_changes_dict, context=context)
|
||||
return super(stock_move, self).write(cr, uid, ids, vals, context=context)
|
||||
track_pickings = not context.get('mail_notrack') and any(field in vals for field in ['state', 'picking_id', 'partially_available'])
|
||||
if track_pickings:
|
||||
to_track_picking_ids = set([move.picking_id.id for move in moves if move.picking_id])
|
||||
if vals.get('picking_id'):
|
||||
to_track_picking_ids.add(vals['picking_id'])
|
||||
to_track_picking_ids = list(to_track_picking_ids)
|
||||
pickings = picking_obj.browse(cr, uid, to_track_picking_ids, context=context)
|
||||
initial_values = dict((picking.id, {'state': picking.state}) for picking in pickings)
|
||||
res = super(stock_move, self).write(cr, uid, ids, vals, context=context)
|
||||
if track_pickings:
|
||||
picking_obj.message_track(cr, uid, to_track_picking_ids, picking_obj.fields_get(cr, uid, ['state'], context=context), initial_values, context=context)
|
||||
return res
|
||||
|
||||
def onchange_quantity(self, cr, uid, ids, product_id, product_qty, product_uom):
|
||||
""" On change of product quantity finds UoM
|
||||
@@ -2306,7 +2332,7 @@ class stock_move(osv.osv):
|
||||
|
||||
for state, write_ids in states.items():
|
||||
if len(write_ids):
|
||||
self.write(cr, uid, write_ids, {'state': state})
|
||||
self.write(cr, uid, write_ids, {'state': state}, context=context)
|
||||
#assign picking in batch for all confirmed move that share the same details
|
||||
for key, move_ids in to_assign.items():
|
||||
self._picking_assign(cr, uid, move_ids, context=context)
|
||||
@@ -2443,7 +2469,7 @@ class stock_move(osv.osv):
|
||||
"""
|
||||
procurement_obj = self.pool.get('procurement.order')
|
||||
context = context or {}
|
||||
procs_to_check = []
|
||||
procs_to_check = set()
|
||||
for move in self.browse(cr, uid, ids, context=context):
|
||||
if move.state == 'done':
|
||||
raise UserError(_('You cannot cancel a stock move that has been set to \'Done\'.'))
|
||||
@@ -2462,11 +2488,11 @@ class stock_move(osv.osv):
|
||||
self.write(cr, uid, [move.move_dest_id.id], {'state': 'confirmed'}, context=context)
|
||||
if move.procurement_id:
|
||||
# Does the same as procurement check, only eliminating a refresh
|
||||
procs_to_check.append(move.procurement_id.id)
|
||||
procs_to_check.add(move.procurement_id.id)
|
||||
|
||||
res = self.write(cr, uid, ids, {'state': 'cancel', 'move_dest_id': False}, context=context)
|
||||
if procs_to_check:
|
||||
procurement_obj.check(cr, uid, procs_to_check, context=context)
|
||||
procurement_obj.check(cr, uid, list(procs_to_check), context=context)
|
||||
return res
|
||||
|
||||
def _check_package_from_moves(self, cr, uid, ids, context=None):
|
||||
|
||||
@@ -50,7 +50,7 @@ class stock_history(osv.osv):
|
||||
if 'inventory_value' in fields:
|
||||
group_lines = {}
|
||||
for line in res:
|
||||
domain = line.get('__domain', [])
|
||||
domain = line.get('__domain', domain)
|
||||
group_lines.setdefault(str(domain), self.search(cr, uid, domain, context=context))
|
||||
line_ids = set()
|
||||
for ids in group_lines.values():
|
||||
@@ -75,7 +75,7 @@ class stock_history(osv.osv):
|
||||
histories_dict[(history['product_id'], history['company_id'])] = history['cost']
|
||||
for line in res:
|
||||
inv_value = 0.0
|
||||
lines = group_lines.get(str(line.get('__domain', [])))
|
||||
lines = group_lines.get(str(line.get('__domain', domain)))
|
||||
for line_id in lines:
|
||||
line_rec = lines_dict[line_id]
|
||||
product = products_dict[line_rec['product_id']]
|
||||
|
||||
@@ -355,7 +355,7 @@ class survey_survey(osv.Model):
|
||||
for cell in product(rows.keys(), answers.keys()):
|
||||
res[cell] = 0
|
||||
for input_line in question.user_input_line_ids:
|
||||
if input_line.answer_type == 'suggestion' and (not(current_filters) or input_line.user_input_id.id in current_filters):
|
||||
if input_line.answer_type == 'suggestion' and (not(current_filters) or input_line.user_input_id.id in current_filters) and input_line.value_suggested_row:
|
||||
res[(input_line.value_suggested_row.id, input_line.value_suggested.id)] += 1
|
||||
if input_line.answer_type == 'text' and (not(current_filters) or input_line.user_input_id.id in current_filters):
|
||||
comments.append(input_line)
|
||||
|
||||
@@ -799,6 +799,10 @@ var PivotView = View.extend({
|
||||
nbr_measures: nbr_measures,
|
||||
title: this.title,
|
||||
};
|
||||
if(table.measure_row.length + 1 > 256) {
|
||||
c.show_message(_t("For Excel compatibility, data cannot be exported if there is more than 256 columns.\n\nTip: try to flip axis, filter further or reduce the number of measures."));
|
||||
return;
|
||||
}
|
||||
session.get_file({
|
||||
url: '/web/pivot/export_xls',
|
||||
data: {data: JSON.stringify(table)},
|
||||
|
||||
@@ -198,7 +198,7 @@ class res_company(osv.osv):
|
||||
self.cache_restart(cr)
|
||||
return super(res_company, self).create(cr, uid, vals, context=context)
|
||||
obj_partner = self.pool.get('res.partner')
|
||||
partner_id = obj_partner.create(cr, uid, {'name': vals['name'], 'is_company':True, 'image': vals.get('logo', False)}, context=context)
|
||||
partner_id = obj_partner.create(cr, uid, {'name': vals['name'], 'is_company':True, 'image': vals.get('logo', False), 'customer': False}, context=context)
|
||||
vals.update({'partner_id': partner_id})
|
||||
self.cache_restart(cr)
|
||||
company_id = super(res_company, self).create(cr, uid, vals, context=context)
|
||||
|
||||
@@ -149,6 +149,9 @@ class Message(models.Model):
|
||||
size = fields.Integer(compute='_compute_size', search='_search_size')
|
||||
double_size = fields.Integer(compute='_compute_double_size')
|
||||
discussion_name = fields.Char(related='discussion.name')
|
||||
author_partner = fields.Many2one(
|
||||
'res.partner', compute='_compute_author_partner',
|
||||
search='_search_author_partner')
|
||||
|
||||
@api.one
|
||||
@api.constrains('author', 'discussion')
|
||||
@@ -194,6 +197,15 @@ class Message(models.Model):
|
||||
size = self.size
|
||||
self.double_size = self.double_size + size
|
||||
|
||||
@api.one
|
||||
@api.depends('author', 'author.partner_id')
|
||||
def _compute_author_partner(self):
|
||||
self.author_partner = author.partner_id
|
||||
|
||||
@api.model
|
||||
def _search_author_partner(self, operator, value):
|
||||
return [('author.partner_id', operator, value)]
|
||||
|
||||
|
||||
class MixedModel(models.Model):
|
||||
_name = 'test_new_api.mixed'
|
||||
|
||||
@@ -5,6 +5,7 @@ from datetime import date, datetime
|
||||
|
||||
from openerp.exceptions import AccessError
|
||||
from openerp.tests import common
|
||||
from openerp.tools import mute_logger
|
||||
|
||||
|
||||
class TestNewFields(common.TransactionCase):
|
||||
@@ -419,7 +420,31 @@ class TestNewFields(common.TransactionCase):
|
||||
self.assertEqual(message.name, "[%s] %s" % (discussion.name, ''))
|
||||
self.assertEqual(message.size, len(BODY))
|
||||
|
||||
def test_41_defaults(self):
|
||||
@mute_logger('openerp.addons.base.ir.ir_model')
|
||||
def test_41_new_related(self):
|
||||
""" test the behavior of related fields on new records. """
|
||||
discussion = self.env.ref('test_new_api.discussion_0')
|
||||
access = self.env.ref('test_new_api.access_discussion')
|
||||
|
||||
# make discussions unreadable for demo user
|
||||
access.write({'perm_read': False})
|
||||
|
||||
# create an environment for demo user
|
||||
demo_env = self.env(user=self.env.ref('base.user_demo'))
|
||||
self.assertEqual(demo_env.user.login, "demo")
|
||||
|
||||
# create a new message as demo user
|
||||
values = {'discussion': discussion.id}
|
||||
message = demo_env['test_new_api.message'].new(values)
|
||||
self.assertEqual(message.discussion, discussion)
|
||||
|
||||
# read the related field discussion_name
|
||||
self.assertEqual(message.discussion.env, demo_env)
|
||||
self.assertEqual(message.discussion_name, discussion.name)
|
||||
with self.assertRaises(AccessError):
|
||||
message.discussion.name
|
||||
|
||||
def test_50_defaults(self):
|
||||
""" test default values. """
|
||||
fields = ['discussion', 'body', 'author', 'size']
|
||||
defaults = self.env['test_new_api.message'].default_get(fields)
|
||||
@@ -428,6 +453,13 @@ class TestNewFields(common.TransactionCase):
|
||||
defaults = self.env['test_new_api.mixed'].default_get(['number'])
|
||||
self.assertEqual(defaults, {'number': 3.14})
|
||||
|
||||
def test_50_search_many2one(self):
|
||||
""" test search through a path of computed fields"""
|
||||
messages = self.env['test_new_api.message'].search(
|
||||
[('author_partner.name', '=', 'Demo User')])
|
||||
self.assertEqual(messages, self.env.ref('test_new_api.message_0_1'))
|
||||
|
||||
|
||||
|
||||
class TestMagicFields(common.TransactionCase):
|
||||
|
||||
|
||||
+4
-1
@@ -560,7 +560,10 @@ class Field(object):
|
||||
# when related_sudo, bypass access rights checks when reading values
|
||||
others = records.sudo() if self.related_sudo else records
|
||||
for record, other in zip(records, others):
|
||||
# do not switch to another environment if record is a draft one
|
||||
if not record.id:
|
||||
# draft records: copy record's cache to other's cache first
|
||||
for name, value in record._cache.iteritems():
|
||||
other[name] = value
|
||||
other, field = self.traverse_related(other if record.id else record)
|
||||
record[self.name] = other[field.name]
|
||||
|
||||
|
||||
@@ -852,12 +852,12 @@ class expression(object):
|
||||
# as after transforming the column, it will go through this loop once again
|
||||
# ----------------------------------------
|
||||
|
||||
elif len(path) > 1 and column._type == 'many2one' and column._auto_join:
|
||||
elif len(path) > 1 and column and column._type == 'many2one' and column._auto_join:
|
||||
# res_partner.state_id = res_partner__state_id.id
|
||||
leaf.add_join_context(comodel, path[0], 'id', path[0])
|
||||
push(create_substitution_leaf(leaf, (path[1], operator, right), comodel))
|
||||
|
||||
elif len(path) > 1 and column._type == 'one2many' and column._auto_join:
|
||||
elif len(path) > 1 and column and column._type == 'one2many' and column._auto_join:
|
||||
# res_partner.id = res_partner__bank_ids.partner_id
|
||||
leaf.add_join_context(comodel, 'id', column._fields_id, path[0])
|
||||
domain = column._domain(model) if callable(column._domain) else column._domain
|
||||
@@ -868,16 +868,16 @@ class expression(object):
|
||||
push(create_substitution_leaf(leaf, elem, comodel))
|
||||
push(create_substitution_leaf(leaf, AND_OPERATOR, comodel))
|
||||
|
||||
elif len(path) > 1 and column._auto_join:
|
||||
elif len(path) > 1 and column and column._auto_join:
|
||||
raise NotImplementedError('_auto_join attribute not supported on many2many column %s' % left)
|
||||
|
||||
elif len(path) > 1 and column._type == 'many2one':
|
||||
elif len(path) > 1 and column and column._type == 'many2one':
|
||||
right_ids = comodel.search(cr, uid, [(path[1], operator, right)], context=dict(context, active_test=False))
|
||||
leaf.leaf = (path[0], 'in', right_ids)
|
||||
push(leaf)
|
||||
|
||||
# Making search easier when there is a left operand as column.o2m or column.m2m
|
||||
elif len(path) > 1 and column._type in ['many2many', 'one2many']:
|
||||
elif len(path) > 1 and column and column._type in ['many2many', 'one2many']:
|
||||
right_ids = comodel.search(cr, uid, [(path[1], operator, right)], context=context)
|
||||
table_ids = model.search(cr, uid, [(path[0], 'in', right_ids)], context=dict(context, active_test=False))
|
||||
leaf.leaf = ('id', 'in', table_ids)
|
||||
@@ -894,7 +894,12 @@ class expression(object):
|
||||
domain = []
|
||||
else:
|
||||
# Let the field generate a domain.
|
||||
recs = model.browse(cr, uid, [], context)
|
||||
if len(path) > 1:
|
||||
right = comodel.search(
|
||||
cr, uid, [(path[1], operator, right)],
|
||||
context=context)
|
||||
operator = 'in'
|
||||
recs = model.browse(cr, uid, [], context=context)
|
||||
domain = field.determine_domain(recs, operator, right)
|
||||
|
||||
if not domain:
|
||||
|
||||
Reference in New Issue
Block a user