[MERGE] forward port branch saas-12 up to e8e4145

This commit is contained in:
Christophe Simonis
2016-10-17 16:00:39 +02:00
26 changed files with 226 additions and 63 deletions
+7 -4
View File
@@ -1037,10 +1037,13 @@ class AccountMoveLine(models.Model):
# the provided values were not already multi-currency
if account.currency_id and 'amount_currency' not in vals and account.currency_id.id != account.company_id.currency_id.id:
vals['currency_id'] = account.currency_id.id
ctx = {}
if 'date' in vals:
ctx['date'] = vals['date']
vals['amount_currency'] = account.company_id.currency_id.with_context(ctx).compute(amount, account.currency_id)
if self._context.get('skip_full_reconcile_check') == 'amount_currency_excluded':
vals['amount_currency'] = 0.0
else:
ctx = {}
if 'date' in vals:
ctx['date'] = vals['date']
vals['amount_currency'] = account.company_id.currency_id.with_context(ctx).compute(amount, account.currency_id)
if not ok:
raise UserError(_('You cannot use this general account in this journal, check the tab \'Entry Controls\' on the related journal.'))
@@ -455,6 +455,7 @@ msgstr ""
#. module: account_asset
#: model:ir.model.fields,field_description:account_asset.field_account_asset_category_account_depreciation_id
#: model:ir.ui.view,arch_db:account_asset.view_account_asset_asset_form
msgid "Depreciation Entries: Asset Account"
msgstr ""
+1 -1
View File
@@ -378,7 +378,7 @@ class AccountAssetAsset(models.Model):
@api.multi
def _compute_entries(self, date, group_entries=False):
depreciation_ids = self.env['account.asset.depreciation.line'].with_context(depreciation_date=date).search([
depreciation_ids = self.env['account.asset.depreciation.line'].search([
('asset_id', 'in', self.ids), ('depreciation_date', '<=', date),
('move_check', '=', False)])
if group_entries:
@@ -81,7 +81,7 @@ var FormViewBarcodeHandler = common.AbstractField.extend(BarcodeHandlerMixin, {
if (this.last_scanned_barcode) {
var new_qty = window.prompt(_t('Set quantity'), character) || "0";
new_qty = new_qty.replace(',', '.');
var record = this._get_records(field).find(function(record) {
var record = _.find(this._get_records(field), function (record) {
return record.get('product_barcode') === self.last_scanned_barcode;
});
if (record) {
@@ -159,8 +159,13 @@ var FormViewBarcodeHandler = common.AbstractField.extend(BarcodeHandlerMixin, {
},
_get_records: function(field) {
return field.viewmanager.active_view.controller.records || // tree view
field.viewmanager.active_view.controller.widgets; // kanban view
var active_view = field.viewmanager.active_view;
if (active_view.type === "kanban") {
return active_view.controller.widgets;
} else {
// tree view case
return active_view.controller.records.records;
}
},
});
+1 -1
View File
@@ -525,7 +525,7 @@
<field name="source_id" invisible="1"/>
<field name="stage_id"/>
<field name="planned_revenue" sum="Expected Revenues"/>
<field name="probability" />
<field name="probability" avg="Avg. of Probability"/>
<field name="team_id"/>
<field name="user_id"/>
<field name="referred" invisible="1"/>
+24 -1
View File
@@ -136,6 +136,7 @@ class HrExpense(models.Model):
'product_id': line.get('product_id'),
'product_uom_id': line.get('uom_id'),
'analytic_account_id': line.get('analytic_account_id'),
'payment_id': line.get('payment_id'),
}
@api.multi
@@ -185,7 +186,10 @@ class HrExpense(models.Model):
'journal_id': journal.id,
'company_id': self.env.user.company_id.id,
'date': acc_date,
'ref': ref
'ref': ref,
# force the name to the default value, to avoid an eventual 'default_name' in the context
# to set it to '' which cause no number to be given to the account.move when posted.
'name': '/',
})
for expense in expense_list:
company_currency = expense.company_id.currency_id
@@ -194,11 +198,29 @@ class HrExpense(models.Model):
move_lines = expense._move_line_get()
#create one more move line, a counterline for the total on payable account
payment_id = False
total, total_currency, move_lines = expense._compute_expense_totals(company_currency, move_lines, acc_date)
if expense.payment_mode == 'company_account':
if not expense.sheet_id.bank_journal_id.default_credit_account_id:
raise UserError(_("No credit account found for the %s journal, please configure one.") % (expense.sheet_id.bank_journal_id.name))
emp_account = expense.sheet_id.bank_journal_id.default_credit_account_id.id
journal = expense.bank_journal_id
#create payment
payment_methods = (total < 0) and journal.outbound_payment_method_ids or journal.inbound_payment_method_ids
journal_currency = journal.currency_id or journal.company_id.currency_id
payment = self.env['account.payment'].create({
'payment_method_id': payment_methods and payment_methods[0].id or False,
'payment_type': total < 0 and 'outbound' or 'inbound',
'partner_id': expense.employee_id.address_home_id.commercial_partner_id.id,
'partner_type': 'supplier',
'journal_id': journal.id,
'payment_date': expense.date,
'state': 'reconciled',
'currency_id': diff_currency_p and expense.currency_id.id or journal_currency.id,
'amount': diff_currency_p and abs(total_currency) or abs(total),
'name': expense.name,
})
payment_id = payment.id
else:
if not expense.employee_id.address_home_id:
raise UserError(_("No Home Address found for the employee %s, please configure one.") % (expense.employee_id.name))
@@ -212,6 +234,7 @@ class HrExpense(models.Model):
'date_maturity': acc_date,
'amount_currency': diff_currency_p and total_currency or False,
'currency_id': diff_currency_p and expense.currency_id.id or False,
'payment_id': payment_id,
})
#convert eml into an osv-valid format
@@ -462,7 +462,7 @@
<field name="account_id" ref="p11235"/>
<field name="refund_account_id" ref="p20011"/>
<field name="chart_template_id" ref="indian_chart_template_standard"/>
<field name="tag_ids" eval="[(6,0,[ref('st_tag_in_70'), ref('st_tag_in_21')])]"/>
<field name="tag_ids" eval="[(6, 0, [ref('st_tag_in_21'), ref('st_tag_in_66')])]"/>
</record>
<record id="input_tax_12" model="account.tax.template">
<field name="name">(standard)Input Sales Tax @ 12%</field>
@@ -474,7 +474,7 @@
<field name="account_id" ref="p11235"/>
<field name="refund_account_id" ref="p20011"/>
<field name="chart_template_id" ref="indian_chart_template_standard"/>
<field name="tag_ids" eval="[(6,0,[ref('st_tag_in_56')])]"/>
<field name="tag_ids" eval="[(6, 0, [ref('st_tag_in_18'), ref('st_tag_in_63')])]"/>
</record>
<record id="input_tax_4" model="account.tax.template">
<field name="name">(standard)Input Sales Tax @ 4%</field>
@@ -486,7 +486,7 @@
<field name="account_id" ref="p11235"/>
<field name="refund_account_id" ref="p20011"/>
<field name="chart_template_id" ref="indian_chart_template_standard"/>
<field name="tag_ids" eval="[(6,0,[ref('st_tag_in_15'), ref('st_tag_in_70')])]"/>
<field name="tag_ids" eval="[(6, 0, [ref('st_tag_in_15'), ref('st_tag_in_60')])]"/>
</record>
<record id="add_input_vat_1" model="account.tax.template">
<field name="name">(standard)Additional Input VAT @ 1%</field>
@@ -605,7 +605,7 @@
<field name="account_id" ref="p112341"/>
<field name="refund_account_id" ref="p20011"/>
<field name="chart_template_id" ref="indian_chart_template_standard"/>
<field name="tag_ids" eval="[(6,0,[ref('st_tag_in_25')])]"/>
<field name="tag_ids" eval="[(6, 0, [ref('st_tag_in_25'), ref('st_tag_in_63')])]"/>
</record>
<record id="sale_edu_cess_service_tax_2" model="account.tax.template">
<field name="name">(standard)Input Education Cess @ 2% On Service Tax</field>
+2 -5
View File
@@ -30,7 +30,6 @@ class AccountInvoice(models.Model):
]}
return result
def _prepare_invoice_line_from_po_line(self, line):
if line.product_id.purchase_method == 'purchase':
qty = line.product_qty - line.qty_invoiced
@@ -43,7 +42,7 @@ class AccountInvoice(models.Model):
invoice_line = self.env['account.invoice.line']
data = {
'purchase_line_id': line.id,
'name': line.name,
'name': self.purchase_id.name+': '+line.name,
'origin': self.purchase_id.origin,
'uom_id': line.product_uom.id,
'product_id': line.product_id.id,
@@ -52,6 +51,7 @@ class AccountInvoice(models.Model):
'quantity': qty,
'discount': 0.0,
'account_analytic_id': line.account_analytic_id.id,
'analytic_tag_ids': line.analytic_tag_ids.ids,
'invoice_line_tax_ids': invoice_line_tax_ids.ids
}
account = invoice_line.get_invoice_line_account('in_invoice', line.product_id, self.purchase_id.fiscal_position_id, self.env.user.company_id)
@@ -73,9 +73,6 @@ class AccountInvoice(models.Model):
if line in self.invoice_line_ids.mapped('purchase_line_id'):
continue
data = self._prepare_invoice_line_from_po_line(line)
account = new_lines.get_invoice_line_account('in_invoice', line.product_id, self.purchase_id.fiscal_position_id, self.env.user.company_id)
if account:
data['account_id'] = account.id
new_line = new_lines.new(data)
new_line._set_additional_fields(self)
new_lines += new_line
+4 -1
View File
@@ -10,10 +10,13 @@ class ProjectTaskType(models.Model):
_inherit = 'project.task.type'
def _default_domain_rating_template_id(self):
return [('model', '=', 'project.task')]
rating_template_id = fields.Many2one(
'mail.template',
string='Rating Email Template',
domain=[('model', '=', 'project.task')],
domain=lambda self: self._default_domain_rating_template_id(),
help="Select an email template. An email will be sent to the customer when the task reach this step.")
auto_validation_kanban_state = fields.Boolean('Automatic kanban status', default=False,
help="Automatically modify the kanban state when the customer reply to the feedback for this stage.\n"
@@ -28,6 +28,16 @@ class ProjectIssue(models.Model):
return super(ProjectIssue, self).rating_apply(rate, token=token, feedback=feedback, subtype="rating_project_issue.mt_issue_rating")
class Stage(models.Model):
_inherit = ['project.task.type']
def _default_domain_rating_template_id(self):
domain = super(Stage, self)._default_domain_rating_template_id()
return ['|'] + domain + [('model', '=', 'project.issue')]
class Project(models.Model):
_inherit = "project.project"
@@ -83,6 +83,10 @@ class SaleAdvancePaymentInv(models.TransientModel):
else:
amount = self.amount
name = _('Down Payment')
if order.fiscal_position_id and self.product_id.taxes_id:
tax_ids = order.fiscal_position_id.map_tax(self.product_id.taxes_id).ids
else:
tax_ids = self.product_id.taxes_id.ids
invoice = inv_obj.create({
'name': order.client_order_ref or order.name,
@@ -102,7 +106,7 @@ class SaleAdvancePaymentInv(models.TransientModel):
'uom_id': self.product_id.uom_id.id,
'product_id': self.product_id.id,
'sale_line_ids': [(6, 0, [so_line.id])],
'invoice_line_tax_ids': [(6, 0, [x.id for x in self.product_id.taxes_id])],
'invoice_line_tax_ids': [(6, 0, tax_ids)],
'account_analytic_id': order.project_id.id or False,
})],
'currency_id': order.pricelist_id.currency_id.id,
@@ -142,6 +146,10 @@ class SaleAdvancePaymentInv(models.TransientModel):
raise UserError(_('The product used to invoice a down payment should have an invoice policy set to "Ordered quantities". Please update your deposit product to be able to create a deposit invoice.'))
if self.product_id.type != 'service':
raise UserError(_("The product used to invoice a down payment should be of type 'Service'. Please use another product or update this product."))
if order.fiscal_position_id and self.product_id.taxes_id:
tax_ids = order.fiscal_position_id.map_tax(self.product_id.taxes_id).ids
else:
tax_ids = self.product_id.taxes_id.ids
so_line = sale_line_obj.create({
'name': _('Advance: %s') % (time.strftime('%m %Y'),),
'price_unit': amount,
@@ -150,7 +158,7 @@ class SaleAdvancePaymentInv(models.TransientModel):
'discount': 0.0,
'product_uom': self.product_id.uom_id.id,
'product_id': self.product_id.id,
'tax_id': [(6, 0, self.product_id.taxes_id.ids)],
'tax_id': [(6, 0, tax_ids)],
})
self._create_invoice(order, so_line, amount)
if self._context.get('open_invoices', False):
+4 -6
View File
@@ -91,14 +91,12 @@ class Inventory(models.Model):
('category', _('One product category')),
('product', _('One product only')),
('partial', _('Select products manually'))]
stock_settings = self.env['stock.config.settings'].search([], limit=1, order='id DESC')
if not stock_settings:
return res_filter
if stock_settings.group_stock_tracking_owner:
if self.user_has_groups('stock.group_tracking_owner'):
res_filter += [('owner', _('One owner only')), ('product_owner', _('One product for a specific owner'))]
if stock_settings.group_stock_production_lot:
if self.user_has_groups('stock.group_production_lot'):
res_filter.append(('lot', _('One Lot/Serial Number')))
if stock_settings.group_stock_tracking_lot:
if self.user_has_groups('stock.group_tracking_lot'):
res_filter.append(('pack', _('A Pack')))
return res_filter
+2 -5
View File
@@ -194,7 +194,6 @@ class StockMove(models.Model):
@api.multi
def _compute_string_qty_information(self):
StockConfig = self.env['stock.config.settings']
precision = self.env['decimal.precision'].precision_get('Product Unit of Measure')
void_moves = self.filtered(lambda move: move.state in ('draft', 'done', 'cancel') or move.location_id.usage != 'internal')
other_moves = self - void_moves
@@ -205,9 +204,7 @@ class StockMove(models.Model):
total_available = move.product_id.uom_id._compute_quantity(total_available, move.product_uom, round=False)
total_available = float_round(total_available, precision_digits=precision)
info = str(total_available)
# look in the settings if we need to display the UoM name or not
config = StockConfig.search([], limit=1, order='id DESC')
if config and config.group_uom:
if self.user_has_groups('product.group_uom'):
info += ' ' + move.product_uom.name
if move.reserved_availability:
if move.reserved_availability != total_available:
@@ -380,7 +377,7 @@ class StockMove(models.Model):
# if no specialized push rule has been found yet, we try to find a general one (without route)
rules = Push.search(domain + [('route_id', '=', False)], order='sequence')
# Make sure it is not returning the return
if rules and (not move.origin_returned_move_id or move.origin_returned_move_id.location_id.id != rules.location_dest_id.id):
if rules and (not move.origin_returned_move_id or move.origin_returned_move_id.location_dest_id.id != rules.location_dest_id.id):
rules._apply(move)
return True
+5
View File
@@ -115,6 +115,11 @@ class StockQuant(models.Model):
else:
self.with_context(force_company=company_from.id)._create_account_move_line(move, acc_valuation, acc_dest, journal_id)
if move.company_id.anglo_saxon_accounting and move.location_id.usage == 'supplier' and move.location_dest_id.usage == 'customer':
# Creates an account entry from stock_input to stock_output on a dropship move. https://github.com/odoo/odoo/issues/12687
journal_id, acc_src, acc_dest, acc_valuation = move._get_accounting_data_for_valuation()
self.with_context(force_company=move.company_id.id)._create_account_move_line(move, acc_src, acc_dest, journal_id)
def _create_account_move_line(self, move, credit_account_id, debit_account_id, journal_id):
# group quants by cost
quant_cost_qty = defaultdict(lambda: 0.0)
+3
View File
@@ -459,6 +459,9 @@ var ViewManager = Widget.extend(ControlPanelMixin, {
}
},
do_load_state: function(state, warm) {
if (state.view_type && state.view_type !== this.active_view.type) {
this.switch_mode(state.view_type, true);
}
this.active_view.controller.do_load_state(state, warm);
},
});
+1 -1
View File
@@ -1733,7 +1733,7 @@ var Column = Class.extend({
}
var aggregation_func = (this.sum && 'sum') || (this.avg && 'avg') ||
(this.max && 'max') || (this.min && 'min') || this.group_operator;
(this.max && 'max') || (this.min && 'min');
if (!aggregation_func) {
return {};
+30 -18
View File
@@ -113,25 +113,37 @@ return AbstractWebClient.extend({
}
},
on_hashchange: function(event) {
var self = this;
var stringstate = event.getState(false);
if (!_.isEqual(this._current_state, stringstate)) {
var state = event.getState(true);
if(!state.action && state.menu_id) {
self.menu.is_bound.done(function() {
self.menu.menu_click(state.menu_id);
});
} else {
state._push_me = false; // no need to push state back...
this.action_manager.do_load_state(state, !!this._current_state).then(function () {
var action = self.action_manager.get_inner_action();
if (action) {
self.menu.open_action(action.action_descr.id);
}
});
}
if (this._ignore_hashchange) {
this._ignore_hashchange = false;
return;
}
this._current_state = stringstate;
var self = this;
this.clear_uncommitted_changes().then(function () {
var stringstate = event.getState(false);
if (!_.isEqual(self._current_state, stringstate)) {
var state = event.getState(true);
if(!state.action && state.menu_id) {
self.menu.is_bound.done(function() {
self.menu.menu_click(state.menu_id);
});
} else {
state._push_me = false; // no need to push state back...
self.action_manager.do_load_state(state, !!self._current_state).then(function () {
var action = self.action_manager.get_inner_action();
if (action) {
self.menu.open_action(action.action_descr.id);
}
});
}
}
self._current_state = stringstate;
}, function () {
if (event) {
self._ignore_hashchange = true;
window.location = event.originalEvent.oldURL;
}
});
},
on_menu_action: function(options) {
var self = this;
@@ -31,6 +31,20 @@ class Blog(models.Model):
post_ids.write({'active': vals['active']})
return res
@api.multi
def message_post(self, parent_id=False, subtype=None, **kwargs):
""" Temporary workaround to avoid spam. If someone replies on a channel
through the 'Presentation Published' email, it should be considered as a
note as we don't want all channel followers to be notified of this answer. """
self.ensure_one()
if parent_id:
parent_message = self.env['mail.message'].sudo().browse(parent_id)
if parent_message.subtype_id and parent_message.subtype_id == self.env.ref('website_blog.mt_blog_blog_published'):
if kwargs.get('subtype_id'):
kwargs['subtype_id'] = False
subtype = 'mail.mt_note'
return super(Blog, self).message_post(parent_id=parent_id, subtype=subtype, **kwargs)
@api.multi
def all_tags(self, min_limit=1):
req = """
@@ -298,7 +298,7 @@
<div class="modal-body" id="sign-dialog">
<p>
<span>I agree that by signing this proposal, I
accept it on the behalf of </span><b t-field="quotation.company_id"/><span>, for an amount of </span>
accept it on the behalf of </span><b t-field="quotation.partner_id.commercial_partner_id"/><span>, for an amount of </span>
<b data-id="total_amount" t-field="quotation.amount_total"
t-options='{"widget": "monetary", "display_currency": quotation.pricelist_id.currency_id}'/>
<span>with payment terms: </span><b t-field="quotation.payment_term_id"/>.
@@ -325,7 +325,7 @@
<div class="modal-body" id="sign-dialog">
<p>
<span>I agree that by paying this proposal, I
accept it on the behalf of </span><b t-field="quotation.company_id"/><span>, for an amount of </span>
accept it on the behalf of </span><b t-field="quotation.partner_id.commercial_partner_id"/><span>, for an amount of </span>
<b data-id="total_amount" t-field="quotation.amount_total"
t-options='{"widget": "monetary", "display_currency": quotation.pricelist_id.currency_id}'/>
<span>with payment terms: </span><b t-field="quotation.payment_term_id"/>.
-1
View File
@@ -207,7 +207,6 @@ class Product(models.Model):
self.ensure_one()
return self.product_tmpl_id.website_publish_button()
class ProductAttribute(models.Model):
_inherit = "product.attribute"
+14
View File
@@ -164,6 +164,20 @@ class Channel(models.Model):
self.with_context(active_test=False).mapped('slide_ids').write({'active': vals['active']})
return res
@api.multi
def message_post(self, parent_id=False, subtype=None, **kwargs):
""" Temporary workaround to avoid spam. If someone replies on a channel
through the 'Presentation Published' email, it should be considered as a
note as we don't want all channel followers to be notified of this answer. """
self.ensure_one()
if parent_id:
parent_message = self.env['mail.message'].sudo().browse(parent_id)
if parent_message.subtype_id and parent_message.subtype_id == self.env.ref('website_slides.mt_channel_slide_published'):
if kwargs.get('subtype_id'):
kwargs['subtype_id'] = False
subtype = 'mail.mt_note'
return super(Channel, self).message_post(parent_id=parent_id, subtype=subtype, **kwargs)
class Category(models.Model):
""" Channel contain various categories to manage its slides """
@@ -3,5 +3,6 @@
from . import test_new_fields
from . import test_onchange
from . import test_attributes
from . import test_one2many
from . import test_ui
from . import test_domain
@@ -176,7 +176,7 @@ class TestOnChange(common.TransactionCase):
self.assertEqual(values, {
'name': partner.name,
'partner': partner.id,
'lines': [(5,), (4, line.id)],
'lines': [(6, 0, [line.id])],
})
# modify 'partner'
+11 -5
View File
@@ -894,10 +894,12 @@ class Field(object):
env.invalidate(spec)
else:
# simply write to the database, and update cache
# Write to database
write_value = self.convert_to_write(self.convert_to_record(value, record), record)
record.write({self.name: write_value})
record._cache[self] = value
# Update the cache unless value contains a new record
if not (self.relational and not all(value)):
record._cache[self] = value
############################################################################
#
@@ -1987,7 +1989,7 @@ class _RelationalMulti(_Relational):
def convert_to_write(self, value, record):
# make result with new and existing records
result = [(5,)]
result = [(6, 0, [])]
for record in value:
if not record.id:
values = {name: record[name] for name in record._cache}
@@ -1998,7 +2000,7 @@ class _RelationalMulti(_Relational):
values = record._convert_to_write(values)
result.append((1, record.id, values))
else:
result.append((4, record.id))
result[0][2].append(record.id)
return result
def convert_to_onchange(self, value, record, fnames=()):
@@ -2171,7 +2173,11 @@ class One2many(_RelationalMulti):
query = "SELECT id FROM %s WHERE %s=%%s AND id <> ALL(%%s)" % (comodel._table, inverse)
comodel._cr.execute(query, (record.id, act[2] or [0]))
lines = comodel.browse([row[0] for row in comodel._cr.fetchall()])
lines.write({inverse: False})
inverse_field = comodel._fields[inverse]
if inverse_field.ondelete == 'cascade':
lines.unlink()
else:
lines.write({inverse: False})
class Many2many(_RelationalMulti):
+1 -2
View File
@@ -3508,8 +3508,7 @@ class BaseModel(object):
``(6, _, ids)``
replaces all existing records in the set by the ``ids`` list,
equivalent to using the command ``5`` followed by a command
``4`` for each ``id`` in ``ids``. Can not be used on
:class:`~odoo.fields.One2many`.
``4`` for each ``id`` in ``ids``.
.. note:: Values marked as ``_`` in the list above are ignored and
can be anything, generally ``0`` or ``False``.
@@ -0,0 +1,65 @@
# -*- coding: utf-8 -*-
from openerp.tests.common import TransactionCase
class One2manyCase(TransactionCase):
def setUp(self):
super(One2manyCase, self).setUp()
self.Line = self.env["test_new_api.multi.line"]
self.multi = self.env["test_new_api.multi"].create({
"name": "What is up?"
})
def operations(self):
"""Run operations on o2m fields to check all works fine."""
# Check the lines first
self.assertItemsEqual(
self.multi.lines.mapped('name'),
map(str, range(10)))
# Modify the first line and drop the last one
self.multi.lines[0].name = "hello"
self.multi.lines = self.multi.lines[:-1]
self.assertEqual(len(self.multi.lines), 9)
self.assertIn("hello", self.multi.lines.mapped('name'))
# Invalidate the cache and check again; this crashes if the value
# of self.multi.lines in cache contains new records
self.multi.invalidate_cache()
self.assertEqual(len(self.multi.lines), 9)
self.assertIn("hello", self.multi.lines.mapped('name'))
def test_new_one_by_one(self):
"""Check lines created with ``new()`` and appended one by one."""
for name in range(10):
self.multi.lines |= self.Line.new({"name": str(name)})
self.operations()
def test_new_single(self):
"""Check lines created with ``new()`` and added in one step."""
self.multi.lines = self.Line.browse(
[self.Line.new({"name": str(name)}).id for name in range(10)]
)
self.operations()
def test_create_one_by_one(self):
"""Check lines created with ``create()`` and appended one by one."""
for name in range(10):
self.multi.lines |= self.Line.create({"name": str(name)})
self.operations()
def test_create_single(self):
"""Check lines created with ``create()`` and added in one step."""
self.multi.lines = self.Line.browse(
[self.Line.create({"name": str(name)}).id for name in range(10)]
)
self.operations()
def test_rpcstyle_one_by_one(self):
"""Check lines created with RPC style and appended one by one."""
for name in range(10):
self.multi.lines = [(0, 0, {"name": str(name)})]
self.operations()
def test_rpcstyle_single(self):
"""Check lines created with RPC style and added in one step"""
self.multi.lines = [(0, 0, {'name': str(name)}) for name in range(10)]
self.operations()