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 @@