[MERGE] forward port branch saas-17 up to bf4ccb21f6

This commit is contained in:
Christophe Simonis
2017-09-21 18:14:55 +02:00
34 changed files with 202 additions and 36 deletions
+8
View File
@@ -987,6 +987,14 @@ class AccountTax(models.Model):
return incl_tax.compute_all(price)['total_excluded']
return price
@api.model
def _fix_tax_included_price_company(self, price, prod_taxes, line_taxes, company_id):
if company_id:
#To keep the same behavior as in _compute_tax_id
prod_taxes = prod_taxes.filtered(lambda tax: tax.company_id == company_id)
line_taxes = line_taxes.filtered(lambda tax: tax.company_id == company_id)
return self._fix_tax_included_price(price, prod_taxes, line_taxes)
class AccountReconcileModel(models.Model):
_name = "account.reconcile.model"
_description = "Preset to create journal entries during a invoices and payments matching"
+7 -2
View File
@@ -661,6 +661,7 @@ class AccountInvoice(models.Model):
self.account_id = account_id
self.payment_term_id = payment_term_id
self.date_due = False
self.fiscal_position_id = fiscal_position
if type in ('in_invoice', 'out_refund'):
@@ -1384,7 +1385,7 @@ class AccountInvoice(models.Model):
if self.origin:
communication = '%s (%s)' % (communication, self.origin)
payment = self.env['account.payment'].create({
payment_vals = {
'invoice_ids': [(6, 0, self.ids)],
'amount': pay_amount or self.residual,
'payment_date': date or fields.Date.context_today(self),
@@ -1396,7 +1397,11 @@ class AccountInvoice(models.Model):
'payment_method_id': payment_method.id,
'payment_difference_handling': writeoff_acc and 'reconcile' or 'open',
'writeoff_account_id': writeoff_acc and writeoff_acc.id or False,
})
}
if self.env.context.get('tx_currency_id'):
payment_vals['currency_id'] = self.env.context.get('tx_currency_id')
payment = self.env['account.payment'].create(payment_vals)
payment.post()
return True
+1 -1
View File
@@ -1679,7 +1679,7 @@ class AccountPartialReconcile(models.Model):
'partner_id': line.partner_id.id,
})
if newly_created_move:
if move_date > self.company_id.period_lock_date and newly_created_move.date != move_date:
if move_date > (self.company_id.period_lock_date or '0000-00-00') and newly_created_move.date != move_date:
# The move date should be the maximum date between payment and invoice (in case
# of payment in advance). However, we should make sure the move date is not
# recorded before the period lock date as the tax statement for this period is
@@ -237,6 +237,7 @@ var StatementModel = BasicModel.extend({
return $.when(partner && this._changePartner(handle, partner.id))
.then(function() {
line.reconciliation_proposition = [];
self._computeLine(line);
return self.changeMode(handle, 'match');
})
.then(function () {
@@ -607,6 +607,10 @@ var LineRenderer = Widget.extend(FieldManagerMixin, {
* @param {keyup event} event
*/
_onInputKeyup: function (event) {
var target_partner_id = $(event.target).parents('[name="partner_id"]');
if (target_partner_id.length === 1) {
return;
}
if(event.keyCode === 13) {
if (_.findWhere(this.model.lines, {mode: 'create'}).balance.amount) {
this._onCreateProposition();
@@ -741,7 +741,7 @@ QUnit.module('account', {
});
QUnit.test('Reconciliation change partner', function (assert) {
assert.expect(13);
assert.expect(17);
var clientAction = new ReconciliationClientAction.StatementAction(null, this.params.options);
@@ -759,6 +759,20 @@ QUnit.module('account', {
var widget = clientAction.widgets[0];
assert.strictEqual(widget.$('.o_input_dropdown input').val(), "Agrolait", "the partner many2one should display agrolait");
assert.strictEqual(widget.$('.match table tr').length, 2, "agrolait should have 2 propositions for reconciliation");
// Adding the two propositions
// This is in order to try that after changing partner the propositions are emptied
widget.$('.match .cell_account_code:first').trigger('click');
widget.$('.match .cell_account_code:first').trigger('click');
assert.strictEqual(widget.$('.accounting_view tbody tr').length, 2, "Both proposition should be selected");
// Similate changing partner to one that does not have propositions to see if create mode is open after
widget.$('.o_input_dropdown input').trigger('click');
$('.ui-autocomplete .ui-menu-item a:contains(partner 1)').trigger('mouseenter').trigger('click');
clientAction._onAction({target: widget, name: 'change_partner', data: {data: {display_name: 'partner 1', id: 1}}, stopped: false});
assert.strictEqual(widget.$('.o_input_dropdown input').val(), "partner 1", "the partner many2one should display partner 1");
assert.strictEqual(widget.$('.match table tr.mv_line').length, 0, "partner 1 should have 0 propositions for reconciliation");
assert.strictEqual(widget.$el.data('mode'), 'create', "widget should be in create mode");
// Simulate changing partner
widget.$('.o_input_dropdown input').trigger('click');
@@ -700,7 +700,7 @@
<field name="view_mode">tree,kanban,form,calendar,pivot,graph</field>
<field eval="False" name="view_id"/>
<field name="domain">[('type','=','out_refund')]</field>
<field name="context">{'default_type': 'out_refund', 'journal_type': 'sale'}</field>
<field name="context">{'default_type': 'out_refund', 'type': 'out_refund', 'journal_type': 'sale'}</field>
<field name="search_view_id" ref="view_account_invoice_filter_inherit_credit_notes"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
@@ -774,7 +774,7 @@
<field name="view_mode">tree,kanban,form,calendar,pivot,graph</field>
<field eval="False" name="view_id"/>
<field name="domain">[('type','=','in_refund')]</field>
<field name="context">{'default_type': 'in_refund', 'journal_type': 'purchase'}</field>
<field name="context">{'default_type': 'in_refund', 'type': 'in_refund', 'journal_type': 'purchase'}</field>
<field name="search_view_id" ref="view_account_invoice_filter_inherit_credit_notes"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
+1 -1
View File
@@ -49,7 +49,7 @@
<td><span t-esc="aml.move_id.name != '/' and aml.move_id.name or ('*'+str(aml.move_id.id))"/></td>
<td><span t-field="aml.date"/></td>
<td><span t-field="aml.account_id.code"/></td>
<td><span t-esc="aml.sudo().partner_id and aml.sudo().partner_id.name[:23] or ''"/></td>
<td><span t-esc="aml.sudo().partner_id and aml.sudo().partner_id.name and aml.sudo().partner_id.name[:23] or ''"/></td>
<td><span t-esc="aml.name[:35]"/></td>
<td><span t-esc="aml.debit" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></td>
<td><span t-esc="aml.credit" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></td>
+4 -3
View File
@@ -6,6 +6,7 @@ import logging
from ldap.filter import filter_format
from odoo import api, fields, models, tools
from odoo.tools.pycompat import to_native
_logger = logging.getLogger(__name__)
@@ -107,7 +108,7 @@ class CompanyLDAP(models.Model):
if len(results) == 1:
dn = results[0][0]
conn = self.connect(conf)
conn.simple_bind_s(dn, password.encode('utf-8'))
conn.simple_bind_s(dn, to_native(password))
conn.unbind()
entry = results[0]
except ldap.INVALID_CREDENTIALS:
@@ -144,8 +145,8 @@ class CompanyLDAP(models.Model):
conn = self.connect(conf)
ldap_password = conf['ldap_password'] or ''
ldap_binddn = conf['ldap_binddn'] or ''
conn.simple_bind_s(ldap_binddn.encode('utf-8'), ldap_password.encode('utf-8'))
results = conn.search_st(conf['ldap_base'].encode('utf-8'), ldap.SCOPE_SUBTREE, filter, retrieve_attributes, timeout=60)
conn.simple_bind_s(to_native(ldap_binddn), to_native(ldap_password))
results = conn.search_st(to_native(conf['ldap_base']), ldap.SCOPE_SUBTREE, filter, retrieve_attributes, timeout=60)
conn.unbind()
except ldap.INVALID_CREDENTIALS:
_logger.error('LDAP bind failed.')
+1 -1
View File
@@ -917,7 +917,7 @@ class PosOrderLine(models.Model):
self.tax_ids = self.product_id.taxes_id.filtered(lambda r: not self.company_id or r.company_id == self.company_id)
fpos = self.order_id.fiscal_position_id
tax_ids_after_fiscal_position = fpos.map_tax(self.tax_ids, self.product_id, self.order_id.partner_id) if fpos else self.tax_ids
self.price_unit = self.env['account.tax']._fix_tax_included_price(price, self.product_id.taxes_id, tax_ids_after_fiscal_position)
self.price_unit = self.env['account.tax']._fix_tax_included_price_company(price, self.product_id.taxes_id, tax_ids_after_fiscal_position, self.company_id)
@api.onchange('qty', 'discount', 'price_unit', 'tax_ids')
def _onchange_qty(self):
+3 -3
View File
@@ -825,7 +825,7 @@ class PurchaseOrderLine(models.Model):
if not seller:
return
price_unit = self.env['account.tax']._fix_tax_included_price(seller.price, self.product_id.supplier_taxes_id, self.taxes_id) if seller else 0.0
price_unit = self.env['account.tax']._fix_tax_included_price_company(seller.price, self.product_id.supplier_taxes_id, self.taxes_id, self.company_id) if seller else 0.0
if price_unit and seller and self.order_id.currency_id and seller.currency_id != self.order_id.currency_id:
price_unit = seller.currency_id.compute(price_unit, self.order_id.currency_id)
@@ -908,7 +908,7 @@ class ProcurementRule(models.Model):
date=po.date_order and po.date_order[:10],
uom_id=product_id.uom_po_id)
price_unit = self.env['account.tax']._fix_tax_included_price(seller.price, line.product_id.supplier_taxes_id, line.taxes_id) if seller else 0.0
price_unit = self.env['account.tax']._fix_tax_included_price_company(seller.price, line.product_id.supplier_taxes_id, line.taxes_id, values['company_id']) if seller else 0.0
if price_unit and seller and po.currency_id and seller.currency_id != po.currency_id:
price_unit = seller.currency_id.compute(price_unit, po.currency_id)
@@ -955,7 +955,7 @@ class ProcurementRule(models.Model):
if taxes_id:
taxes_id = taxes_id.filtered(lambda x: x.company_id.id == values['company_id'].id)
price_unit = self.env['account.tax']._fix_tax_included_price(seller.price, product_id.supplier_taxes_id, taxes_id) if seller else 0.0
price_unit = self.env['account.tax']._fix_tax_included_price_company(seller.price, product_id.supplier_taxes_id, taxes_id, values['company_id']) if seller else 0.0
if price_unit and seller and po.currency_id and seller.currency_id != po.currency_id:
price_unit = seller.currency_id.compute(price_unit, po.currency_id)
@@ -93,7 +93,7 @@
<field name="name">report.intrastat.kanban</field>
<field name="model">report.intrastat</field>
<field name="arch" type="xml">
<kanban class="o_kanban_mobile">
<kanban class="o_kanban_mobile" create="false">
<field name="name" />
<field name="month"/>
<field name="code"/>
+3 -3
View File
@@ -1021,7 +1021,7 @@ class SaleOrderLine(models.Model):
self._compute_tax_id()
if self.order_id.pricelist_id and self.order_id.partner_id:
vals['price_unit'] = self.env['account.tax']._fix_tax_included_price(self._get_display_price(product), product.taxes_id, self.tax_id)
vals['price_unit'] = self.env['account.tax']._fix_tax_included_price_company(self._get_display_price(product), product.taxes_id, self.tax_id, self.company_id)
self.update(vals)
return result
@@ -1041,7 +1041,7 @@ class SaleOrderLine(models.Model):
uom=self.product_uom.id,
fiscal_position=self.env.context.get('fiscal_position')
)
self.price_unit = self.env['account.tax']._fix_tax_included_price(self._get_display_price(product), product.taxes_id, self.tax_id)
self.price_unit = self.env['account.tax']._fix_tax_included_price_company(self._get_display_price(product), product.taxes_id, self.tax_id, self.company_id)
@api.multi
def unlink(self):
@@ -1117,7 +1117,7 @@ class SaleOrderLine(models.Model):
price, rule_id = self.order_id.pricelist_id.with_context(pricelist_context).get_product_price_rule(self.product_id, self.product_uom_qty or 1.0, self.order_id.partner_id)
new_list_price, currency_id = self.with_context(context_partner)._get_real_price_currency(self.product_id, rule_id, self.product_uom_qty, self.product_uom, self.order_id.pricelist_id.id)
new_list_price = self.env['account.tax']._fix_tax_included_price(new_list_price, self.product_id.taxes_id, self.tax_id)
new_list_price = self.env['account.tax']._fix_tax_included_price_company(new_list_price, self.product_id.taxes_id, self.tax_id, self.company_id)
if new_list_price != 0:
if self.product_id.company_id and self.order_id.pricelist_id.currency_id != self.product_id.company_id.currency_id:
+1
View File
@@ -248,6 +248,7 @@
<field name="product_id"
context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom, 'company_id': parent.company_id}"
attrs="{'readonly': [('qty_invoiced', '&gt;', 0)]}"
force_save="1"
/>
<field name="layout_category_id" groups="sale.group_sale_layout"/>
<field name="invoice_status" invisible="1"/>
+1 -1
View File
@@ -87,7 +87,7 @@ class PaymentTransaction(models.Model):
_logger.warning('<%s> transaction completed, could not auto-generate payment for %s (ID %s) (no journal set on acquirer)',
self.acquirer_id.provider, self.sale_order_id.name, self.sale_order_id.id)
self.acquirer_id.journal_id = default_journal
created_invoice.pay_and_reconcile(self.acquirer_id.journal_id, pay_amount=created_invoice.amount_total)
created_invoice.with_context(tx_currency_id=self.currency_id.id).pay_and_reconcile(self.acquirer_id.journal_id, pay_amount=created_invoice.amount_total)
if created_invoice.payment_ids:
created_invoice.payment_ids[0].payment_transaction_id = self
else:
+7
View File
@@ -302,6 +302,13 @@ class ProcurementGroup(models.Model):
1000 orderpoints.
This is appropriate for batch jobs only.
"""
if company_id and self.env.user.company_id.id != company_id:
# To ensure that the company_id is taken into account for
# all the processes triggered by this method
# i.e. If a PO is generated by the run of the procurements the
# sequence to use is the one for the specified company not the
# one of the user's company
self = self.with_context(company_id=company_id, force_company=company_id)
OrderPoint = self.env['stock.warehouse.orderpoint']
domain = self._get_orderpoint_domain(company_id=company_id)
orderpoints_noprefetch = OrderPoint.with_context(prefetch_fields=False).search(domain,
@@ -294,12 +294,7 @@ var ViewManager = Widget.extend(ControlPanelMixin, {
}).fail(view.loaded.reject.bind(view.loaded));
} else {
view.loaded = view.loaded.then(function() {
// By default, the view will be loaded in readonly mode
// Returns to this default mode if you load action from breadcrumb
view_options = _.extend({}, view_options, self.env);
if (view_type === 'form') {
view_options.mode = view_options.mode || 'readonly';
}
return view.controller.reload(view_options);
});
}
@@ -384,8 +379,14 @@ var ViewManager = Widget.extend(ControlPanelMixin, {
});
},
select_view: function (index) {
var view_type = this.view_stack[index].type;
return this.switch_mode(view_type);
var viewType = this.view_stack[index].type;
var viewOptions = {};
if (viewType === 'form') {
// reload form views in readonly, except for inline actions (i.e.
// settings views) that stay in edit
viewOptions.mode = this.action.target === 'inline' ? 'edit' : 'readonly';
}
return this.switch_mode(viewType, viewOptions);
},
/**
* Renders the switch buttons for multi- and mono-record views and adds
@@ -71,7 +71,7 @@ var BasicController = AbstractController.extend(FieldManagerMixin, {
return $.when(false);
}
var message = _t("The record has been modified, your changes will be discarded. Are you sure you want to ?");
var message = _t("The record has been modified, your changes will be discarded. Do you want to proceed?");
var def = $.Deferred();
var dialog = Dialog.confirm(this, message, {
title: _t("Warning"),
@@ -13,6 +13,7 @@ var FormRenderer = BasicRenderer.extend({
className: "o_form_view",
events: _.extend({}, BasicRenderer.prototype.events, {
'click .o_notification_box .oe_field_translate': '_onTranslate',
'click .oe_title, .o_group': '_onClick',
}),
/**
* @override
@@ -832,6 +833,16 @@ var FormRenderer = BasicRenderer.extend({
// Handlers
//--------------------------------------------------------------------------
/**
* Makes the Edit button bounce in readonly
*
* @private
*/
_onClick: function () {
if (this.mode === 'readonly') {
this.trigger_up('bounce_edit');
}
},
/**
* @override
* @private
@@ -192,6 +192,7 @@ ListRenderer.include({
* @param {string} recordID
*/
removeLine: function (state, recordID) {
var self = this;
var rowIndex = _.findIndex(this.state.data, {id: recordID});
this.state = state;
if (rowIndex === -1) {
@@ -746,6 +747,17 @@ ListRenderer.include({
this._super.apply(this, arguments);
}
},
/**
* Overrides to prevent from sorting if we are currently editing a record.
*
* @override
* @private
*/
_onSortColumn: function () {
if (this.currentRow === null) {
this._super.apply(this, arguments);
}
},
/**
* Triggers a delete event. I don't know why we stop the propagation of the
* event.
@@ -75,9 +75,16 @@ var DateWidget = Widget.extend({
* set datetime value
*/
changeDatetime: function () {
if(this.isValid()) {
if (this.isValid()) {
var oldValue = this.getValue();
this._setValueFromUi();
this.trigger("datetime_changed");
var newValue = this.getValue();
if (!oldValue !== !newValue || oldValue && newValue && !oldValue.isSame(newValue)) {
// The condition is strangely written; this is because the
// values can be false/undefined
this.trigger("datetime_changed");
}
}
},
/**
+10
View File
@@ -2,6 +2,7 @@
// Variables
@reward-size: 400px;
@reward-size-mobile: 300px;
@reward-text-color: #727880;
@reward-base-time: 1.4s;
@@ -11,6 +12,9 @@
z-index: @zindex-modal + 1;
padding: 50px;
margin: -5% auto 0 -(@reward-size / 2);
@media (max-width: @screen-xs-max) {
margin: -5% auto 0 -(@reward-size-mobile / 2);
}
background-image: -webkit-radial-gradient(#EDEFF4 30%, transparent 70%, transparent);
background-image: -o-radial-gradient(#EDEFF4 30%, transparent 70%, transparent);
background-image: radial-gradient(#EDEFF4 30%, transparent 70%, transparent);
@@ -18,6 +22,9 @@
.o-animation(reward-fading, @reward-base-time * 0.5, ease-in-out, 0s, 1, normal, forwards);
.o-position-absolute(20%, auto, auto, 50%);
.size(@reward-size, @reward-size);
@media (max-width: @screen-xs-max) {
.size(@reward-size-mobile, @reward-size-mobile);
}
&.o_reward_fading {
display: block;
@@ -70,6 +77,9 @@
.o_reward_stars {
display: block;
.size(@reward-size * 0.75, @reward-size / 2);
@media (max-width: @screen-xs-max) {
.size(@reward-size-mobile * 0.75, @reward-size-mobile / 2);
}
.o-position-absolute(18%, 7%);
svg {
@@ -5946,5 +5946,36 @@ QUnit.module('Views', {
delete widgetRegistry.map.test;
});
QUnit.test('bounce edit button in readonly mode', function (assert) {
assert.expect(3);
var form = createView({
View: FormView,
model: 'partner',
data: this.data,
arch: '<form>' +
'<div class="oe_title">' +
'<field name="display_name"/>' +
'</div>' +
'</form>',
res_id: 1,
intercepts: {
bounce_edit: function() {
assert.step('bounce');
},
},
});
// in readonly
form.$('[name="display_name"]').click();
assert.verifySteps(['bounce']);
// in edit
form.$buttons.find('.o_form_button_edit').click();
form.$('[name="display_name"]').click();
assert.verifySteps(['bounce']);
form.destroy();
});
});
});
@@ -487,6 +487,39 @@ QUnit.module('Views', {
list.destroy();
});
QUnit.test('editable list view: save data when list sorting in edit mode', function (assert) {
assert.expect(3);
this.data.foo.fields.foo.sortable = true;
var list = createView({
View: ListView,
model: 'foo',
data: this.data,
arch: '<tree editable="bottom"><field name="foo"/></tree>',
mockRPC: function (route, args) {
if (args.method === 'write') {
assert.deepEqual(args.args, [[1], {foo: 'xyz'}],
"should correctly save the edited record");
}
return this._super.apply(this, arguments);
}
});
list.$('.o_data_cell:first').click();
list.$('input[name="foo"]').val('xyz').trigger('input');
list.$('.o_column_sortable').click();
assert.ok(list.$('.o_data_row:first').hasClass('o_selected_row'),
"first row should still be in edition");
list.$buttons.find('.o_list_button_save').click();
assert.ok(!list.$buttons.hasClass('o-editing'),
"list buttons should be back to their readonly mode");
list.destroy();
});
QUnit.test('selection changes are triggered correctly', function (assert) {
assert.expect(8);
@@ -912,6 +945,7 @@ QUnit.module('Views', {
assert.ok(form.$('tbody tr:eq(2) td input').val(),
"Value 2 should be third (shouldn't be sorted)");
form.$('.o_form_sheet_bg').click(); // validate the row before sorting
$o2m.find('.o_column_sortable').click();
assert.ok(form.$('tbody tr:first td:contains(Value 3)').length,
"Value 3 should be first");
@@ -151,7 +151,7 @@ QUnit.module('DomainSelector', {
});
QUnit.test("building a domain with a datetime", function (assert) {
assert.expect(1);
assert.expect(2);
var $target = $("#qunit-fixture");
@@ -163,8 +163,16 @@ QUnit.module('DomainSelector', {
domainSelector.appendTo($target);
// Check that there is a datepicker to choose the date
assert.strictEqual(domainSelector.$(".o_datepicker:visible").length, 1,
var $datepicker = domainSelector.$(".o_datepicker:visible");
assert.strictEqual($datepicker.length, 1,
"there should be a datepicker");
var val = $datepicker.find('input').focus().click().val();
$('.bootstrap-datetimepicker-widget :not(.today)[data-action="selectDay"]').click();
assert.notEqual(domainSelector.$(".o_datepicker:visible input").val(), val,
"datepicker value should have changed");
domainSelector.destroy();
});
});
});
+4 -3
View File
@@ -97,7 +97,7 @@ class SaleOrder(models.Model):
if order.pricelist_id and order.partner_id:
order_line = order._cart_find_product_line(product.id)
if order_line:
pu = self.env['account.tax']._fix_tax_included_price(pu, product.taxes_id, order_line[0].tax_id)
pu = self.env['account.tax']._fix_tax_included_price_company(pu, product.taxes_id, order_line[0].tax_id, self.company_id)
return {
'product_id': product_id,
@@ -185,10 +185,11 @@ class SaleOrder(models.Model):
'pricelist': order.pricelist_id.id,
})
product = self.env['product.product'].with_context(product_context).browse(product_id)
values['price_unit'] = self.env['account.tax']._fix_tax_included_price(
values['price_unit'] = self.env['account.tax']._fix_tax_included_price_company(
order_line._get_display_price(product),
order_line.product_id.taxes_id,
order_line.tax_id
order_line.tax_id,
self.company_id
)
order_line.write(values)
+5
View File
@@ -48,6 +48,11 @@ related to testing Odoo content (modules, mainly):
.. autoclass:: odoo.tests.common.SingleTransactionCase
:members: browse_ref, ref
.. autoclass:: odoo.tests.common.SavepointCase
.. autoclass:: odoo.tests.common.HttpCase
:members: browse_ref, ref, url_open, phantom_js
By default, tests are run once right after the corresponding module has been
installed. Test cases can also be configured to run after all modules have
been installed, and not run right after the module installation:
+1 -1
View File
@@ -228,7 +228,7 @@ class IrHttp(models.AbstractModel):
if not hasattr(cls, '_routing_map'):
_logger.info("Generating routing map")
installed = request.registry._init_modules - {'web'}
if tools.config['test_enable']:
if tools.config['test_enable'] and odoo.modules.module.current_test:
installed.add(odoo.modules.module.current_test)
mods = [''] + odoo.conf.server_wide_modules + sorted(installed)
# Note : when routing map is generated, we put it on the class `cls`
@@ -283,6 +283,11 @@
<field name="state_id"/>
<field name="image_small"/>
<field name="lang"/>
<!-- fields in form x2many view to diminish requests -->
<field name="comment"/>
<field name="customer"/>
<field name="display_name"/>
<field name="supplier"/>
<templates>
<t t-name="kanban-box">
<t t-set="color" t-value="kanban_color(record.color.raw_value)"/>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -63,7 +63,7 @@ class Shell(Command):
def console(self, local_vars):
if not os.isatty(sys.stdin.fileno()):
exec(sys.stdin, local_vars)
exec(sys.stdin.read(), local_vars)
else:
if 'env' not in local_vars:
print('No environment set, use `%s shell -d dbname` to get one.' % sys.argv[0])