diff --git a/addons/account_analytic_default/models/account_analytic_default.py b/addons/account_analytic_default/models/account_analytic_default.py index 5f07ae08878..85ec2199f0f 100644 --- a/addons/account_analytic_default/models/account_analytic_default.py +++ b/addons/account_analytic_default/models/account_analytic_default.py @@ -63,3 +63,9 @@ class AccountInvoiceLine(models.Model): fields.Date.today(), company_id=self.company_id.id) self.account_analytic_id = rec.analytic_id.id return res + + def _set_additional_fields(self, invoice): + rec = self.env['account.analytic.default'].account_get(self.product_id.id, self.invoice_id.partner_id.id, self.env.uid, + fields.Date.today(), company_id=self.company_id.id) + self.account_analytic_id = rec.analytic_id.id + super(AccountInvoiceLine, self)._set_additional_fields(invoice) diff --git a/addons/hr/views/hr_views.xml b/addons/hr/views/hr_views.xml index b2a0c159510..7831105b82f 100644 --- a/addons/hr/views/hr_views.xml +++ b/addons/hr/views/hr_views.xml @@ -38,8 +38,8 @@
-
-
diff --git a/addons/membership/membership.py b/addons/membership/membership.py index e969fde2013..2698fcfb826 100644 --- a/addons/membership/membership.py +++ b/addons/membership/membership.py @@ -402,6 +402,15 @@ class Product(osv.osv): class Invoice(osv.osv): _inherit = 'account.invoice' + def action_cancel_draft(self, cr, uid, ids, context=None): + member_line_obj = self.pool.get('membership.membership_line') + for invoice in self.browse(cr, uid, ids, context=context): + mlines = member_line_obj.search(cr, uid, + [('account_invoice_line', 'in', + [l.id for l in invoice.invoice_line])]) + member_line_obj.write(cr, uid, mlines, {'date_cancel': False}, context=context) + return super(Invoice, self).action_cancel_draft(cr, uid, ids, context=context) + def action_cancel(self, cr, uid, ids, context=None): '''Create a 'date_cancel' on the membership_line object''' member_line_obj = self.pool.get('membership.membership_line') diff --git a/addons/product/pricelist.py b/addons/product/pricelist.py index 815b64de624..7047cebb1f6 100644 --- a/addons/product/pricelist.py +++ b/addons/product/pricelist.py @@ -285,6 +285,13 @@ class product_pricelist_item(osv.osv): return False return True + def _get_product_pricelist(self, cr, uid, ids, context=None): + result = set() + for pricelist in self.pool['product.pricelist'].browse(cr, uid, ids, context=context): + for item in pricelist.item_ids: + result.add(item.id) + return list(result) + _columns = { 'product_tmpl_id': fields.many2one('product.template', 'Product Template', ondelete='cascade', help="Specify a template if this rule only applies to one product template. Keep empty otherwise."), 'product_id': fields.many2one('product.product', 'Product', ondelete='cascade', help="Specify a product if this rule only applies to one product. Keep empty otherwise."), @@ -315,9 +322,13 @@ class product_pricelist_item(osv.osv): 'price_max_margin': fields.float('Max. Price Margin', digits_compute= dp.get_precision('Product Price'), help='Specify the maximum amount of margin over the base price.'), 'company_id': fields.related('pricelist_id','company_id',type='many2one', - readonly=True, relation='res.company', string='Company', store=True), + readonly=True, relation='res.company', string='Company', store={ + 'product.pricelist': (_get_product_pricelist, ['company_id'], 30), + }), 'currency_id': fields.related('pricelist_id', 'currency_id', type='many2one', - readonly=True, relation='res.currency', string='Currency', store=True), + readonly=True, relation='res.currency', string='Currency', store={ + 'product.pricelist': (_get_product_pricelist, ['currency_id'], 30), + }), 'date_start': fields.date('Start Date', help="Starting date for the pricelist item validation"), 'date_end': fields.date('End Date', help="Ending valid for the pricelist item validation"), 'compute_price': fields.selection([('fixed', 'Fix Price'), ('percentage', 'Percentage (discount)'), ('formula', 'Formula')], select=True, default='fixed'), diff --git a/addons/purchase/invoice.py b/addons/purchase/invoice.py index 49cc77ec0c8..bc157db833e 100644 --- a/addons/purchase/invoice.py +++ b/addons/purchase/invoice.py @@ -156,6 +156,7 @@ class AccountInvoice(models.Model): valuation_price_unit_total += val_stock_move.price_unit * val_stock_move.product_qty valuation_total_qty += val_stock_move.product_qty valuation_price_unit = valuation_price_unit_total / valuation_total_qty + valuation_price_unit = self.env['product.uom']._compute_price(i_line.product_id.uom_id.id, valuation_price_unit, i_line.uom_id.id) if inv.currency_id.id != company_currency.id: valuation_price_unit = company_currency.with_context(date=inv.date_invoice).compute(valuation_price_unit, inv.currency_id) if valuation_price_unit != i_line.price_unit and line['price_unit'] == i_line.price_unit and acc: diff --git a/addons/web/static/src/js/framework/formats.js b/addons/web/static/src/js/framework/formats.js index 8a5a8ffedb7..90cecd5398d 100644 --- a/addons/web/static/src/js/framework/formats.js +++ b/addons/web/static/src/js/framework/formats.js @@ -164,16 +164,24 @@ function parse_value (value, descriptor, value_if_empty) { if (datetime.isValid()) return time.datetime_to_str(datetime.toDate()); datetime = moment(value, [date_pattern + ' ' + time_pattern, date_pattern_wo_zero + ' ' + time_pattern_wo_zero, moment.ISO_8601]); - if (datetime.isValid()) + if (datetime.isValid()) { + if (datetime.year() === 0) { + datetime.year(moment.utc().year()); + } return time.datetime_to_str(datetime.toDate()); + } throw new Error(_.str.sprintf(_t("'%s' is not a correct datetime"), value)); case 'date': var date = moment(value, [date_pattern, date_pattern_wo_zero, moment.ISO_8601], true); if (date.isValid()) return time.date_to_str(date.toDate()); date = moment(value, [date_pattern, date_pattern_wo_zero, moment.ISO_8601]); - if (date.isValid()) + if (date.isValid()) { + if (date.year() === 0) { + date.year(moment.utc().year()); + } return time.date_to_str(date.toDate()); + } throw new Error(_.str.sprintf(_t("'%s' is not a correct date"), value)); case 'time': var _time = moment(value, [time_pattern, time_pattern_wo_zero, moment.ISO_8601], true); diff --git a/addons/web/static/src/js/framework/translation.js b/addons/web/static/src/js/framework/translation.js index 69743e9787d..f01bb246693 100644 --- a/addons/web/static/src/js/framework/translation.js +++ b/addons/web/static/src/js/framework/translation.js @@ -31,9 +31,7 @@ var TranslationDataBase = Class.extend(/** @lends instance.TranslationDataBase# }); if (translation_bundle.lang_parameters) { this.parameters = translation_bundle.lang_parameters; - if (typeof(py) !== "undefined") { - this.parameters.grouping = py.eval(this.parameters.grouping); - } + this.parameters.grouping = JSON.parse(this.parameters.grouping); } }, add_module_translation: function(mod) { diff --git a/addons/website/models/res_config.py b/addons/website/models/res_config.py index acd63957141..9a55a3bcd8d 100644 --- a/addons/website/models/res_config.py +++ b/addons/website/models/res_config.py @@ -10,7 +10,7 @@ class website_config_settings(osv.osv_memory): 'website_name': fields.related('website_id', 'name', type="char", string="Website Name"), 'language_ids': fields.related('website_id', 'language_ids', type='many2many', relation='res.lang', string='Languages'), - 'default_lang_id': fields.related('website_id', 'default_lang_id', type='many2one', relation='res.lang', string='Default language'), + 'default_lang_id': fields.related('website_id', 'default_lang_id', type='many2one', relation='res.lang', string='Default language', required=True), 'default_lang_code': fields.related('website_id', 'default_lang_code', type="char", string="Default language code"), 'google_analytics_key': fields.related('website_id', 'google_analytics_key', type="char", string='Google Analytics Key'), diff --git a/addons/website/models/website.py b/addons/website/models/website.py index 8d2177b2d2b..e74a56b2f7b 100644 --- a/addons/website/models/website.py +++ b/addons/website/models/website.py @@ -165,7 +165,7 @@ class website(osv.osv): 'domain': fields.char('Website Domain'), 'company_id': fields.many2one('res.company', string="Company"), 'language_ids': fields.many2many('res.lang', 'website_lang_rel', 'website_id', 'lang_id', 'Languages'), - 'default_lang_id': fields.many2one('res.lang', string="Default language"), + 'default_lang_id': fields.many2one('res.lang', string="Default language", required=True), 'default_lang_code': fields.related('default_lang_id', 'code', type="char", string="Default language code", store=True), 'social_twitter': fields.char('Twitter Account'), 'social_facebook': fields.char('Facebook Account'), diff --git a/addons/website_hr/views/hr_employee_views.xml b/addons/website_hr/views/hr_employee_views.xml index 258a611d6cf..8f32d0eb30b 100644 --- a/addons/website_hr/views/hr_employee_views.xml +++ b/addons/website_hr/views/hr_employee_views.xml @@ -8,7 +8,7 @@
diff --git a/addons/website_portal/views/templates.xml b/addons/website_portal/views/templates.xml index 6f52b9a8aac..592bf9a4f63 100644 --- a/addons/website_portal/views/templates.xml +++ b/addons/website_portal/views/templates.xml @@ -73,11 +73,11 @@
- +
- +
diff --git a/addons/website_sale/static/src/js/website_sale.js b/addons/website_sale/static/src/js/website_sale.js index cc6a57e2796..aaca350d82f 100644 --- a/addons/website_sale/static/src/js/website_sale.js +++ b/addons/website_sale/static/src/js/website_sale.js @@ -53,6 +53,7 @@ odoo.define('website_sale.website_sale', function (require) { var ajax = require('web.ajax'); var core = require('web.core'); +var utils = require('web.utils'); var _t = core._t; var base = require('web_editor.base'); @@ -250,9 +251,15 @@ $('.oe_website_sale').each(function () { }); function price_to_str(price) { - price = Math.round(price * 100) / 100; - var dec = Math.round((price % 1) * 100); - return price + (dec ? '' : '.0') + (dec%10 ? '' : '0'); + var l10n = _t.database.parameters; + var precision = 2; + + if ($(".decimal_precision").length) { + precision = parseInt($(".decimal_precision").first().data('precision')); + } + var formatted = _.str.sprintf('%.' + precision + 'f', price).split('.'); + formatted[0] = utils.insert_thousand_seps(formatted[0]); + return formatted.join(l10n.decimal_point); } $(oe_website_sale).on('change', 'input.js_product_change', function () { diff --git a/addons/website_sale/views/templates.xml b/addons/website_sale/views/templates.xml index 89e19c05cb8..534183846ff 100644 --- a/addons/website_sale/views/templates.xml +++ b/addons/website_sale/views/templates.xml @@ -439,7 +439,7 @@ -

+

- +

@@ -990,7 +990,7 @@
- +
diff --git a/doc/cla/corporate/diagram-software.md b/doc/cla/corporate/diagram-software.md new file mode 100644 index 00000000000..93dd9623a62 --- /dev/null +++ b/doc/cla/corporate/diagram-software.md @@ -0,0 +1,20 @@ +Spain, 2016-11-21 + +Diagram Software, S.L. 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, + +Jose Zambudio jose.zambudio@diagram.es https://github.com/zamberjo + +List of contributors: + +Cristian Moncho cristian.moncho@diagram.es https://github.com/crimoniv +Jose Zambudio jose.zambudio@diagram.es https://github.com/zamberjo +Almudena de la Puente almudena.delapuente@diagram.es https://github.com/almumu +Mauro Cebriá mauro.cebria@diagram.es https://github.com/maurochip +Pedro Albujer pedro.albujer.rico@diagram.es https://github.com/P4R +Rubén Cerdà ruben.cerda.roig@diagram.es https://github.com/rubencr7 diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py index 3b12ac011f8..cb81c607423 100644 --- a/openerp/addons/base/res/res_partner.py +++ b/openerp/addons/base/res/res_partner.py @@ -10,7 +10,7 @@ import urllib2 import urlparse from lxml import etree -from odoo import api, fields, models, tools, _ +from odoo import api, fields, models, tools, SUPERUSER_ID, _ from odoo.modules import get_module_resource from odoo.osv.expression import get_unaccent_wrapper from odoo.exceptions import UserError, ValidationError @@ -478,8 +478,12 @@ class Partner(models.Model, FormatAddress): 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) + result = True + # To write in SUPERUSER on field is_company and avoid access rights problems. + if 'is_company' in vals and self.user_has_groups('base.group_partner_manager') and not self.env.uid == SUPERUSER_ID: + result = super(Partner, self).sudo().write({'is_company': vals.get('is_company')}) + del vals['is_company'] + result = result and super(Partner, self).write(vals) for partner in self: if any(u.has_group('base.group_user') for u in partner.user_ids if u != self.env.user): self.env['res.users'].check_access_rights('write') diff --git a/openerp/tools/misc.py b/openerp/tools/misc.py index 18f9dc18205..e5211f56c09 100644 --- a/openerp/tools/misc.py +++ b/openerp/tools/misc.py @@ -1126,6 +1126,8 @@ def formatLang(env, value, digits=None, grouping=True, monetary=False, dp=False, if dp: decimal_precision_obj = env['decimal.precision'] digits = decimal_precision_obj.precision_get(dp) + elif currency_obj: + digits = currency_obj.decimal_places elif (hasattr(value, '_field') and isinstance(value._field, (float_field, function_field)) and value._field.digits): digits = value._field.digits[1] if not digits and digits is not 0: