diff --git a/addons/account/account_invoice_view.xml b/addons/account/account_invoice_view.xml
index 310750a0b6c..5fd16afa4ee 100644
--- a/addons/account/account_invoice_view.xml
+++ b/addons/account/account_invoice_view.xml
@@ -145,6 +145,7 @@
+
@@ -504,6 +505,17 @@
+
+ Invoices
+ account.invoice
+ form
+ tree,form,calendar,graph
+
+ [('type','in', ['out_invoice', 'out_refund']), ('state', 'not in', ['draft', 'cancel'])]
+ {'type':False}
+
+
+
Pending Invoice
account.invoice
diff --git a/addons/account/account_move_line.py b/addons/account/account_move_line.py
index 348d0ced3bc..dcdbd9da785 100644
--- a/addons/account/account_move_line.py
+++ b/addons/account/account_move_line.py
@@ -306,7 +306,8 @@ class account_move_line(osv.osv):
if not id:
return []
ml = self.browse(cr, uid, id, context=context)
- return map(lambda x: x.id, ml.move_id.line_id)
+ domain = (context or {}).get('on_write_domain', [])
+ return self.pool.get('account.move.line').search(cr, uid, domain + [['id', 'in', [l.id for l in ml.move_id.line_id]]], context=context)
def _balance(self, cr, uid, ids, name, arg, context=None):
if context is None:
diff --git a/addons/account/partner.py b/addons/account/partner.py
index 2b9cb47bb63..4ca4abde46e 100644
--- a/addons/account/partner.py
+++ b/addons/account/partner.py
@@ -242,7 +242,7 @@ class res_partner(osv.osv):
result = {}
account_invoice_report = self.pool.get('account.invoice.report')
for partner in self.browse(cr, uid, ids, context=context):
- domain = [('partner_id', 'child_of', partner.id)]
+ domain = [('partner_id', 'child_of', partner.id), ('state', 'not in', ['draft', 'cancel'])]
invoice_ids = account_invoice_report.search(cr, uid, domain, context=context)
invoices = account_invoice_report.browse(cr, uid, invoice_ids, context=context)
result[partner.id] = sum(inv.user_currency_price_total for inv in invoices)
diff --git a/addons/account/partner_view.xml b/addons/account/partner_view.xml
index 9c85d091a71..dd99a854135 100644
--- a/addons/account/partner_view.xml
+++ b/addons/account/partner_view.xml
@@ -77,7 +77,7 @@
class="oe_stat_button"
id="invoice_button"
icon="fa-pencil-square-o"
- name="%(account.action_invoice_tree)d"
+ name="%(account.action_invoice_refund_out_tree)d"
attrs="{'invisible': [('customer', '=', False)]}"
context="{'search_default_partner_id': active_id,'default_partner_id': active_id}">
Invoiced
diff --git a/addons/account/static/src/xml/account_bank_statement_reconciliation.xml b/addons/account/static/src/xml/account_bank_statement_reconciliation.xml
index 6140b492699..dd1a5f8a0bf 100644
--- a/addons/account/static/src/xml/account_bank_statement_reconciliation.xml
+++ b/addons/account/static/src/xml/account_bank_statement_reconciliation.xml
@@ -152,6 +152,7 @@
| Description | |
| Amount | () |
| Account | |
+ | Note | |
diff --git a/addons/account_payment/account_payment_view.xml b/addons/account_payment/account_payment_view.xml
index c4088a62ee6..8d2eaadfa31 100644
--- a/addons/account_payment/account_payment_view.xml
+++ b/addons/account_payment/account_payment_view.xml
@@ -132,8 +132,8 @@
-
-
+
+
diff --git a/addons/base_import/models.py b/addons/base_import/models.py
index ab2ec8b72ce..9157b9b5920 100644
--- a/addons/base_import/models.py
+++ b/addons/base_import/models.py
@@ -157,7 +157,7 @@ class ir_import(orm.TransientModel):
for field in fields:
# FIXME: should match all translations & original
# TODO: use string distance (levenshtein? hamming?)
- if header == field['name'] \
+ if header.lower() == field['name'].lower() \
or header.lower() == field['string'].lower():
return [field]
diff --git a/addons/google_account/__init__.py b/addons/google_account/__init__.py
index 47544bfd347..c16913ab79c 100644
--- a/addons/google_account/__init__.py
+++ b/addons/google_account/__init__.py
@@ -20,3 +20,5 @@
##############################################################################
import google_account
import controllers
+
+from .google_account import TIMEOUT # noqa
\ No newline at end of file
diff --git a/addons/google_account/google_account.py b/addons/google_account/google_account.py
index db137b087e6..2cc56d0cba4 100644
--- a/addons/google_account/google_account.py
+++ b/addons/google_account/google_account.py
@@ -15,6 +15,7 @@ import simplejson
import logging
_logger = logging.getLogger(__name__)
+TIMEOUT = 20
class google_service(osv.osv_memory):
_name = 'google.service'
@@ -31,7 +32,7 @@ class google_service(osv.osv_memory):
data = werkzeug.url_encode(data)
try:
req = urllib2.Request("https://accounts.google.com/o/oauth2/token", data, headers)
- content = urllib2.urlopen(req).read()
+ content = urllib2.urlopen(req, timeout=TIMEOUT).read()
except urllib2.HTTPError:
error_msg = "Something went wrong during your token generation. Maybe your Authorization Code is invalid or already expired"
raise self.pool.get('res.config.settings').get_config_warning(cr, _(error_msg), context=context)
@@ -148,7 +149,7 @@ class google_service(osv.osv_memory):
raise ('Method not supported [%s] not in [GET, POST, PUT, PATCH or DELETE]!' % (type))
req.get_method = lambda: type.upper()
- request = urllib2.urlopen(req)
+ request = urllib2.urlopen(req, timeout=TIMEOUT)
status = request.getcode()
if int(status) in (204, 404): # Page not found, no response
diff --git a/addons/google_drive/google_drive.py b/addons/google_drive/google_drive.py
index 019ea745ce6..8bfc6fd7697 100644
--- a/addons/google_drive/google_drive.py
+++ b/addons/google_drive/google_drive.py
@@ -20,6 +20,7 @@
import logging
from openerp import SUPERUSER_ID
+from openerp.addons.google_account import TIMEOUT
from openerp.osv import fields, osv
from openerp.tools.translate import _
from openerp.exceptions import UserError
@@ -82,7 +83,7 @@ class config(osv.Model):
headers = {"Content-type": "application/x-www-form-urlencoded", "Accept-Encoding": "gzip, deflate"}
try:
req = urllib2.Request('https://accounts.google.com/o/oauth2/token', data, headers)
- content = urllib2.urlopen(req).read()
+ content = urllib2.urlopen(req, timeout=TIMEOUT).read()
except urllib2.HTTPError:
if user_is_admin:
model, action_id = self.pool['ir.model.data'].get_object_reference(cr, uid, 'base_setup', 'action_general_configuration')
@@ -102,7 +103,7 @@ class config(osv.Model):
headers = {"Content-type": "application/x-www-form-urlencoded", "Accept-Encoding": "gzip, deflate"}
try:
req = urllib2.Request(request_url, None, headers)
- parents = urllib2.urlopen(req).read()
+ parents = urllib2.urlopen(req, timeout=TIMEOUT).read()
except urllib2.HTTPError:
raise UserError(_("The Google Template cannot be found. Maybe it has been deleted."))
parents_dict = json.loads(parents)
@@ -114,7 +115,7 @@ class config(osv.Model):
data_json = json.dumps(data)
# resp, content = Http().request(request_url, "POST", data_json, headers)
req = urllib2.Request(request_url, data_json, headers)
- content = urllib2.urlopen(req).read()
+ content = urllib2.urlopen(req, timeout=TIMEOUT).read()
content = json.loads(content)
res = {}
if content.get('alternateLink'):
@@ -129,7 +130,7 @@ class config(osv.Model):
data = {'role': 'writer', 'type': 'anyone', 'value': '', 'withLink': True}
try:
req = urllib2.Request(request_url, json.dumps(data), headers)
- urllib2.urlopen(req)
+ urllib2.urlopen(req, timeout=TIMEOUT)
except urllib2.HTTPError:
raise self.pool.get('res.config.settings').get_config_warning(cr, _("The permission 'reader' for 'anyone with the link' has not been written on the document"), context=context)
user = self.pool['res.users'].browse(cr, uid, uid, context=context)
@@ -137,10 +138,10 @@ class config(osv.Model):
data = {'role': 'writer', 'type': 'user', 'value': user.email}
try:
req = urllib2.Request(request_url, json.dumps(data), headers)
- urllib2.urlopen(req)
+ urllib2.urlopen(req, timeout=TIMEOUT)
except urllib2.HTTPError:
pass
- return res
+ return res
def get_google_drive_config(self, cr, uid, res_model, res_id, context=None):
'''
diff --git a/addons/google_spreadsheet/google_spreadsheet.py b/addons/google_spreadsheet/google_spreadsheet.py
index df63ac5f632..2d062c9a9d2 100644
--- a/addons/google_spreadsheet/google_spreadsheet.py
+++ b/addons/google_spreadsheet/google_spreadsheet.py
@@ -27,7 +27,7 @@ import werkzeug.urls
import urllib2
from openerp.osv import osv
-from openerp import SUPERUSER_ID
+from openerp.addons.google_account import TIMEOUT
_logger = logging.getLogger(__name__)
@@ -92,7 +92,7 @@ class config(osv.osv):
'https://spreadsheets.google.com/feeds/cells/%s/od6/private/full/batch?%s' % (spreadsheet_key, werkzeug.url_encode({'v': 3, 'access_token': access_token})),
data=request,
headers={'content-type': 'application/atom+xml', 'If-Match': '*'})
- urllib2.urlopen(req)
+ urllib2.urlopen(req, timeout=TIMEOUT)
except (urllib2.HTTPError, urllib2.URLError):
_logger.warning("An error occured while writting the formula on the Google Spreadsheet.")
diff --git a/addons/l10n_be_coda/wizard/account_coda_import.py b/addons/l10n_be_coda/wizard/account_coda_import.py
index 0d3d1cf1fa3..6a3902acde6 100644
--- a/addons/l10n_be_coda/wizard/account_coda_import.py
+++ b/addons/l10n_be_coda/wizard/account_coda_import.py
@@ -241,7 +241,7 @@ class account_bank_statement_import(osv.TransientModel):
'partner_name': line['counterpartyName'],
'ref': line['ref'],
'sequence': line['sequence'],
- 'unique_import_id': line['ref'] + line['transactionRef'],
+ 'unique_import_id': str(statement['codaSeqNumber']) + '-' + str(statement['date']) + '-' + str(line['ref']),
}
statement_line.append(line_data)
if statement['coda_note'] != '':
diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py
index 4e19284e8c4..b8e0d9061f2 100644
--- a/addons/mrp/mrp.py
+++ b/addons/mrp/mrp.py
@@ -369,6 +369,7 @@ class mrp_bom(osv.osv):
class mrp_bom_line(osv.osv):
_name = 'mrp.bom.line'
_order = "sequence"
+ _rec_name = "product_id"
def _get_child_bom_lines(self, cr, uid, ids, field_name, arg, context=None):
"""If the BOM line refers to a BOM, return the ids of the child BOM lines"""
diff --git a/addons/point_of_sale/point_of_sale.py b/addons/point_of_sale/point_of_sale.py
index bd05695fbe6..a5c343fc9a9 100644
--- a/addons/point_of_sale/point_of_sale.py
+++ b/addons/point_of_sale/point_of_sale.py
@@ -1008,8 +1008,8 @@ class pos_order(osv.osv):
inv_line['price_unit'] = line.price_unit
inv_line['discount'] = line.discount
inv_line['name'] = inv_name
- if line.tax_ids:
- inv_line['invoice_line_tax_id'] = [(6, 0, [x.id for x in line.tax_ids])]
+ if inv_line['invoice_line_tax_id']:
+ inv_line['invoice_line_tax_id'] = [(6, 0, inv_line['invoice_line_tax_id'])]
inv_line_ref.create(cr, uid, inv_line, context=context)
inv_ref.button_reset_taxes(cr, uid, [inv_id], context=context)
self.signal_workflow(cr, uid, [order.id], 'invoice')
diff --git a/addons/web/static/src/js/views/list_view_editable.js b/addons/web/static/src/js/views/list_view_editable.js
index 47f5d6aab43..48e75c76090 100644
--- a/addons/web/static/src/js/views/list_view_editable.js
+++ b/addons/web/static/src/js/views/list_view_editable.js
@@ -9,6 +9,7 @@ odoo.define('web.ListEditor', function (require) {
*/
var core = require('web.core');
+var data = require('web.data');
var FormView = require('web.FormView');
var common = require('web.list_common');
var ListView = require('web.ListView');
@@ -584,7 +585,8 @@ ListView.include(/** @lends instance.web.ListView# */{
var self = this;
var on_write_callback = self.fields_view.arch.attrs.on_write;
if (!on_write_callback) { return $.when(); }
- return this.dataset.call(on_write_callback, [source_record.get('id')])
+ var context = new data.CompoundContext(self.dataset.get_context(), {'on_write_domain': self.dataset.domain}).eval();
+ return this.dataset.call(on_write_callback, [source_record.get('id'), context])
.then(function (ids) {
return $.when.apply(
null, _(ids).map(
diff --git a/addons/web/static/src/js/views/pivot_view.js b/addons/web/static/src/js/views/pivot_view.js
index 605cfe1667d..47883175342 100644
--- a/addons/web/static/src/js/views/pivot_view.js
+++ b/addons/web/static/src/js/views/pivot_view.js
@@ -154,6 +154,17 @@ var PivotView = View.extend({
if ((!self.active_measures.length) || fvg.arch.attrs.display_quantity){
self.active_measures.push('__count__');
}
+ // add active measures to the measure list. This is very rarely necessary, but it
+ // can be useful if one is working with a functional field non stored, but in a
+ // model with an overrided read_group method. In this case, the pivot view could
+ // work, and the measure should be allowed. However, be careful if you define a
+ // measure in your pivot view: non stored functional fields will probably not work
+ // (their aggregate will always be 0).
+ _.each(this.active_measures, function (m) {
+ if (!(m in self.measures)) {
+ self.measures[m] = self.fields[m];
+ }
+ });
},
prepare_fields: function (fields) {
var self = this,
diff --git a/addons/web/static/src/js/views/search_menus.js b/addons/web/static/src/js/views/search_menus.js
index b7338d0c4db..c4a6817cae0 100644
--- a/addons/web/static/src/js/views/search_menus.js
+++ b/addons/web/static/src/js/views/search_menus.js
@@ -59,7 +59,8 @@ return Widget.extend({
this.prepare_dropdown_menu([]);
return $.when();
}
- return this.model.call('get_filters', [this.target_model, this.action_id])
+ return this.model.call('get_filters', [this.target_model, this.action_id],
+ {context: this.searchview.dataset.context})
.done(this.proxy('prepare_dropdown_menu'));
},
prepare_dropdown_menu: function (filters) {
diff --git a/addons/web_kanban/static/src/js/kanban_common.js b/addons/web_kanban/static/src/js/kanban_common.js
index bcfb8105762..1ad2f3edf01 100644
--- a/addons/web_kanban/static/src/js/kanban_common.js
+++ b/addons/web_kanban/static/src/js/kanban_common.js
@@ -710,12 +710,12 @@ var KanbanGroup = Widget.extend({
},
do_show_more: function(evt) {
var self = this;
- var ids = self.view.dataset.ids.splice(0);
+ var ids = self.view.dataset.ids.slice(0);
return this.dataset.read_slice(this.view.fields_keys.concat(['__last_update']), {
'limit': self.view.limit,
'offset': self.dataset_offset += self.view.limit
}).then(function(records) {
- self.view.dataset.ids = ids.concat(self.dataset.ids);
+ self.view.dataset.ids = ids.concat(_.difference(self.dataset.ids, ids));
self.do_add_records(records);
self.compute_cards_auto_height();
self.view.postprocess_m2m_tags();
diff --git a/addons/website/models/ir_http.py b/addons/website/models/ir_http.py
index 9dd1347d4f3..7726c4c8cf7 100644
--- a/addons/website/models/ir_http.py
+++ b/addons/website/models/ir_http.py
@@ -1,6 +1,4 @@
# -*- coding: utf-8 -*-
-import datetime
-import hashlib
import logging
import os
import re
@@ -39,10 +37,9 @@ class ir_http(orm.AbstractModel):
def _auth_method_public(self):
if not request.session.uid:
- domain_name = request.httprequest.environ.get('HTTP_HOST', '').split(':')[0]
- website_id = self.pool['website']._get_current_website_id(request.cr, openerp.SUPERUSER_ID, domain_name, context=request.context)
- if website_id:
- request.uid = self.pool['website'].browse(request.cr, openerp.SUPERUSER_ID, website_id, request.context).user_id.id
+ website = self.pool['website'].get_current_website(request.cr, openerp.SUPERUSER_ID, context=request.context)
+ if website:
+ request.uid = website.user_id.id
else:
request.uid = self.pool['ir.model.data'].xmlid_to_res_id(request.cr, openerp.SUPERUSER_ID, 'base', 'public_user')
else:
@@ -170,7 +167,6 @@ class ir_http(orm.AbstractModel):
path += '?' + request.httprequest.query_string
return werkzeug.utils.redirect(path, code=301)
-
def _handle_exception(self, exception, code=500):
is_website_request = bool(getattr(request, 'website_enabled', False) and request.website)
if not is_website_request:
diff --git a/addons/website/models/website.py b/addons/website/models/website.py
index 4abed17d91b..2c1a373d586 100644
--- a/addons/website/models/website.py
+++ b/addons/website/models/website.py
@@ -309,7 +309,7 @@ class website(osv.osv):
return False
@openerp.tools.ormcache(skiparg=3)
- def _get_languages(self, cr, uid, id, context=None):
+ def _get_languages(self, cr, uid, id):
website = self.browse(cr, uid, id)
return [(lg.code, lg.name) for lg in website.language_ids]
@@ -324,7 +324,7 @@ class website(osv.osv):
return uri
def get_languages(self, cr, uid, ids, context=None):
- return self._get_languages(cr, uid, ids[0], context=context)
+ return self._get_languages(cr, uid, ids[0])
def get_alternate_languages(self, cr, uid, ids, req=None, context=None):
langs = []
@@ -350,17 +350,17 @@ class website(osv.osv):
lang['hreflang'] = lang['short']
return langs
- @openerp.tools.ormcache(skiparg=4)
- def _get_current_website_id(self, cr, uid, domain_name, context=None):
- ids = self.search(cr, uid, [('name', '=', domain_name)], limit=1, context=context)
+ @openerp.tools.ormcache(skiparg=3)
+ def _get_current_website_id(self, cr, uid, domain_name):
+ ids = self.search(cr, uid, [('name', '=', domain_name)], limit=1)
if ids:
return ids[0]
else:
- return self.search(cr, uid, [], limit=1, context=context)[0]
+ return self.search(cr, uid, [], limit=1)[0]
def get_current_website(self, cr, uid, context=None):
domain_name = request.httprequest.environ.get('HTTP_HOST', '').split(':')[0]
- website_id = self._get_current_website_id(cr, uid, domain_name, context=context)
+ website_id = self._get_current_website_id(cr, uid, domain_name)
request.context['website_id'] = website_id
return self.browse(cr, uid, website_id, context=context)
diff --git a/addons/website_quote/views/website_quotation.xml b/addons/website_quote/views/website_quotation.xml
index c5a7aa34854..0345b525f5a 100644
--- a/addons/website_quote/views/website_quotation.xml
+++ b/addons/website_quote/views/website_quotation.xml
@@ -157,7 +157,8 @@