[MERGE] forward port branch 11.0 up to c3ea0a7811
This commit is contained in:
@@ -1292,7 +1292,8 @@ var ManualModel = StatementModel.extend({
|
||||
});
|
||||
} else {
|
||||
var mv_line_ids = _.pluck(_.filter(props, function (prop) {return !isNaN(prop.id);}), 'id');
|
||||
var new_mv_line_dicts = _.map(_.filter(props, function (prop) {return isNaN(prop.id) && prop.display;}), self._formatToProcessReconciliation.bind(self, line));
|
||||
// Dear KangOl, please FORWARD-PORT UP TO SAAS-11.3. Thank you for your hard work.
|
||||
var new_mv_line_dicts = _.map(_.filter(props, function (prop) {return isNaN(prop.id) && prop.display && !prop.is_tax;}), self._formatToProcessReconciliation.bind(self, line));
|
||||
process_reconciliations.push({
|
||||
id: null,
|
||||
type: null,
|
||||
|
||||
@@ -187,6 +187,28 @@ var Activity = AbstractActivityField.extend({
|
||||
this.trigger_up('reload_mail_fields', fieldsToReload);
|
||||
},
|
||||
|
||||
/** Binds a focusout handler on a bootstrap popover
|
||||
* Useful to do some operations on the popover's HTML,
|
||||
* like keeping the user's input for the feedback
|
||||
* @param {JQuery} $popover_el: the element on which
|
||||
* the popover() method has been called
|
||||
*/
|
||||
_bindPopoverFocusout: function ($popover_el) {
|
||||
var self = this;
|
||||
// Retrieve the actual popover's HTML
|
||||
var $popover = $popover_el.data("bs.popover").tip();
|
||||
var activity_id = $popover_el.data('activity-id');
|
||||
$popover.off('focusout');
|
||||
$popover.focusout(function (e) {
|
||||
// outside click of popover hides the popover
|
||||
// e.relatedTarget is the element receiving the focus
|
||||
self.feedbackValue[activity_id] = $popover.find('#activity_feedback').val().trim();
|
||||
if(!$popover.is(e.relatedTarget) && !$popover.find(e.relatedTarget).length) {
|
||||
$popover_el.popover('hide');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// handlers
|
||||
_onClickRedirect: function (ev) {
|
||||
var id = $(ev.target).data('oe-id');
|
||||
@@ -236,19 +258,23 @@ var Activity = AbstractActivityField.extend({
|
||||
})
|
||||
.then(this._reload.bind(this, {activity: true}));
|
||||
},
|
||||
|
||||
_onMarkActivityDone: function (event) {
|
||||
event.preventDefault();
|
||||
var self = this;
|
||||
this.feedbackValue = this.feedbackValue || {};
|
||||
var $popover_el = $(event.currentTarget);
|
||||
var activity_id = $popover_el.data('activity-id');
|
||||
var previous_activity_type_id = $popover_el.data('previous-activity-type-id');
|
||||
if (!$popover_el.data('bs.popover')) {
|
||||
this.feedbackValue[activity_id] = "";
|
||||
$popover_el.popover({
|
||||
title : _t('Feedback'),
|
||||
html: 'true',
|
||||
trigger:'click',
|
||||
content : function() {
|
||||
var $popover = $(QWeb.render("mail.activity_feedback_form", {'previous_activity_type_id': previous_activity_type_id}));
|
||||
$popover.find('#activity_feedback').val(self.feedbackValue[activity_id]);
|
||||
$popover.on('click', '.o_activity_popover_done_next', function () {
|
||||
var feedback = _.escape($popover.find('#activity_feedback').val());
|
||||
var previous_activity_type_id = $popover_el.data('previous-activity-type-id');
|
||||
@@ -272,14 +298,7 @@ var Activity = AbstractActivityField.extend({
|
||||
}).on("shown.bs.popover", function () {
|
||||
var $popover = $(this).data("bs.popover").tip();
|
||||
$popover.find('#activity_feedback').focus();
|
||||
$popover.off('focusout');
|
||||
$popover.focusout(function (e) {
|
||||
// outside click of popover hide the popover
|
||||
// e.relatedTarget is the element receiving the focus
|
||||
if(!$popover.is(e.relatedTarget) && !$popover.find(e.relatedTarget).length) {
|
||||
$popover.popover('hide');
|
||||
}
|
||||
});
|
||||
self._bindPopoverFocusout($(this));
|
||||
}).popover('show');
|
||||
}
|
||||
},
|
||||
|
||||
@@ -17,6 +17,8 @@ var createBusService = mailTestUtils.createBusService;
|
||||
var createAsyncView = testUtils.createAsyncView;
|
||||
var createView = testUtils.createView;
|
||||
|
||||
var Activity = require('mail.Activity');
|
||||
|
||||
QUnit.module('mail', {}, function () {
|
||||
|
||||
QUnit.module('Chatter', {
|
||||
@@ -72,6 +74,7 @@ QUnit.module('Chatter', {
|
||||
type: 'selection',
|
||||
selection: [['overdue', 'Overdue'], ['today', 'Today'], ['planned', 'Planned']],
|
||||
},
|
||||
note : { string: "Note", type: "char" },
|
||||
},
|
||||
},
|
||||
'mail.activity.type': {
|
||||
@@ -143,6 +146,73 @@ QUnit.test('basic rendering', function (assert) {
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('Activity Done keep feedback on blur', function (assert) {
|
||||
assert.expect(3);
|
||||
var done = assert.async();
|
||||
|
||||
this.data['mail.activity'].records = [
|
||||
{activity_type_id: 1, id: 1, user_id: 2, state: 'today', note: 'But I\'m talkin\' about Shaft'},
|
||||
];
|
||||
this.data.partner.records[0].activity_ids = [1];
|
||||
|
||||
var shownDef = $.Deferred();
|
||||
var hiddenDef = $.Deferred();
|
||||
testUtils.patch(Activity, {
|
||||
_bindPopoverFocusout: function () {
|
||||
this._super.apply(this, arguments);
|
||||
shownDef.resolve();
|
||||
},
|
||||
});
|
||||
|
||||
var form = createView({
|
||||
View: FormView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
res_id: 2,
|
||||
arch:'<form string="Partners">' +
|
||||
'<div class="oe_chatter">' +
|
||||
'<field name="activity_ids" widget="mail_activity"/>' +
|
||||
'</div>' +
|
||||
'</form>',
|
||||
});
|
||||
|
||||
// sanity checks
|
||||
var $activityEl = form.$('.o_mail_activity[name=activity_ids]');
|
||||
assert.strictEqual($activityEl.find('.o_thread_message').length, 1,
|
||||
'There should be one activity');
|
||||
assert.strictEqual($activityEl.find('.o_thread_message .o_thread_message_note').text().trim(),
|
||||
'But I\'m talkin\' about Shaft', 'The activity should have the right note');
|
||||
|
||||
var $popoverEl = $activityEl.find('.o_thread_message_tools .o_activity_done');
|
||||
$popoverEl.on('hidden.bs.popover', hiddenDef.resolve.bind(hiddenDef));
|
||||
|
||||
// open popover
|
||||
$popoverEl.click();
|
||||
|
||||
shownDef.then(function () {
|
||||
// write a feedback and focusout
|
||||
var $feedbackPopover = $popoverEl.data('bs.popover').tip();
|
||||
$feedbackPopover.find('#activity_feedback').val('John Shaft').focusout();
|
||||
|
||||
hiddenDef.then(function () {
|
||||
shownDef = $.Deferred();
|
||||
|
||||
// re-open popover
|
||||
$popoverEl.click();
|
||||
|
||||
shownDef.then(function () {
|
||||
var $feedbackPopover = $popoverEl.data('bs.popover').tip();
|
||||
assert.strictEqual($feedbackPopover.find('#activity_feedback').val(), 'John Shaft',
|
||||
"feedback should have been kept");
|
||||
|
||||
form.destroy();
|
||||
testUtils.unpatch(Activity);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test('chatter in create mode', function (assert) {
|
||||
assert.expect(9);
|
||||
|
||||
|
||||
@@ -164,8 +164,10 @@ class Partner(models.Model):
|
||||
|
||||
@api.model
|
||||
def _cron_update_membership(self):
|
||||
# used to recompute 'membership_state'; should no longer be necessary
|
||||
pass
|
||||
partners = self.search([('membership_state', 'in', ['invoiced', 'paid'])])
|
||||
# mark the field to be recomputed, and recompute it
|
||||
partners._recompute_todo(self._fields['membership_state'])
|
||||
self.recompute()
|
||||
|
||||
@api.multi
|
||||
def create_membership_invoice(self, product_id=None, datas=None):
|
||||
|
||||
@@ -185,9 +185,13 @@ class PaymentAcquirer(models.Model):
|
||||
def _check_required_if_provider(self):
|
||||
""" If the field has 'required_if_provider="<provider>"' attribute, then it
|
||||
required if record.provider is <provider>. """
|
||||
empty_field = []
|
||||
for acquirer in self:
|
||||
if any(getattr(f, 'required_if_provider', None) == acquirer.provider and not acquirer[k] for k, f in self._fields.items()):
|
||||
return False
|
||||
for k, f in acquirer._fields.items():
|
||||
if getattr(f, 'required_if_provider', None) == acquirer.provider and not acquirer[k]:
|
||||
empty_field.append(self.env['ir.model.fields'].search([('name', '=', k), ('model', '=', acquirer._name)]).field_description)
|
||||
if empty_field:
|
||||
raise ValidationError((', ').join(empty_field))
|
||||
return True
|
||||
|
||||
_constraints = [
|
||||
|
||||
@@ -451,7 +451,7 @@
|
||||
Operation type used to record product pickings
|
||||
</div>
|
||||
<div class="content-group mt16">
|
||||
<field name="picking_type_id"/>
|
||||
<field name="picking_type_id" required="1"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -384,7 +384,7 @@
|
||||
<field name="team_id" options="{'no_create': True}"/>
|
||||
<field name="client_order_ref"/>
|
||||
<field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/>
|
||||
<field name="analytic_account_id" context="{'default_partner_id':partner_invoice_id, 'default_name':name}" attrs="{'readonly': [('invoice_count','!=',0),('state','=','sale')]}" groups="analytic.group_analytic_accounting"/>
|
||||
<field name="analytic_account_id" context="{'default_partner_id':partner_invoice_id, 'default_name':name}" attrs="{'readonly': [('invoice_count','!=',0),('state','=','sale')]}" groups="analytic.group_analytic_accounting" force_save="1"/>
|
||||
</group>
|
||||
<group name="sale_pay" string="Invoicing">
|
||||
<field name="date_order" attrs="{'invisible': [('state', 'in', ['sale', 'done', 'cancel'])]}"/>
|
||||
|
||||
@@ -190,7 +190,9 @@ var AbstractWebClient = Widget.extend(ServiceProviderMixin, KeyboardNavigationMi
|
||||
// If it is not handled, we should display something clearer than the common crash_manager error dialog
|
||||
// since it won't show anything except "Script error."
|
||||
// This link will probably explain it better: https://blog.sentry.io/2016/05/17/what-is-script-error.html
|
||||
if (message === "Script error." && !file && !line && !col && !error) {
|
||||
if (!file && !line && !col) {
|
||||
// Chrome and Opera set "Script error." on the `message` and hide the `error`
|
||||
// Firefox handles the "Script error." directly. It sets the error thrown by the CORS file into `error`
|
||||
if (window.onOriginError) {
|
||||
window.onOriginError();
|
||||
delete window.onOriginError;
|
||||
@@ -198,7 +200,7 @@ var AbstractWebClient = Widget.extend(ServiceProviderMixin, KeyboardNavigationMi
|
||||
crash_manager.show_error({
|
||||
type: _t("Odoo Client Error"),
|
||||
message: _t("Unknown CORS error"),
|
||||
data: {debug: _t("An unknown CORS error occured. The error probably originates from a JavaScript file served from a different origin.")},
|
||||
data: {debug: _t("An unknown CORS error occured. The error probably originates from a JavaScript file served from a different origin. (Opening your browser console might give you a hint on the error.)")},
|
||||
});
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -4,6 +4,7 @@ odoo.define('web_settings_dashboard', function (require) {
|
||||
var AbstractAction = require('web.AbstractAction');
|
||||
var core = require('web.core');
|
||||
var framework = require('web.framework');
|
||||
var session = require('web.session');
|
||||
var Widget = require('web.Widget');
|
||||
|
||||
var QWeb = core.qweb;
|
||||
|
||||
@@ -11,12 +11,12 @@ var Dashboard = webSettingsDashboard.Dashboard;
|
||||
function createDashboard(params) {
|
||||
var widget = new Widget();
|
||||
var dashboard = new Dashboard(widget);
|
||||
dashboard.all_dashboards = ['invitations']; // test only user invitations
|
||||
dashboard.all_dashboards = params.dashboards || ['invitations']; // test only user invitations
|
||||
|
||||
testUtils.addMockEnvironment(widget, params);
|
||||
|
||||
var originalDestroy = Dashboard.prototype.destroy;
|
||||
Dashboard.destroy = function () {
|
||||
dashboard.destroy = function () {
|
||||
dashboard.destroy = originalDestroy;
|
||||
widget.destroy();
|
||||
};
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
<template id="report_saleorder_validity_date" inherit_id="sale.report_saleorder_document">
|
||||
<xpath expr="//div[hasclass('page')]/p[@id='fiscal_position_remark']" position="after">
|
||||
<div t-if="doc.options and doc.state in ['draft', 'sent']" style="page-break-before:always;">
|
||||
<t t-set="has_option_discount" t-value="any(doc.options.filtered(lambda o: o.discount != 0.0))" />
|
||||
<h2>
|
||||
<span>Suggested Products</span>
|
||||
</h2>
|
||||
@@ -11,7 +12,7 @@
|
||||
<tr>
|
||||
<th>Product</th>
|
||||
<th>Description</th>
|
||||
<th groups="sale.group_discount_per_so_line"></th>
|
||||
<th t-if="has_option_discount" groups="sale.group_discount_per_so_line"></th>
|
||||
<th class="text-right">Unit Price</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -23,8 +24,8 @@
|
||||
<td>
|
||||
<span t-field="option.name"/>
|
||||
</td>
|
||||
<td groups="sale.group_discount_per_so_line">
|
||||
<strong class="text-info">
|
||||
<td t-if="has_option_discount" groups="sale.group_discount_per_so_line">
|
||||
<strong t-if="option.discount != 0.0" class="text-info">
|
||||
<t t-esc="((option.discount % 1) and '%s' or '%d') % option.discount"/>% discount
|
||||
</strong>
|
||||
</td>
|
||||
|
||||
@@ -105,7 +105,6 @@ class SaleOrder(models.Model):
|
||||
'order_id': order_id,
|
||||
'product_uom': product.uom_id.id,
|
||||
'price_unit': pu,
|
||||
'customer_lead': product.sale_delay,
|
||||
}
|
||||
|
||||
@api.multi
|
||||
|
||||
@@ -31,6 +31,13 @@ class SaleOrder(models.Model):
|
||||
values['warning'] = self.warning_stock
|
||||
return values
|
||||
|
||||
@api.multi
|
||||
def _website_product_id_change(self, order_id, product_id, qty=0):
|
||||
res = super(SaleOrder, self)._website_product_id_change(order_id, product_id, qty=qty)
|
||||
product = self.env['product.product'].browse(product_id)
|
||||
res['customer_lead'] = product.sale_delay
|
||||
return res
|
||||
|
||||
@api.multi
|
||||
def _get_stock_warning(self, clear=True):
|
||||
self.ensure_one()
|
||||
|
||||
@@ -33,3 +33,4 @@ Akim Juillerat akim.juillerat@camptocamp.com https://github.com/grindtildeath
|
||||
Damien Crier damien.crier@camptocamp.com https://github.com/damdam-s
|
||||
Simone Orsi simahawk@gmail.com https://github.com/simahawk
|
||||
Patrick Tombez patrick.tombez@camptocamp.com https://github.com/p-tombez
|
||||
Julien Coux julien.coux@camptocamp.com https://github.com/jcoux
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
Guatemala, 2018-09-04
|
||||
|
||||
I hereby agree to the terms of the Odoo Individual Contributor License
|
||||
Agreement v1.0.
|
||||
|
||||
I declare that I am authorized and able to make this agreement and sign this
|
||||
declaration.
|
||||
|
||||
Signed,
|
||||
|
||||
Rodrigo Fernandez rodrigo@solucionesprisma.com https://github.com/rocketgithub
|
||||
@@ -651,7 +651,7 @@
|
||||
<field name="name">Guatemala</field>
|
||||
<field name="code">gt</field>
|
||||
<field file="base/static/img/country_flags/gt.png" name="image" type="base64" />
|
||||
<field name="currency_id" ref="QTQ" />
|
||||
<field name="currency_id" ref="GTQ" />
|
||||
<field eval="502" name="phone_code" />
|
||||
</record>
|
||||
<record id="gu" model="res.country">
|
||||
|
||||
@@ -1,4 +1,17 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
#from . import models
|
||||
from odoo import api, SUPERUSER_ID
|
||||
|
||||
#
|
||||
# Conditional installation of enterprise modules.
|
||||
#
|
||||
# This module is defined in community but some steps (defined with 'edition: "enterprise"')
|
||||
# are only used to test enterprise. As it's not possible to direcly add enterprise
|
||||
# modules dependencies, this post install hook will install account_accountant if exists.
|
||||
#
|
||||
def _auto_install_enterprise_dependencies(cr, registry):
|
||||
env = api.Environment(cr, SUPERUSER_ID, {})
|
||||
module_list = ['account_accountant']
|
||||
module_ids = env['ir.module.module'].search([('name', 'in', module_list), ('state', '=', 'uninstalled')])
|
||||
module_ids.sudo().button_install()
|
||||
|
||||
@@ -13,4 +13,5 @@ It will install some main apps and will try to execute the most important action
|
||||
'views/templates.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'post_init_hook': '_auto_install_enterprise_dependencies',
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user