-
-
-
+
+
Visualize on Google Maps
(
-
-
+
Free)
diff --git a/addons/website_portal/controllers/main.py b/addons/website_portal/controllers/main.py
index dc900002be7..cf8e818fc3b 100644
--- a/addons/website_portal/controllers/main.py
+++ b/addons/website_portal/controllers/main.py
@@ -37,6 +37,16 @@ class website_account(http.Controller):
values.update(post)
if not error:
post.update({'zip': post.pop('zipcode', '')})
+ if partner.type == "contact":
+ address_fields = {
+ 'city': post.pop('city'),
+ 'street': post.pop('street'),
+ 'street2': post.pop('street2'),
+ 'zip': post.pop('zip'),
+ 'country_id': post.pop('country_id'),
+ 'state_id': post.pop('state_id')
+ }
+ partner.commercial_partner_id.write(address_fields)
partner.sudo().write(post)
if redirect:
return request.redirect(redirect)
diff --git a/addons/website_quote/views/website_quotation.xml b/addons/website_quote/views/website_quotation.xml
index 75b1086e6e9..ee48f5397d2 100644
--- a/addons/website_quote/views/website_quotation.xml
+++ b/addons/website_quote/views/website_quotation.xml
@@ -446,7 +446,7 @@
- -
+
-
Edit Quote
Back to Sale Order
diff --git a/doc/cla/corporate/pine-view-buildings.md b/doc/cla/corporate/pine-view-buildings.md
new file mode 100644
index 00000000000..78caa110a70
--- /dev/null
+++ b/doc/cla/corporate/pine-view-buildings.md
@@ -0,0 +1,15 @@
+USA, 08/13/2016
+
+Pine View Buildings agrees to the terms of the Odoo Corporate Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Freeman Helmuth freeman@pineview.biz https://github.com/busyfritz
+
+List of contributors:
+
+Freeman Helmuth freeman@pineview.biz https://github.com/busyfritz
diff --git a/openerp/addons/base/ir/ir_http.py b/openerp/addons/base/ir/ir_http.py
index 6e6cb250312..4907ce131a7 100644
--- a/openerp/addons/base/ir/ir_http.py
+++ b/openerp/addons/base/ir/ir_http.py
@@ -21,7 +21,8 @@ import werkzeug.utils
import odoo
from odoo import api, http, models, tools, SUPERUSER_ID
from odoo.exceptions import AccessDenied, AccessError
-from odoo.http import request, STATIC_CACHE
+from odoo.http import request, STATIC_CACHE, content_disposition
+from odoo.tools.mimetypes import guess_mimetype
from odoo.modules.module import get_resource_path, get_module_path
_logger = logging.getLogger(__name__)
@@ -210,16 +211,7 @@ class IrHttp(models.AbstractModel):
return self._routing_map
def content_disposition(self, filename):
- filename = tools.ustr(filename)
- escaped = urllib2.quote(filename.encode('utf8'))
- browser = request.httprequest.user_agent.browser
- version = int((request.httprequest.user_agent.version or '0').split('.')[0])
- if browser == 'msie' and version < 9:
- return "attachment; filename=%s" % escaped
- elif browser == 'safari' and version < 537:
- return u"attachment; filename=%s" % filename.encode('ascii', 'replace')
- else:
- return "attachment; filename*=UTF-8''%s" % escaped
+ return content_disposition(filename)
def binary_content(self, xmlid=None, model='ir.attachment', id=None, field='datas', unique=False, filename=None, filename_field='datas_fname', download=False, mimetype=None, default_mimetype='application/octet-stream', env=None):
""" Get file, attachment or downloadable content
@@ -305,7 +297,8 @@ class IrHttp(models.AbstractModel):
attach_mimetype = env['ir.attachment'].search_read(domain=[('res_model', '=', model), ('res_id', '=', id), ('res_field', '=', field)], fields=['mimetype'], limit=1)
mimetype = attach_mimetype and attach_mimetype[0]['mimetype']
if not mimetype:
- mimetype = default_mimetype
+ mimetype = guess_mimetype(base64.b64decode(content), default=default_mimetype)
+
headers += [('Content-Type', mimetype), ('X-Content-Type-Options', 'nosniff')]
# cache
@@ -318,7 +311,6 @@ class IrHttp(models.AbstractModel):
# content-disposition default name
if download:
headers.append(('Content-Disposition', self.content_disposition(filename)))
-
return (status, headers, content)
diff --git a/openerp/addons/base/res/res_users.py b/openerp/addons/base/res/res_users.py
index 775384ccbb7..73b909607d3 100644
--- a/openerp/addons/base/res/res_users.py
+++ b/openerp/addons/base/res/res_users.py
@@ -678,8 +678,7 @@ class GroupsView(models.Model):
@api.multi
def write(self, values):
res = super(GroupsView, self).write(values)
- if 'category_id' in values:
- self._update_user_groups_view()
+ self._update_user_groups_view()
# ir_values.get_actions() depends on action records
self.env['ir.values'].clear_caches()
return res
diff --git a/openerp/addons/base/tests/__init__.py b/openerp/addons/base/tests/__init__.py
index e9414be9011..2325c11aa8e 100644
--- a/openerp/addons/base/tests/__init__.py
+++ b/openerp/addons/base/tests/__init__.py
@@ -7,12 +7,14 @@ import test_expression
import test_func
import test_ir_actions
import test_ir_attachment
+import test_ir_http
import test_ir_filters
import test_ir_sequence
import test_ir_sequence_date_range
import test_ir_values
import test_mail
import test_menu
+import test_mimetypes
import test_orm
import test_ormcache
import test_osv
@@ -21,7 +23,7 @@ import test_res_config
import test_res_lang
import test_search
import test_translate
-#import test_uninstall
+#import test_uninstall # loop
import test_user_has_group
import test_view_validation
import test_views
diff --git a/openerp/addons/base/tests/test_ir_http.py b/openerp/addons/base/tests/test_ir_http.py
new file mode 100644
index 00000000000..649cd069816
--- /dev/null
+++ b/openerp/addons/base/tests/test_ir_http.py
@@ -0,0 +1,81 @@
+# -*- coding: utf-8 -*-
+
+from openerp.tests import common
+import openerp
+
+GIF = "R0lGODdhAQABAIAAAP///////ywAAAAAAQABAAACAkQBADs="
+
+
+class test_ir_http_mimetype(common.TransactionCase):
+
+ def test_ir_http_mimetype_attachment(self):
+ """ Test mimetype for attachment """
+ attachment = self.env['ir.attachment'].create({
+ 'datas': GIF,
+ 'name': 'Test mimetype gif',
+ 'datas_fname': 'file.gif'})
+
+ status, headers, content = self.env['ir.http'].binary_content(
+ id=attachment.id,
+ mimetype=None,
+ default_mimetype='application/octet-stream',
+ env=self.env
+ )
+ mimetype = dict(headers).get('Content-Type')
+ self.assertEqual(mimetype, 'image/gif')
+
+ def test_ir_http_mimetype_attachment_name(self):
+ """ Test mimetype for attachment with bad name"""
+ attachment = self.env['ir.attachment'].create({
+ 'datas': GIF,
+ 'name': 'Test mimetype gif with png name',
+ 'datas_fname': 'file.png'})
+
+ status, headers, content = self.env['ir.http'].binary_content(
+ id=attachment.id,
+ mimetype=None,
+ default_mimetype='application/octet-stream',
+ env=self.env
+ )
+ mimetype = dict(headers).get('Content-Type')
+ # TODO: fix and change it in master, should be image/gif
+ self.assertEqual(mimetype, 'image/png')
+
+ def test_ir_http_mimetype_basic_field(self):
+ """ Test mimetype for classic field """
+ partner = self.env['res.partner'].create({
+ 'image': GIF,
+ 'name': 'Test mimetype basic field',
+ })
+
+ status, headers, content = self.env['ir.http'].binary_content(
+ model='res.partner',
+ id=partner.id,
+ field='image',
+ default_mimetype='application/octet-stream',
+ env=self.env
+ )
+ mimetype = dict(headers).get('Content-Type')
+ self.assertEqual(mimetype, 'image/gif')
+
+ def test_ir_http_mimetype_computed_field(self):
+ """ Test mimetype for computed field wich resize picture"""
+ prop = self.env['ir.property'].create({
+ 'fields_id': self.env['ir.model.fields'].search([], limit=1).id,
+ 'name': "Property binary",
+ 'value_binary': GIF,
+ 'type': 'binary',
+ })
+
+ resized = openerp.tools.image_get_resized_images(prop.value_binary, return_big=True, avoid_resize_medium=True)['image_small']
+ # Simul computed field which resize and that is not attachement=True (E.G. on product)
+ prop.write({'value_binary': resized})
+ status, headers, content = self.env['ir.http'].binary_content(
+ model='ir.property',
+ id=prop.id,
+ field='value_binary',
+ default_mimetype='application/octet-stream',
+ env=self.env
+ )
+ mimetype = dict(headers).get('Content-Type')
+ self.assertEqual(mimetype, 'image/gif')
diff --git a/openerp/addons/base/tests/test_mimetypes.py b/openerp/addons/base/tests/test_mimetypes.py
new file mode 100644
index 00000000000..0d3ce6b71fc
--- /dev/null
+++ b/openerp/addons/base/tests/test_mimetypes.py
@@ -0,0 +1,52 @@
+import base64
+import unittest
+
+from openerp.tools.mimetypes import guess_mimetype
+
+PNG = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVQI12P4//8/AAX+Av7czFnnAAAAAElFTkSuQmCC'
+GIF = "R0lGODdhAQABAIAAAP///////ywAAAAAAQABAAACAkQBADs="
+BMP = """Qk1+AAAAAAAAAHoAAABsAAAAAQAAAAEAAAABABgAAAAAAAQAAAATCwAAEwsAAAAAAAAAAAAAQkdScwAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAD///8A"""
+JPG = """/9j/4AAQSkZJRgABAQEASABIAAD//gATQ3JlYXRlZCB3aXRoIEdJTVD/2wBDAP
+//////////////////////////////////////////////////////////////////////////////////////2wBDAf///////
+///////////////////////////////////////////////////////////////////////////////wgARCAABAAEDAREAAhEB
+AxEB/8QAFAABAAAAAAAAAAAAAAAAAAAAAv/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAUf/xAAUEAEAAAAAAAA
+AAAAAAAAAAAAA/9oACAEBAAEFAn//xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oACAEDAQE/AX//xAAUEQEAAAAAAAAAAAAAAAAAAA
+AA/9oACAECAQE/AX//xAAUEAEAAAAAAAAAAAAAAAAAAAAA/9oACAEBAAY/An//xAAUEAEAAAAAAAAAAAAAAAAAAAAA/9oACAEBA
+AE/IX//2gAMAwEAAgADAAAAEB//xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oACAEDAQE/EH//xAAUEQEAAAAAAAAAAAAAAAAAAAAA
+/9oACAECAQE/EH//xAAUEAEAAAAAAAAAAAAAAAAAAAAA/9oACAEBAAE/EH//2Q=="""
+
+
+class test_guess_mimetype(unittest.TestCase):
+
+ def test_default_mimetype_empty(self):
+ mimetype = guess_mimetype('')
+ self.assertEqual(mimetype, 'application/octet-stream')
+
+ def test_default_mimetype(self):
+ mimetype = guess_mimetype('', default='test')
+ self.assertEqual(mimetype, 'test')
+
+ def test_mimetype_png(self):
+ content = base64.b64decode(PNG)
+ mimetype = guess_mimetype(content, default='test')
+ self.assertEqual(mimetype, 'image/png')
+
+ def test_mimetype_bmp(self):
+ content = base64.b64decode(BMP)
+ mimetype = guess_mimetype(content, default='test')
+ self.assertEqual(mimetype, 'image/bmp')
+
+ def test_mimetype_jpg(self):
+ content = base64.b64decode(JPG)
+ mimetype = guess_mimetype(content, default='test')
+ self.assertEqual(mimetype, 'image/jpeg')
+
+ def test_mimetype_gif(self):
+ content = base64.b64decode(GIF)
+ mimetype = guess_mimetype(content, default='test')
+ self.assertEqual(mimetype, 'image/gif')
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/openerp/addons/base/tests/test_uninstall.py b/openerp/addons/base/tests/test_uninstall.py
index 8bb658d61ba..a99240d703b 100644
--- a/openerp/addons/base/tests/test_uninstall.py
+++ b/openerp/addons/base/tests/test_uninstall.py
@@ -4,7 +4,7 @@ import unittest
import openerp
from openerp import SUPERUSER_ID
-import common
+from openerp.tests import common
ADMIN_USER_ID = common.ADMIN_USER_ID
diff --git a/openerp/http.py b/openerp/http.py
index d837131d52d..45db589aa28 100644
--- a/openerp/http.py
+++ b/openerp/http.py
@@ -20,6 +20,7 @@ import sys
import threading
import time
import traceback
+import urllib2
import urlparse
import warnings
from zlib import adler32
@@ -1809,6 +1810,18 @@ def send_file(filepath_or_fp, mimetype=None, as_attachment=False, filename=None,
rv.headers.pop('x-sendfile', None)
return rv
+def content_disposition(filename):
+ filename = openerp.tools.ustr(filename)
+ escaped = urllib2.quote(filename.encode('utf8'))
+ browser = request.httprequest.user_agent.browser
+ version = int((request.httprequest.user_agent.version or '0').split('.')[0])
+ if browser == 'msie' and version < 9:
+ return "attachment; filename=%s" % escaped
+ elif browser == 'safari' and version < 537:
+ return u"attachment; filename=%s" % filename.encode('ascii', 'replace')
+ else:
+ return "attachment; filename*=UTF-8''%s" % escaped
+
#----------------------------------------------------------
# RPC controller
#----------------------------------------------------------
diff --git a/openerp/tools/mimetypes.py b/openerp/tools/mimetypes.py
index cf5a9debc90..581dcb27bd6 100644
--- a/openerp/tools/mimetypes.py
+++ b/openerp/tools/mimetypes.py
@@ -103,10 +103,11 @@ _Entry = collections.namedtuple('_Entry', ['mimetype', 'signatures', 'discrimina
_mime_mappings = (
# pdf
_Entry('application/pdf', ['%PDF'], []),
- # jpg, jpeg, png, gif
+ # jpg, jpeg, png, gif, bmp
_Entry('image/jpeg', ['\xFF\xD8\xFF\xE0', '\xFF\xD8\xFF\xE2', '\xFF\xD8\xFF\xE3', '\xFF\xD8\xFF\xE1'], []),
_Entry('image/png', ['\x89PNG\r\n\x1A\n'], []),
_Entry('image/gif', ['GIF87a', 'GIF89a'], []),
+ _Entry('image/bmp', ['BM'], []),
# OLECF files in general (Word, Excel, PPT, default to word because why not?)
_Entry('application/msword', ['\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1', '\x0D\x44\x4F\x43'], [
_check_olecf
@@ -114,7 +115,7 @@ _mime_mappings = (
# zip, but will include jar, odt, ods, odp, docx, xlsx, pptx, apk
_Entry('application/zip', ['PK\x03\x04'], [_check_ooxml, _check_open_container_format]),
)
-def guess_mimetype(bin_data):
+def guess_mimetype(bin_data, default='application/octet-stream'):
""" Attempts to guess the mime type of the provided binary data, similar
to but significantly more limited than libmagic
@@ -140,7 +141,7 @@ def guess_mimetype(bin_data):
# if no discriminant or no discriminant matches, return
# primary mime type
return entry.mimetype
- return 'application/octet-stream'
+ return default
try: