[MERGE] forward port branch saas-15 up to 2629029d03

This commit is contained in:
Christophe Simonis
2018-01-29 13:29:14 +01:00
14 changed files with 62 additions and 60 deletions
+3 -1
View File
@@ -291,11 +291,13 @@ class account_payment(models.Model):
self.partner_type = 'customer'
elif self.payment_type == 'outbound':
self.partner_type = 'supplier'
else:
self.partner_type = False
# Set payment method domain
res = self._onchange_journal()
if not res.get('domain', {}):
res['domain'] = {}
res['domain']['journal_id'] = self.payment_type == 'inbound' and [('at_least_one_inbound', '=', True)] or [('at_least_one_outbound', '=', True)]
res['domain']['journal_id'] = self.payment_type == 'inbound' and [('at_least_one_inbound', '=', True)] or self.payment_type == 'outbound' and [('at_least_one_outbound', '=', True)] or []
res['domain']['journal_id'].append(('type', 'in', ('bank', 'cash')))
return res
@@ -3,7 +3,8 @@
from datetime import datetime
from dateutil.relativedelta import relativedelta
from odoo import api, fields, models
from odoo import api, fields, models, _
from odoo.exceptions import UserError
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT as DF
import odoo.addons.decimal_precision as dp
+1 -1
View File
@@ -124,7 +124,7 @@ class PadCommon(models.AbstractModel):
myPad.setText(path, (html2plaintext(vals[field.pad_content_field]).encode('utf-8')))
# Update the `pad_content_field` if the pad is modified
for k, v in vals.items():
field = self._fields[k]
field = self._fields.get(k)
if hasattr(field, 'pad_content_field'):
vals[field.pad_content_field] = self.pad_get_content(v)
@@ -1812,6 +1812,12 @@ msgstr ""
msgid "No sequence defined on the journal"
msgstr ""
#. module: point_of_sale
#: code:addons/point_of_sale/models/pos_order.py:986
#, python-format
msgid "No Taxes"
msgstr ""
#. module: point_of_sale
#. openerp-web
#: code:addons/point_of_sale/static/src/js/screens.js:2023
+4 -1
View File
@@ -983,7 +983,10 @@ class ReportSaleDetails(models.AbstractModel):
for tax in line_taxes['taxes']:
taxes.setdefault(tax['id'], {'name': tax['name'], 'tax_amount':0.0, 'base_amount':0.0})
taxes[tax['id']]['tax_amount'] += tax['amount']
taxes[tax['id']]['base_amount'] += line.price_subtotal
taxes[tax['id']]['base_amount'] += tax['base']
else:
taxes.setdefault(0, {'name': _('No Taxes'), 'tax_amount':0.0, 'base_amount':0.0})
taxes[0]['base_amount'] += line.price_subtotal_incl
st_line_ids = self.env["account.bank.statement.line"].search([('pos_statement_id', 'in', orders.ids)]).ids
if st_line_ids:
+2 -4
View File
@@ -87,13 +87,11 @@ class AccountInvoice(models.Model):
self.purchase_id = False
return {}
@api.onchange('currency_id', 'date_invoice')
@api.onchange('currency_id')
def _onchange_currency_id(self):
if self.currency_id:
for line in self.invoice_line_ids.filtered(lambda r: r.purchase_line_id):
if line.purchase_id.currency_id != self.currency_id:
line.price_unit = line.purchase_id.currency_id.with_context(date=self.date_invoice)\
.compute(line.purchase_line_id.price_unit, self.currency_id, round=False)
line.price_unit = line.purchase_id.currency_id.with_context(date=self.date_invoice).compute(line.purchase_line_id.price_unit, self.currency_id, round=False)
@api.onchange('invoice_line_ids')
def _onchange_origin(self):
+4 -5
View File
@@ -32,14 +32,13 @@ data.dom_ready = dom_ready;
var all_ready;
data.ready = function () {
if (!all_ready) {
all_ready = $.when(dom_ready, ajax.loadXML());
all_ready = dom_ready;
if (!odoo._modules) {
all_ready.then(load_translations);
all_ready = all_ready.then(load_translations);
}
} else { // can add async template
all_ready = $.when(dom_ready, ajax.loadXML());
}
return all_ready;
// also load new templates since previous ready call
return $.when(all_ready, ajax.loadXML());
};
function load_translations() {
+21 -23
View File
@@ -280,7 +280,15 @@ var RTE = Widget.extend({
} else {
rng = $editable.data('range') || rng;
}
rng.select();
try {
// TODO this line might break for unknown reasons. I suppose that
// the created range is an invalid one. As it might be tricky to
// adapt that line and that it is not a critical one, temporary fix
// is to ignore the errors that this generates.
rng.select();
} catch (e) {
console.log('error', e);
}
history.recordUndo($editable, event, internal_history);
},
/**
@@ -567,8 +575,8 @@ var RTE = Widget.extend({
onEnableEditableArea: function ($editable) {
},
onMouseup: function (event) {
var $target = $(event.target);
onMouseup: function (ev) {
var $target = $(ev.target);
var $editable = $target.closest('.o_editable');
if (!$editable.length) {
@@ -580,26 +588,16 @@ var RTE = Widget.extend({
self.historyRecordUndo($target, 'activate', true);
});
// To Fix Google Chrome Tripleclick Issue, which selects the ending
// whitespace characters (so Tripleclicking then typing text will remove
// the whole paragraph instead of its content).
// http://stackoverflow.com/questions/38467334/why-does-google-chrome-always-add-space-after-selected-text
if ($.browser.chrome === true && event.originalEvent.detail === 3) {
var currentSelection = range.create();
if (currentSelection.sc.parentNode === currentSelection.ec) {
_selectSC(currentSelection);
} else if (currentSelection.eo === 0) {
var $hasNext = $(currentSelection.sc).parent();
while (!$hasNext.next().length && !$hasNext.is('body')) {
$hasNext = $hasNext.parent();
}
if ($hasNext.next()[0] === currentSelection.ec) {
_selectSC(currentSelection);
}
}
}
function _selectSC(selection) {
range.create(selection.sc, selection.so, selection.sc, selection.sc.length).select();
// Browsers select different content from one to another after a
// triple click (especially: if triple-clicking on a paragraph on
// Chrome, blank characters of the element following the paragraph are
// selected too)
//
// The triple click behavior is reimplemented for all browsers here
if (ev.originalEvent.detail === 3) {
// Select the whole content inside the deepest DOM element that was
// triple-clicked
range.create(ev.target, 0, ev.target, ev.target.childNodes.length).select();
}
},
@@ -422,6 +422,9 @@ dom.isImg = function (node) {
};
var fn_is_forbidden_node = dom.isForbiddenNode || function () {};
dom.isForbiddenNode = function (node) {
if (node.tagName === "BR") {
return false;
}
return fn_is_forbidden_node(node) || $(node).is(".media_iframe_video");
};
var fn_is_img_font = dom.isImgFont || function () {};
@@ -703,10 +703,16 @@ dom.isRemovableEmptyNode = function (node) {
dom.isForbiddenNode = function (node) {
return node.tagName === "BR" || $(node).is(".fa, img");
};
dom.listBetween = function (sc, ec) {
/**
* @todo 'so' and 'eo' were added as a bugfix and are not given everytime. They
* however should be as the function may be wrong without them (for example,
* when asking the list between an element and its parent, as there is no path
* from the beginning of the former to the beginning of the later).
*/
dom.listBetween = function (sc, ec, so, eo) {
var nodes = [];
var ancestor = dom.commonAncestor(sc, ec);
dom.walkPoint({'node': sc, 'offset': 0}, {'node': ec, 'offset': 0}, function (point) {
dom.walkPoint({'node': sc, 'offset': so || 0}, {'node': ec, 'offset': eo || 0}, function (point) {
if (ancestor !== point.node || ancestor === sc || ancestor === ec) {
nodes.push(point.node);
}
@@ -1926,7 +1932,7 @@ $.summernote.pluginEvents.formatBlock = function (event, editor, layoutInfo, sTa
}
// fix by odoo because if you select a style in a li with no p tag all the ul is wrapped by the style tag
var nodes = dom.listBetween(r.sc, r.ec);
var nodes = dom.listBetween(r.sc, r.ec, r.so, r.eo);
for (var i=0; i<nodes.length; i++) {
if (dom.isBR(nodes[i]) || (dom.isText(nodes[i]) && dom.isVisibleText(nodes[i])) || dom.isB(nodes[i]) || dom.isU(nodes[i]) || dom.isS(nodes[i]) || dom.isI(nodes[i]) || dom.isFont(nodes[i])) {
var ancestor = dom.ancestor(nodes[i], isFormatNode);
+1 -1
View File
@@ -209,7 +209,7 @@ class BlogPost(models.Model):
def write(self, vals):
result = True
for post in self:
copy_vals = vals
copy_vals = dict(vals)
if 'website_published' in vals and 'published_date' not in vals and post.published_date <= fields.Datetime.now():
copy_vals['published_date'] = vals['website_published'] and fields.Datetime.now() or False
result &= super(BlogPost, self).write(copy_vals)
+1 -1
View File
@@ -374,7 +374,7 @@ class IrActionsActWindowView(models.Model):
_name = 'ir.actions.act_window.view'
_table = 'ir_act_window_view'
_rec_name = 'view_id'
_order = 'sequence'
_order = 'sequence,id'
sequence = fields.Integer()
view_id = fields.Many2one('ir.ui.view', string='View')
+1 -7
View File
@@ -14,7 +14,6 @@ from odoo.exceptions import AccessDenied, AccessError, UserError, ValidationErro
from odoo.osv import expression
from odoo.service.db import check_super
from odoo.tools import partition
from odoo.http import root
_logger = logging.getLogger(__name__)
@@ -374,8 +373,6 @@ class Users(models.Model):
if any(key.startswith('context_') or key in ('lang', 'tz') for key in values):
self.context_get.clear_cache(self)
if any(key in values for key in ['active'] + USER_PRIVATE_FIELDS):
# force deletion of all sessions for these users
root.session_store.delete_sessions_for_uids(self.ids)
db = self._cr.dbname
for id in self.ids:
self.__uid_cache[db].pop(id, None)
@@ -389,10 +386,7 @@ class Users(models.Model):
db = self._cr.dbname
for id in self.ids:
self.__uid_cache[db].pop(id, None)
res = super(Users, self).unlink()
# force deletion of all sessions for these users
root.session_store.delete_sessions_for_uids(self.ids)
return res
return super(Users, self).unlink()
@api.model
def name_search(self, name='', args=None, operator='ilike', limit=100):
+4 -12
View File
@@ -1035,6 +1035,7 @@ class OpenERPSession(werkzeug.contrib.sessions.Session):
self.db = db
self.uid = uid
self.login = login
self.password = password
request.uid = uid
request.disable_db = False
@@ -1049,6 +1050,7 @@ class OpenERPSession(werkzeug.contrib.sessions.Session):
"""
if not self.db or not self.uid:
raise SessionExpiredException("Session expired")
security.check(self.db, self.uid, self.password)
def logout(self, keep_db=False):
for k in self.keys():
@@ -1061,6 +1063,7 @@ class OpenERPSession(werkzeug.contrib.sessions.Session):
self.setdefault("db", None)
self.setdefault("uid", None)
self.setdefault("login", None)
self.setdefault("password", None)
self.setdefault("context", {})
def get_context(self):
@@ -1273,17 +1276,6 @@ class DisableCacheMiddleware(object):
start_response(status, new_headers)
return self.app(environ, start_wrapped)
class OdooSessionStore(werkzeug.contrib.sessions.FilesystemSessionStore):
def delete_sessions_for_uids(self, uids):
# pretty expensive on large session stores, especially non-local!
uids = set(uids)
_logger.info('Deleting all HTTP sessions for UIDs %s', uids)
for sid in self.list():
s = self.get(sid)
if s.uid and s.uid in uids:
_logger.debug('Deleting session %s', sid)
self.delete(s)
class Root(object):
"""Root WSGI application for the OpenERP Web Client.
"""
@@ -1295,7 +1287,7 @@ class Root(object):
# Setup http sessions
path = odoo.tools.config.session_dir
_logger.debug('HTTP sessions stored in: %s', path)
return OdooSessionStore(path, session_class=OpenERPSession)
return werkzeug.contrib.sessions.FilesystemSessionStore(path, session_class=OpenERPSession)
@lazy_property
def nodb_routing_map(self):