[MERGE] forward port branch saas-17 up to bf4ccb21f6
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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.')
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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', '>', 0)]}"
|
||||
force_save="1"
|
||||
/>
|
||||
<field name="layout_category_id" groups="sale.group_sale_layout"/>
|
||||
<field name="invoice_status" invisible="1"/>
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
@@ -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])
|
||||
|
||||
Reference in New Issue
Block a user