[MERGE] forward port of branch saas-9 up to 549daaa

This commit is contained in:
Christophe Simonis
2016-04-05 19:27:34 +02:00
25 changed files with 258 additions and 232 deletions
+2
View File
@@ -123,6 +123,8 @@ class AccountFiscalPosition(models.Model):
if not country_id:
return False
base_domain = [('auto_apply', '=', True), ('vat_required', '=', vat_required)]
if self.env.context.get('force_company'):
base_domain.append(('company_id', '=', self.env.context.get('force_company')))
null_state_dom = state_domain = [('state_ids', '=', False)]
null_zip_dom = zip_domain = [('zip_from', '=', 0), ('zip_to', '=', 0)]
null_country_dom = [('country_id', '=', False), ('country_group_id', '=', False)]
@@ -234,7 +234,7 @@
<div class="col-xs-6 o_kanban_primary_right">
<div class="row">
<div class="col-xs-6">
<span title="Balance in Odoo">Balance in Odoo</span>
<span title="Balance in Odoo">Balance in GL</span>
</div>
<div class="col-xs-6 text-right">
<span><t t-esc="dashboard.account_balance"/></span>
+2 -1
View File
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
import cgi
import json
from openerp.http import Controller, route
@@ -15,4 +16,4 @@ class ImportController(Controller):
}, req.context)
return 'window.top.%s(%s)' % (
jsonp, json.dumps({'result': written}))
cgi.escape(jsonp), json.dumps({'result': written}))
@@ -2,12 +2,30 @@
-- PostgreSQL database dump
--
-- Dumped from database version 9.5.2
-- Dumped by pg_dump version 9.5.2
SET statement_timeout = 0;
SET lock_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = off;
SET standard_conforming_strings = on;
SET check_function_bodies = false;
SET client_min_messages = warning;
SET escape_string_warning = off;
SET row_security = off;
--
-- Name: plpgsql; Type: EXTENSION; Schema: -; Owner: -
--
CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;
--
-- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner: -
--
COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';
SET search_path = public, pg_catalog;
@@ -16,7 +34,7 @@ SET default_tablespace = '';
SET default_with_oids = false;
--
-- Name: companies; Type: TABLE; Schema: public; Owner: fp; Tablespace:
-- Name: companies; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE companies (
@@ -25,38 +43,27 @@ CREATE TABLE companies (
);
ALTER TABLE public.companies OWNER TO fp;
--
-- Name: companies_id_seq; Type: SEQUENCE; Schema: public; Owner: fp
-- Name: companies_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE companies_id_seq
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER TABLE public.companies_id_seq OWNER TO fp;
--
-- Name: companies_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: fp
-- Name: companies_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE companies_id_seq OWNED BY companies.id;
--
-- Name: companies_id_seq; Type: SEQUENCE SET; Schema: public; Owner: fp
--
SELECT pg_catalog.setval('companies_id_seq', 3, true);
--
-- Name: persons; Type: TABLE; Schema: public; Owner: fp; Tablespace:
-- Name: persons; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE persons (
@@ -66,52 +73,41 @@ CREATE TABLE persons (
);
ALTER TABLE public.persons OWNER TO fp;
--
-- Name: persons_id_seq; Type: SEQUENCE; Schema: public; Owner: fp
-- Name: persons_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE persons_id_seq
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER TABLE public.persons_id_seq OWNER TO fp;
--
-- Name: persons_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: fp
-- Name: persons_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE persons_id_seq OWNED BY persons.id;
--
-- Name: persons_id_seq; Type: SEQUENCE SET; Schema: public; Owner: fp
--
SELECT pg_catalog.setval('persons_id_seq', 4, true);
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: fp
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY companies ALTER COLUMN id SET DEFAULT nextval('companies_id_seq'::regclass);
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: fp
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY persons ALTER COLUMN id SET DEFAULT nextval('persons_id_seq'::regclass);
--
-- Data for Name: companies; Type: TABLE DATA; Schema: public; Owner: fp
-- Data for Name: companies; Type: TABLE DATA; Schema: public; Owner: -
--
COPY companies (id, company_name) FROM stdin;
@@ -122,19 +118,33 @@ COPY companies (id, company_name) FROM stdin;
--
-- Data for Name: persons; Type: TABLE DATA; Schema: public; Owner: fp
-- Name: companies_id_seq; Type: SEQUENCE SET; Schema: public; Owner: -
--
SELECT pg_catalog.setval('companies_id_seq', 3, true);
--
-- Data for Name: persons; Type: TABLE DATA; Schema: public; Owner: -
--
COPY persons (id, company_id, person_name) FROM stdin;
1 1 Fabien
2 1 Laurence
3 2 Eric
4 3 Ramsy
4 3 Ramzy
\.
--
-- Name: companies_pkey; Type: CONSTRAINT; Schema: public; Owner: fp; Tablespace:
-- Name: persons_id_seq; Type: SEQUENCE SET; Schema: public; Owner: -
--
SELECT pg_catalog.setval('persons_id_seq', 4, true);
--
-- Name: companies_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY companies
@@ -142,13 +152,23 @@ ALTER TABLE ONLY companies
--
-- Name: persons_company_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: fp
-- Name: persons_company_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY persons
ADD CONSTRAINT persons_company_id_fkey FOREIGN KEY (company_id) REFERENCES companies(id);
--
-- Name: public; Type: ACL; Schema: -; Owner: -
--
REVOKE ALL ON SCHEMA public FROM PUBLIC;
REVOKE ALL ON SCHEMA public FROM postgres;
GRANT ALL ON SCHEMA public TO postgres;
GRANT ALL ON SCHEMA public TO PUBLIC;
--
-- PostgreSQL database dump complete
--
@@ -1,10 +1,6 @@
Order Date,Order Reference,Supplier,Destination,Pricelist,Order Lines / Product,Order Lines / Quantity
2012-12-15,PO00008,ASUSTeK,Stock,Default Purchase Pricelist,ADPT,20
,,,,,CARD,30
,,,,,C-Case,40
2012-12-15,PO00009,Axelor,Stock,Default Purchase Pricelist,CD,5
,,,,,CPUa8,15
2012-12-15,PO000010,China Export,Stock,Default Purchase Pricelist,HDD SH-1,10
,,,,,HDD SH-2,20
,,,,,LAP-CUS,35
,,,,,LAP-E5,40
"Order Date","Order Reference",Vendor,"Order Lines / Product","Order Lines / Description","Order Lines / Quantity","Order Lines / Product Unit of Measure","Order Lines / Unit Price","Order Lines / Scheduled Date"
2016-12-15,PO00008,ASUSTeK,ADPT,ADPT,20.0,"Unit(s)",13.0,2016-12-15
,,,CARD,CARD,30,"Unit(s)",876.0,2016-12-15
,,,C-Case,C-Case,40,"Unit(s)",20.0,2016-12-15
2016-12-15,PO00009,Camptocamp,CD,CD,5,"Unit(s)",18.4,2016-12-15
,,,CPUa8,CPUa8,15,"Unit(s)",1910.0,2016-12-15
1 Order Date Order Reference Supplier Vendor Destination Order Lines / Product Pricelist Order Lines / Description Order Lines / Quantity Order Lines / Product Unit of Measure Order Lines / Unit Price Order Lines / Scheduled Date
2 2012-12-15 2016-12-15 PO00008 ASUSTeK ASUSTeK Stock ADPT Default Purchase Pricelist ADPT 20 20.0 Unit(s) 13.0 2016-12-15
3 CARD CARD 30 Unit(s) 876.0 2016-12-15
4 C-Case C-Case 40 Unit(s) 20.0 2016-12-15
5 2012-12-15 2016-12-15 PO00009 Axelor Camptocamp Stock CD Default Purchase Pricelist CD 5 Unit(s) 18.4 2016-12-15
6 CPUa8 CPUa8 15 Unit(s) 1910.0 2016-12-15
2012-12-15 PO000010 China Export Stock HDD SH-1 Default Purchase Pricelist 10
HDD SH-2 20
LAP-CUS 35
LAP-E5 40
@@ -1,6 +1,3 @@
"Order Reference","Supplier","Destination","Pricelist","Order Lines / Product","Order Lines / Quantity"
"PO000020","ASUSTeK","Stock","Default Purchase Pricelist","ADPT",20
,,,,"CARD",30
,,,,"C-Case",40
"PO000021","Axelor","Stock","Default Purchase Pricelist","CD",5
,,,,"CPUa8",15
"Order Reference","Vendor"
"PO000020","ASUSTeK"
"PO000021","Camptocamp"
1 Order Reference Supplier Vendor Destination Pricelist Order Lines / Product Order Lines / Quantity
2 PO000020 ASUSTeK ASUSTeK Stock Default Purchase Pricelist ADPT 20
3 PO000021 Camptocamp CARD 30
C-Case 40
PO000021 Axelor Stock Default Purchase Pricelist CD 5
CPUa8 15
+24
View File
@@ -1372,6 +1372,30 @@ class calendar_event(osv.Model):
('user_id', '=', uid),
]
@api.multi
def _get_message_unread(self):
id_map = {x: calendar_id2real_id(x) for x in self.ids}
real = self.browse(set(id_map.values()))
super(calendar_event, real)._get_message_unread()
for event in self:
if event.id == id_map[event.id]:
continue
rec = self.browse(id_map[event.id])
event.message_unread_counter = rec.message_unread_counter
event.message_unread = rec.message_unread
@api.multi
def _get_message_needaction(self):
id_map = {x: calendar_id2real_id(x) for x in self.ids}
real = self.browse(set(id_map.values()))
super(calendar_event, real)._get_message_needaction()
for event in self:
if event.id == id_map[event.id]:
continue
rec = self.browse(id_map[event.id])
event.message_needaction_counter = rec.message_needaction_counter
event.message_needaction = rec.message_needaction
@api.cr_uid_ids_context
def message_post(self, cr, uid, thread_id, context=None, **kwargs):
if isinstance(thread_id, basestring):
+10 -16
View File
@@ -142,30 +142,24 @@ class fleet_vehicle_model_brand(osv.Model):
image = openerp.fields.Binary("Logo", attachment=True,
help="This field holds the image used as logo for the brand, limited to 1024x1024px.")
image_medium = openerp.fields.Binary("Medium-sized image",
compute='_compute_images', inverse='_inverse_image_medium', store=True, attachment=True,
image_medium = openerp.fields.Binary("Medium-sized image", attachment=True,
help="Medium-sized logo of the brand. It is automatically "\
"resized as a 128x128px image, with aspect ratio preserved. "\
"Use this field in form views or some kanban views.")
image_small = openerp.fields.Binary("Small-sized image",
compute='_compute_images', inverse='_inverse_image_small', store=True, attachment=True,
image_small = openerp.fields.Binary("Small-sized image", attachment=True,
help="Small-sized logo of the brand. It is automatically "\
"resized as a 64x64px image, with aspect ratio preserved. "\
"Use this field anywhere a small image is required.")
@openerp.api.depends('image')
def _compute_images(self):
for rec in self:
rec.image_medium = tools.image_resize_image_medium(rec.image)
rec.image_small = tools.image_resize_image_small(rec.image)
@openerp.api.model
def create(self, vals):
tools.image_resize_images(vals)
return super(fleet_vehicle_model_brand, self).create(vals)
def _inverse_image_medium(self):
for rec in self:
rec.image = tools.image_resize_image_big(rec.image_medium)
def _inverse_image_small(self):
for rec in self:
rec.image = tools.image_resize_image_big(rec.image_small)
@openerp.api.multi
def write(self, vals):
tools.image_resize_images(vals)
return super(fleet_vehicle_model_brand, self).write(vals)
class fleet_vehicle(osv.Model):
+12 -18
View File
@@ -172,31 +172,15 @@ class hr_employee(osv.osv):
# image: all image fields are base64 encoded and PIL-supported
image = openerp.fields.Binary("Photo", attachment=True,
help="This field holds the image used as photo for the employee, limited to 1024x1024px.")
image_medium = openerp.fields.Binary("Medium-sized photo",
compute='_compute_images', inverse='_inverse_image_medium', store=True, attachment=True,
image_medium = openerp.fields.Binary("Medium-sized photo", attachment=True,
help="Medium-sized photo of the employee. It is automatically "\
"resized as a 128x128px image, with aspect ratio preserved. "\
"Use this field in form views or some kanban views.")
image_small = openerp.fields.Binary("Small-sized photo",
compute='_compute_images', inverse='_inverse_image_small', store=True, attachment=True,
image_small = openerp.fields.Binary("Small-sized photo", attachment=True,
help="Small-sized photo of the employee. It is automatically "\
"resized as a 64x64px image, with aspect ratio preserved. "\
"Use this field anywhere a small image is required.")
@api.depends('image')
def _compute_images(self):
for rec in self:
rec.image_medium = tools.image_resize_image_medium(rec.image)
rec.image_small = tools.image_resize_image_small(rec.image)
def _inverse_image_medium(self):
for rec in self:
rec.image = tools.image_resize_image_big(rec.image_medium)
def _inverse_image_small(self):
for rec in self:
rec.image = tools.image_resize_image_big(rec.image_small)
def _get_default_image(self, cr, uid, context=None):
image_path = get_module_resource('hr', 'static/src/img', 'default_image.png')
return tools.image_resize_image_big(open(image_path, 'rb').read().encode('base64'))
@@ -207,6 +191,16 @@ class hr_employee(osv.osv):
'color': 0,
}
@api.model
def create(self, vals):
tools.image_resize_images(vals)
return super(hr_employee, self).create(vals)
@api.multi
def write(self, vals):
tools.image_resize_images(vals)
return super(hr_employee, self).write(vals)
def unlink(self, cr, uid, ids, context=None):
resource_ids = []
for employee in self.browse(cr, uid, ids, context=context):
@@ -48,13 +48,11 @@ class ImLivechatChannel(models.Model):
# images fields
image = fields.Binary('Image', default=_default_image, attachment=True,
help="This field holds the image used as photo for the group, limited to 1024x1024px.")
image_medium = fields.Binary('Medium',
compute='_compute_image', store=True, attachment=True,
image_medium = fields.Binary('Medium', attachment=True,
help="Medium-sized photo of the group. It is automatically "\
"resized as a 128x128px image, with aspect ratio preserved. "\
"Use this field in form views or some kanban views.")
image_small = fields.Binary('Thumbnail',
compute='_compute_image', store=True, attachment=True,
image_small = fields.Binary('Thumbnail', attachment=True,
help="Small-sized photo of the group. It is automatically "\
"resized as a 64x64px image, with aspect ratio preserved. "\
"Use this field anywhere a small image is required.")
@@ -69,12 +67,6 @@ class ImLivechatChannel(models.Model):
def _are_you_inside(self):
self.are_you_inside = bool(self.env.uid in [u.id for u in self.user_ids])
@api.one
@api.depends('image')
def _compute_image(self):
self.image_medium = tools.image_resize_image_medium(self.image)
self.image_small = tools.image_resize_image_small(self.image)
@api.multi
def _compute_script_external(self):
view = self.env['ir.model.data'].get_object('im_livechat', 'external_loader')
@@ -111,6 +103,16 @@ class ImLivechatChannel(models.Model):
else:
record.rating_percentage_satisfaction = -1
@api.model
def create(self, vals):
tools.image_resize_images(vals)
return super(ImLivechatChannel, self).create(vals)
@api.multi
def write(self, vals):
tools.image_resize_images(vals)
return super(ImLivechatChannel, self).write(vals)
# --------------------------
# Action Methods
# --------------------------
+4 -16
View File
@@ -69,13 +69,11 @@ class Channel(models.Model):
# image: all image fields are base64 encoded and PIL-supported
image = fields.Binary("Photo", default=_get_default_image, attachment=True,
help="This field holds the image used as photo for the group, limited to 1024x1024px.")
image_medium = fields.Binary('Medium-sized photo',
compute='_get_image', inverse='_set_image_medium', store=True, attachment=True,
image_medium = fields.Binary('Medium-sized photo', attachment=True,
help="Medium-sized photo of the group. It is automatically "
"resized as a 128x128px image, with aspect ratio preserved. "
"Use this field in form views or some kanban views.")
image_small = fields.Binary('Small-sized photo',
compute='_get_image', inverse='_set_image_small', store=True, attachment=True,
image_small = fields.Binary('Small-sized photo', attachment=True,
help="Small-sized photo of the group. It is automatically "
"resized as a 64x64px image, with aspect ratio preserved. "
"Use this field anywhere a small image is required.")
@@ -100,20 +98,9 @@ class Channel(models.Model):
for record in self:
record.is_member = record in membership_ids
@api.one
@api.depends('image')
def _get_image(self):
self.image_medium = tools.image_resize_image_medium(self.image)
self.image_small = tools.image_resize_image_small(self.image)
def _set_image_medium(self):
self.image = tools.image_resize_image_big(self.image_medium)
def _set_image_small(self):
self.image = tools.image_resize_image_big(self.image_small)
@api.model
def create(self, vals):
tools.image_resize_images(vals)
# Create channel and alias
channel = super(Channel, self.with_context(
alias_model_name=self._name, alias_parent_model_name=self._name, mail_create_nolog=True, mail_create_nosubscribe=True)
@@ -147,6 +134,7 @@ class Channel(models.Model):
@api.multi
def write(self, vals):
tools.image_resize_images(vals)
result = super(Channel, self).write(vals)
if vals.get('group_ids'):
self._subscribe_users()
+13 -19
View File
@@ -3,7 +3,7 @@ import logging
import openerp
from openerp.osv import osv, fields
from openerp.tools import float_round, float_repr, image_get_resized_images, image_resize_image_big
from openerp.tools import float_round, float_repr, image_resize_images
from openerp.tools.translate import _
_logger = logging.getLogger(__name__)
@@ -97,31 +97,15 @@ class PaymentAcquirer(osv.Model):
image = openerp.fields.Binary("Image", attachment=True,
help="This field holds the image used for this provider, limited to 1024x1024px")
image_medium = openerp.fields.Binary("Medium-sized image",
compute='_compute_images', inverse='_inverse_image_medium', store=True, attachment=True,
image_medium = openerp.fields.Binary("Medium-sized image", attachment=True,
help="Medium-sized image of this provider. It is automatically "\
"resized as a 128x128px image, with aspect ratio preserved. "\
"Use this field in form views or some kanban views.")
image_small = openerp.fields.Binary("Small-sized image",
compute='_compute_images', inverse='_inverse_image_small', store=True, attachment=True,
image_small = openerp.fields.Binary("Small-sized image", attachment=True,
help="Small-sized image of this provider. It is automatically "\
"resized as a 64x64px image, with aspect ratio preserved. "\
"Use this field anywhere a small image is required.")
@openerp.api.depends('image')
def _compute_images(self):
for rec in self:
rec.image_medium = openerp.tools.image_resize_image_medium(rec.image)
rec.image_small = openerp.tools.image_resize_image_small(rec.image)
def _inverse_image_medium(self):
for rec in self:
rec.image = openerp.tools.image_resize_image_big(rec.image_medium)
def _inverse_image_small(self):
for rec in self:
rec.image = openerp.tools.image_resize_image_big(rec.image_small)
_defaults = {
'company_id': lambda self, cr, uid, obj, ctx=None: self.pool['res.users'].browse(cr, uid, uid).company_id.id,
'environment': 'test',
@@ -145,6 +129,16 @@ class PaymentAcquirer(osv.Model):
(_check_required_if_provider, 'Required fields not filled', ['required for this provider']),
]
@openerp.api.model
def create(self, vals):
image_resize_images(vals)
return super(PaymentAcquirer, self).create(vals)
@openerp.api.multi
def write(self, vals):
image_resize_images(vals)
return super(PaymentAcquirer, self).write(vals)
def get_form_action_url(self, cr, uid, id, context=None):
""" Returns the form action URL, for form-based acquirer implementations. """
acquirer = self.browse(cr, uid, id, context=context)
+10 -17
View File
@@ -2,7 +2,6 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models, tools, _
class PosCategory(models.Model):
_name = "pos.category"
_description = "Public Category"
@@ -23,30 +22,24 @@ class PosCategory(models.Model):
# buttons have consistent styling.
image = fields.Binary(attachment=True,
help="This field holds the image used as image for the cateogry, limited to 1024x1024px.")
image_medium = fields.Binary(string="Medium-sized image",
compute='_compute_images', inverse='_inverse_image_medium', store=True, attachment=True,
image_medium = fields.Binary(string="Medium-sized image", attachment=True,
help="Medium-sized image of the category. It is automatically "
"resized as a 128x128px image, with aspect ratio preserved. "
"Use this field in form views or some kanban views.")
image_small = fields.Binary(string="Small-sized image",
compute='_compute_images', inverse='_inverse_image_small', store=True, attachment=True,
image_small = fields.Binary(string="Small-sized image", attachment=True,
help="Small-sized image of the category. It is automatically "
"resized as a 64x64px image, with aspect ratio preserved. "
"Use this field anywhere a small image is required.")
@api.depends('image')
def _compute_images(self):
for rec in self:
rec.image_medium = tools.image_resize_image_medium(rec.image)
rec.image_small = tools.image_resize_image_small(rec.image)
@api.model
def create(self, vals):
tools.image_resize_images(vals)
return super(PosCategory, self).create(vals)
def _inverse_image_medium(self):
for rec in self:
rec.image = tools.image_resize_image_big(rec.image_medium)
def _inverse_image_small(self):
for rec in self:
rec.image = tools.image_resize_image_big(rec.image_small)
@api.multi
def write(self, vals):
tools.image_resize_images(vals)
return super(PosCategory, self).write(vals)
@api.multi
def name_get(self):
+4 -18
View File
@@ -537,31 +537,15 @@ class product_template(osv.osv):
# image: all image fields are base64 encoded and PIL-supported
image = openerp.fields.Binary("Image", attachment=True,
help="This field holds the image used as image for the product, limited to 1024x1024px.")
image_medium = openerp.fields.Binary("Medium-sized image",
compute='_compute_images', inverse='_inverse_image_medium', store=True, attachment=True,
image_medium = openerp.fields.Binary("Medium-sized image", attachment=True,
help="Medium-sized image of the product. It is automatically "\
"resized as a 128x128px image, with aspect ratio preserved, "\
"only when the image exceeds one of those sizes. Use this field in form views or some kanban views.")
image_small = openerp.fields.Binary("Small-sized image",
compute='_compute_images', inverse='_inverse_image_small', store=True, attachment=True,
image_small = openerp.fields.Binary("Small-sized image", attachment=True,
help="Small-sized image of the product. It is automatically "\
"resized as a 64x64px image, with aspect ratio preserved. "\
"Use this field anywhere a small image is required.")
@api.depends('image')
def _compute_images(self):
for rec in self:
rec.image_medium = tools.image_resize_image_medium(rec.image, avoid_if_small=True)
rec.image_small = tools.image_resize_image_small(rec.image)
def _inverse_image_medium(self):
for rec in self:
rec.image = tools.image_resize_image_big(rec.image_medium)
def _inverse_image_small(self):
for rec in self:
rec.image = tools.image_resize_image_big(rec.image_small)
def _price_get(self, cr, uid, products, ptype='list_price', context=None):
if context is None:
context = {}
@@ -687,6 +671,7 @@ class product_template(osv.osv):
def create(self, cr, uid, vals, context=None):
''' Store the initial standard price in order to be able to retrieve the cost of a product template for a given date'''
tools.image_resize_images(vals)
product_template_id = super(product_template, self).create(cr, uid, vals, context=context)
if not context or "create_product_product" not in context:
self.create_variant_ids(cr, uid, [product_template_id], context=context)
@@ -710,6 +695,7 @@ class product_template(osv.osv):
return product_template_id
def write(self, cr, uid, ids, vals, context=None):
tools.image_resize_images(vals)
res = super(product_template, self).write(cr, uid, ids, vals, context=context)
if 'attribute_line_ids' in vals or vals.get('active'):
self.create_variant_ids(cr, uid, ids, context=context)
+7 -4
View File
@@ -348,14 +348,17 @@ class PurchaseOrder(models.Model):
# this product. We limit to 10 the number of suppliers for a product to avoid the mess that
# could be caused for some generic products ("Miscellaneous").
for line in self.order_line:
if self.partner_id not in line.product_id.seller_ids.mapped('name') and len(line.product_id.seller_ids) <= 10:
# Do not add a contact as a supplier
partner = self.partner_id if not self.partner_id.parent_id else self.partner_id.parent_id
if partner not in line.product_id.seller_ids.mapped('name') and len(line.product_id.seller_ids) <= 10:
currency = partner.property_purchase_currency_id or self.env.user.company_id.currency_id
supplierinfo = {
'name': self.partner_id.id,
'name': partner.id,
'sequence': max(line.product_id.seller_ids.mapped('sequence')) + 1 if line.product_id.seller_ids else 1,
'product_uom': line.product_uom.id,
'min_qty': 0.0,
'price': line.price_unit,
'currency_id': self.partner_id.currency_id.id,
'price': self.currency_id.compute(line.price_unit, currency),
'currency_id': currency.id,
'delay': 0,
}
vals = {
+8 -6
View File
@@ -15,13 +15,15 @@ class CrmTeam(models.Model):
def _get_default_team_id(self, user_id=None):
if not user_id:
user_id = self.env.uid
team_id = self.env['crm.team'].search([
'|',
('user_id', '=', user_id),
('member_ids', 'in', [user_id])],
limit=1) or self.env.ref('sales_team.team_sales_department', raise_if_not_found=False)
if not team_id and self.env.context.get('default_team_id'):
team_id = self.env['crm.team'].search(
['|', ('user_id', '=', user_id), ('member_ids', 'in', [user_id])],
limit=1)
if not team_id and 'default_team_id' in self.env.context:
team_id = self.env['crm.team'].browse(self.env.context.get('default_team_id'))
if not team_id and 'default_team_id' not in self.env.context:
default_team_id = self.env.ref('sales_team.team_sales_department', raise_if_not_found=False)
if default_team_id and (self.env.context.get('default_type') != 'lead' or default_team_id.use_leads):
team_id = default_team_id
return team_id
name = fields.Char('Sales Team', required=True, translate=True)
+2 -4
View File
@@ -336,9 +336,8 @@ var PropertiesMixin = _.extend({}, EventDispatcherMixin, {
// remove this, or move it elsewhere. Also, learn OO programming.
if (key === 'value' && self.field && self.field.type === 'float' && tmp && val){
var digits = self.field.digits;
if (digits !== 0){
digits = digits ? digits[1] : 2;
if (utils.float_is_zero(tmp - val, digits)) {
if (_.isArray(digits)) {
if (utils.float_is_zero(tmp - val, digits[1])) {
return;
}
}
@@ -366,4 +365,3 @@ return {
};
});
+1 -1
View File
@@ -1155,7 +1155,7 @@ ListView.List = Class.extend( /** @lends instance.web.ListView.List# */{
record.set(column.id, names[0]);
});
}
} else if (column.type === 'many2many' || column.type === 'one2many') {
} else if (column.type === 'many2many') {
value = record.get(column.id);
// non-resolved (string) m2m values are arrays
if (value instanceof Array && !_.isEmpty(value)
@@ -86,6 +86,9 @@ var CalendarView = View.extend({
this.title = (this.options.action)? this.options.action.name : '';
this.shown = $.Deferred();
self.current_start = null;
self.current_end = null;
self.previous_ids = [];
},
set_default_options: function(options) {
@@ -729,11 +732,25 @@ var CalendarView = View.extend({
);
}
}
// read_slice is launched uncoditionally, when quickly
// changing the range in the calender view, all of
// these RPC calls will race each other. Because of
// this we keep track of the current range of the
// calendar view.
self.current_start = start;
self.current_end = end;
self.dataset.read_slice(_.keys(self.fields), {
offset: 0,
domain: event_domain,
context: context,
}).done(function(events) {
// undo the read_slice if it the range has changed since it launched
if (self.current_start.getTime() != start.getTime() || self.current_end.getTime() != end.getTime()) {
self.dataset.ids = self.previous_ids;
return;
}
self.previous_ids = self.dataset.ids.slice();
if (self.dataset.index === null) {
if (events.length) {
self.dataset.index = 0;
+10 -16
View File
@@ -60,30 +60,24 @@ class product_public_category(osv.osv):
# In this case, the default image is set by the js code.
image = openerp.fields.Binary("Image", attachment=True,
help="This field holds the image used as image for the category, limited to 1024x1024px.")
image_medium = openerp.fields.Binary("Medium-sized image",
compute='_compute_images', inverse='_inverse_image_medium', store=True, attachment=True,
image_medium = openerp.fields.Binary("Medium-sized image", attachment=True,
help="Medium-sized image of the category. It is automatically "\
"resized as a 128x128px image, with aspect ratio preserved. "\
"Use this field in form views or some kanban views.")
image_small = openerp.fields.Binary("Small-sized image",
compute='_compute_images', inverse='_inverse_image_small', store=True, attachment=True,
image_small = openerp.fields.Binary("Small-sized image", attachment=True,
help="Small-sized image of the category. It is automatically "\
"resized as a 64x64px image, with aspect ratio preserved. "\
"Use this field anywhere a small image is required.")
@openerp.api.depends('image')
def _compute_images(self):
for rec in self:
rec.image_medium = tools.image_resize_image_medium(rec.image)
rec.image_small = tools.image_resize_image_small(rec.image)
@openerp.api.model
def create(self, vals):
tools.image_resize_images(vals)
return super(product_public_category, self).create(vals)
def _inverse_image_medium(self):
for rec in self:
rec.image = tools.image_resize_image_big(rec.image_medium)
def _inverse_image_small(self):
for rec in self:
rec.image = tools.image_resize_image_big(rec.image_small)
@openerp.api.multi
def write(self, vals):
tools.image_resize_images(vals)
return super(product_public_category, self).write(vals)
class product_template(osv.Model):
_inherit = ["product.template", "website.seo.metadata", 'website.published.mixin', 'rating.mixin']
+20 -8
View File
@@ -12,7 +12,7 @@ from openerp import SUPERUSER_ID, tools
from openerp.exceptions import AccessError
from openerp.osv import fields,osv
from openerp.tools.translate import _
from openerp.tools.misc import ustr
from openerp.tools.misc import ustr, html_escape
from openerp.tools.mimetypes import guess_mimetype
_logger = logging.getLogger(__name__)
@@ -199,14 +199,26 @@ class ir_attachment(osv.osv):
:param values : dict of values to create or write an ir_attachment
:return mime : string indicating the mimetype, or application/octet-stream by default
"""
mimetype = 'application/octet-stream'
if values.get('datas_fname'):
mimetype = None
if values.get('mimetype'):
mimetype = values['mimetype']
if not mimetype and values.get('datas_fname'):
mimetype = mimetypes.guess_type(values['datas_fname'])[0]
if values.get('url'):
if not mimetype and values.get('url'):
mimetype = mimetypes.guess_type(values['url'])[0]
if values.get('datas') and (not mimetype or mimetype == 'application/octet-stream'):
mimetype = guess_mimetype(values['datas'].decode('base64'))
return mimetype
return mimetype or 'application/octet-stream'
def _check_contents(self, cr, uid, values, context=None):
mimetype = values['mimetype'] = self._compute_mimetype(values)
needs_escape = 'htm' in mimetype or '/ht' in mimetype # hta, html, xhtml, etc.
if needs_escape and not self.pool['res.users']._is_admin(cr, uid, [uid]):
if 'datas' in values:
values['datas'] = html_escape(values['datas'].decode('base64')).encode('base64')
else:
values['mimetype'] = 'text/plain'
return values
def _index(self, cr, uid, bin_data, datas_fname, file_type):
""" compute the index content of the given filename, or binary data.
@@ -382,6 +394,8 @@ class ir_attachment(osv.osv):
# remove computed field depending of datas
for field in ['file_size', 'checksum']:
vals.pop(field, False)
if 'mimetype' in vals or 'datas' in vals:
vals = self._check_contents(cr, uid, vals, context=context)
return super(ir_attachment, self).write(cr, uid, ids, vals, context)
def copy(self, cr, uid, id, default=None, context=None):
@@ -409,9 +423,7 @@ class ir_attachment(osv.osv):
# remove computed field depending of datas
for field in ['file_size', 'checksum']:
values.pop(field, False)
# if mimetype not given, compute it !
if 'mimetype' not in values:
values['mimetype'] = self._compute_mimetype(values)
values = self._check_contents(cr, uid, values, context=context)
self.check(cr, uid, [], mode='write', context=context, values=values)
return super(ir_attachment, self).create(cr, uid, values, context)
+6 -18
View File
@@ -198,13 +198,11 @@ class Partner(models.Model, FormatAddress):
# image: all image fields are base64 encoded and PIL-supported
image = fields.Binary("Image", attachment=True,
help="This field holds the image used as avatar for this contact, limited to 1024x1024px",)
image_medium = fields.Binary("Medium-sized image",
compute='_compute_images', inverse='_inverse_image_medium', store=True, attachment=True,
image_medium = fields.Binary("Medium-sized image", attachment=True,
help="Medium-sized image of this contact. It is automatically "\
"resized as a 128x128px image, with aspect ratio preserved. "\
"Use this field in form views or some kanban views.")
image_small = fields.Binary("Small-sized image",
compute='_compute_images', inverse='_inverse_image_small', store=True, attachment=True,
image_small = fields.Binary("Small-sized image", attachment=True,
help="Small-sized image of this contact. It is automatically "\
"resized as a 64x64px image, with aspect ratio preserved. "\
"Use this field anywhere a small image is required.")
@@ -238,20 +236,6 @@ class Partner(models.Model, FormatAddress):
else:
partner.commercial_partner_id = partner.parent_id.commercial_partner_id
@api.depends('image')
def _compute_images(self):
for rec in self:
rec.image_medium = tools.image_resize_image_medium(rec.image)
rec.image_small = tools.image_resize_image_small(rec.image)
def _inverse_image_medium(self):
for rec in self:
rec.image = tools.image_resize_image_big(rec.image_medium)
def _inverse_image_small(self):
for rec in self:
rec.image = tools.image_resize_image_big(rec.image_small)
@api.model
def _get_default_image(self, partner_type, is_company, parent_id):
if getattr(threading.currentThread(), 'testing', False) or self._context.get('install_mode'):
@@ -484,10 +468,13 @@ class Partner(models.Model, FormatAddress):
companies = set(user.company_id for user in partner.user_ids)
if len(companies) > 1 or company not in companies:
raise UserError(_("You can not change the company as the partner/user has multiple user linked with different companies."))
tools.image_resize_images(vals)
result = super(Partner, self).write(vals)
for partner in self:
partner._fields_sync(vals)
if any(u.has_group('base.group_user') for u in partner.user_ids):
self.env['res.users'].check_access_rights('write')
return result
@api.model
@@ -501,6 +488,7 @@ class Partner(models.Model, FormatAddress):
partner = super(Partner, self).create(vals)
partner._fields_sync(vals)
partner._handle_first_contact_creation()
tools.image_resize_images(vals)
return partner
@api.multi
+3 -3
View File
@@ -174,7 +174,7 @@ class Users(models.Model):
__uid_cache = defaultdict(dict) # {dbname: {uid: password}}
# User can write on a few of his own fields (but not his groups for example)
SELF_WRITEABLE_FIELDS = ['password', 'signature', 'action_id', 'company_id', 'email', 'name', 'image', 'image_medium', 'image_small', 'lang', 'tz']
SELF_WRITEABLE_FIELDS = ['signature', 'action_id', 'company_id', 'email', 'name', 'image', 'image_medium', 'image_small', 'lang', 'tz']
# User can read a few of his own fields
SELF_READABLE_FIELDS = ['signature', 'company_id', 'login', 'email', 'name', 'image', 'image_medium', 'image_small', 'lang', 'tz', 'tz_offset', 'groups_id', 'partner_id', '__last_update', 'action_id']
@@ -510,8 +510,8 @@ class Users(models.Model):
"""
self.check(self._cr.dbname, self._uid, old_passwd)
if new_passwd:
# do not use self.env.user here, since it has uid=SUPERUSER_ID
return self.browse(self._uid).write({'password': new_passwd})
# use self.env.user here, because it has uid=SUPERUSER_ID
return self.env.user.write({'password': new_passwd})
raise UserError(_("Setting empty passwords is not allowed for security reasons!"))
@api.multi
+4 -1
View File
@@ -418,7 +418,10 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
t0 = time.time()
t0_sql = openerp.sql_db.sql_counter
if openerp.tools.config['test_enable']:
cr.execute("SELECT name FROM ir_module_module WHERE state='installed'")
if update_module:
cr.execute("SELECT name FROM ir_module_module WHERE state='installed' and name = ANY(%s)", (processed_modules,))
else:
cr.execute("SELECT name FROM ir_module_module WHERE state='installed'")
for module_name in cr.fetchall():
report.record_result(openerp.modules.module.run_unit_tests(module_name[0], cr.dbname, position=runs_post_install))
_logger.log(25, "All post-tested in %.2fs, %s queries", time.time() - t0, openerp.sql_db.sql_counter - t0_sql)
+18
View File
@@ -256,6 +256,24 @@ def image_get_resized_images(base64_source, return_big=False, return_medium=True
return_dict[small_name] = image_resize_image_small(base64_source, avoid_if_small=avoid_resize_small)
return return_dict
def image_resize_images(vals, big_name='image', medium_name='image_medium', small_name='image_small'):
""" Update ``vals`` with image fields resized as expected. """
if big_name in vals:
vals.update(image_get_resized_images(vals[big_name],
return_big=True, return_medium=True, return_small=True,
big_name=big_name, medium_name=medium_name, small_name=small_name,
avoid_resize_big=True, avoid_resize_medium=False, avoid_resize_small=False))
elif medium_name in vals:
vals.update(image_get_resized_images(vals[medium_name],
return_big=True, return_medium=True, return_small=True,
big_name=big_name, medium_name=medium_name, small_name=small_name,
avoid_resize_big=True, avoid_resize_medium=True, avoid_resize_small=False))
elif small_name in vals:
vals.update(image_get_resized_images(vals[small_name],
return_big=True, return_medium=True, return_small=True,
big_name=big_name, medium_name=medium_name, small_name=small_name,
avoid_resize_big=True, avoid_resize_medium=True, avoid_resize_small=True))
if __name__=="__main__":
import sys