diff options
| author | Christophe Simonis <chs@odoo.com> | 2014-10-21 14:59:56 +0200 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2014-10-21 14:59:56 +0200 |
| commit | a42167d085e8c4989412c39ec4e21685ebd93cd2 (patch) | |
| tree | fc8cf942fe689de94aec631d5b8d7365693de5d0 /addons | |
| parent | d822766296fed8f72d3168c675d4cf0b89e73f0c (diff) | |
| parent | 262eb662de489d98b76dece7305b594399161014 (diff) | |
[MERGE] forward port of branch 8.0 up to 262eb66
Diffstat (limited to 'addons')
24 files changed, 148 insertions, 83 deletions
diff --git a/addons/account/account_cash_statement.py b/addons/account/account_cash_statement.py index d4c98b7c275..5b1952f44d9 100644 --- a/addons/account/account_cash_statement.py +++ b/addons/account/account_cash_statement.py @@ -23,6 +23,7 @@ import time from openerp.osv import fields, osv +from openerp.tools import float_compare from openerp.tools.translate import _ import openerp.addons.decimal_precision as dp @@ -80,7 +81,8 @@ class account_cash_statement(osv.osv): if (statement.journal_id.type not in ('cash',)): continue if not statement.journal_id.cash_control: - if statement.balance_end_real <> statement.balance_end: + prec = self.pool['decimal.precision'].precision_get(cr, uid, 'Account') + if float_compare(statement.balance_end_real, statement.balance_end, precision_digits=prec): statement.write({'balance_end_real' : statement.balance_end}) continue start = end = 0 diff --git a/addons/account/res_config.py b/addons/account/res_config.py index 4e870b78dfd..c69eeb9646e 100644 --- a/addons/account/res_config.py +++ b/addons/account/res_config.py @@ -241,8 +241,8 @@ class account_config_settings(osv.osv_memory): }) # update taxes ir_values = self.pool.get('ir.values') - taxes_id = ir_values.get_default(cr, uid, 'product.product', 'taxes_id', company_id=company_id) - supplier_taxes_id = ir_values.get_default(cr, uid, 'product.product', 'supplier_taxes_id', company_id=company_id) + taxes_id = ir_values.get_default(cr, uid, 'product.template', 'taxes_id', company_id=company_id) + supplier_taxes_id = ir_values.get_default(cr, uid, 'product.template', 'supplier_taxes_id', company_id=company_id) values.update({ 'default_sale_tax': isinstance(taxes_id, list) and taxes_id[0] or taxes_id, 'default_purchase_tax': isinstance(supplier_taxes_id, list) and supplier_taxes_id[0] or supplier_taxes_id, @@ -311,9 +311,9 @@ class account_config_settings(osv.osv_memory): raise openerp.exceptions.AccessError(_("Only administrators can change the settings")) ir_values = self.pool.get('ir.values') config = self.browse(cr, uid, ids[0], context) - ir_values.set_default(cr, SUPERUSER_ID, 'product.product', 'taxes_id', + ir_values.set_default(cr, SUPERUSER_ID, 'product.template', 'taxes_id', config.default_sale_tax and [config.default_sale_tax.id] or False, company_id=config.company_id.id) - ir_values.set_default(cr, SUPERUSER_ID, 'product.product', 'supplier_taxes_id', + ir_values.set_default(cr, SUPERUSER_ID, 'product.template', 'supplier_taxes_id', config.default_purchase_tax and [config.default_purchase_tax.id] or False, company_id=config.company_id.id) def set_chart_of_accounts(self, cr, uid, ids, context=None): diff --git a/addons/account/static/src/js/account_widgets.js b/addons/account/static/src/js/account_widgets.js index 158805fe55f..04189e36d7f 100644 --- a/addons/account/static/src/js/account_widgets.js +++ b/addons/account/static/src/js/account_widgets.js @@ -41,6 +41,7 @@ openerp.account = function (instance) { this.max_move_lines_displayed = 5; this.animation_speed = 100; // "Blocking" animations this.aestetic_animation_speed = 300; // eye candy + this.map_currency_id_rounding = {}; this.map_tax_id_amount = {}; this.presets = {}; // We'll need to get the code of an account selected in a many2one (whose value is the id) @@ -199,6 +200,13 @@ openerp.account = function (instance) { _.each(data, function(o) { self.map_account_id_code[o.id] = o.code }); }); + // Create a dict currency id -> rounding factor + new instance.web.Model("res.currency") + .query(['id', 'rounding']) + .all().then(function(data) { + _.each(data, function(o) { self.map_currency_id_rounding[o.id] = o.rounding }); + }); + // Create a dict tax id -> amount new instance.web.Model("account.tax") .query(['id', 'amount']) @@ -347,10 +355,12 @@ openerp.account = function (instance) { self.$(".reconciliation_lines_container").fadeIn(self.aestetic_animation_speed); }); }); - } - // Congratulate the user if the work is done - if (self.reconciled_lines === self.st_lines.length) { + } else if (self.reconciled_lines === self.st_lines.length) { + // Congratulate the user if the work is done self.displayDoneMessage(); + } else { + // Some lines weren't persisted because they were't valid + self.$(".reconciliation_lines_container").fadeIn(self.aestetic_animation_speed); } }).fail(function() { self.$(".reconciliation_lines_container").fadeIn(self.aestetic_animation_speed); @@ -386,7 +396,7 @@ openerp.account = function (instance) { // Update children if needed _.each(self.getChildren(), function(child){ - if (child.partner_id === partner_id && child !== source_child) { + if ((child.partner_id === partner_id || child.st_line.has_no_partner) && child !== source_child) { if (contains_lines(child.get("mv_lines_selected"), line_ids)) { child.set("mv_lines_selected", _.filter(child.get("mv_lines_selected"), function(o){ return line_ids.indexOf(o.id) === -1 })); } else if (contains_lines(child.mv_lines_deselected, line_ids)) { @@ -412,6 +422,8 @@ openerp.account = function (instance) { _.each(self.getChildren(), function(child){ if (child.partner_id === partner_id && child !== source_child && (child.get("mode") === "match" || child.$el.hasClass("no_match"))) child.updateMatches(); + if (child.st_line.has_no_partner && child.get("mode") === "match" || child.$el.hasClass("no_match")) + child.updateMatches(); }); }, @@ -639,12 +651,13 @@ openerp.account = function (instance) { this.model_bank_statement_line = new instance.web.Model("account.bank.statement.line"); this.model_res_users = new instance.web.Model("res.users"); this.model_tax = new instance.web.Model("account.tax"); + this.map_currency_id_rounding = this.getParent().map_currency_id_rounding; this.map_account_id_code = this.getParent().map_account_id_code; this.map_tax_id_amount = this.getParent().map_tax_id_amount; this.presets = this.getParent().presets; this.is_valid = true; this.is_consistent = true; // Used to prevent bad server requests - this.total_move_lines_num = undefined; // Used for pagers + this.can_fetch_more_move_lines; // Tell if we can show more move lines this.filter = ""; // In rare cases like when deleting a statement line's partner we don't want the server to // look for a reconciliation proposition (in this particular case it might find a move line @@ -1039,16 +1052,15 @@ openerp.account = function (instance) { pagerControlLeftHandler: function() { var self = this; if (self.$(".pager_control_left").hasClass("disabled")) { return; /* shouldn't happen, anyway*/ } - if (self.total_move_lines_num < 0) { return; } + if (self.get("pager_index") === 0) { return; } self.set("pager_index", self.get("pager_index")-1 ); }, pagerControlRightHandler: function() { var self = this; - var new_index = self.get("pager_index")+1; if (self.$(".pager_control_right").hasClass("disabled")) { return; /* shouldn't happen, anyway*/ } - if ((new_index * self.max_move_lines_displayed) >= self.total_move_lines_num) { return; } - self.set("pager_index", new_index ); + if (! self.can_fetch_more_move_lines) { return; } + self.set("pager_index", self.get("pager_index")+1 ); }, filterHandler: function() { @@ -1222,7 +1234,7 @@ openerp.account = function (instance) { self.$(".pager_control_left").addClass("disabled"); else self.$(".pager_control_left").removeClass("disabled"); - if (self.total_move_lines_num <= ((self.get("pager_index")+1) * self.max_move_lines_displayed)) + if (! self.can_fetch_more_move_lines) self.$(".pager_control_right").addClass("disabled"); else self.$(".pager_control_right").removeClass("disabled"); @@ -1323,12 +1335,12 @@ openerp.account = function (instance) { mvLinesChanged: function() { var self = this; // If pager_index is out of range, set it to display the last page - if (self.get("pager_index") !== 0 && self.total_move_lines_num <= (self.get("pager_index") * self.max_move_lines_displayed)) { - self.set("pager_index", Math.ceil(self.total_move_lines_num/self.max_move_lines_displayed)-1); + if (self.get("pager_index") !== 0 && self.get("mv_lines").length === 0 && ! self.can_fetch_more_move_lines) { + self.set("pager_index", 0); } // If there is no match to display, disable match view and pass in mode inactive - if (self.total_move_lines_num + self.mv_lines_deselected.length === 0 && self.filter === "") { + if (self.get("mv_lines").length + self.mv_lines_deselected.length === 0 && !self.can_fetch_more_move_lines && self.filter === "") { self.$el.addClass("no_match"); if (self.get("mode") === "match") { self.set("mode", "inactive"); @@ -1406,7 +1418,6 @@ openerp.account = function (instance) { } ); } else { - line_created_being_edited[0].amount = amount; line_created_being_edited.length = 1; deferred_tax.resolve(); } @@ -1414,9 +1425,12 @@ openerp.account = function (instance) { $.when(deferred_tax).then(function(){ // Format amounts + var rounding = 1/self.map_currency_id_rounding[self.st_line.currency_id]; $.each(line_created_being_edited, function(index, val) { - if (val.amount) + if (val.amount) { + line_created_being_edited[index].amount = Math.round(val.amount*rounding)/rounding; line_created_being_edited[index].amount_str = self.formatCurrency(Math.abs(val.amount), val.currency_id); + } }); self.set("line_created_being_edited", line_created_being_edited); self.createdLinesChanged(); // TODO For some reason, previous line doesn't trigger change handler @@ -1534,48 +1548,38 @@ openerp.account = function (instance) { updateMatches: function() { var self = this; var deselected_lines_num = self.mv_lines_deselected.length; - var move_lines_num = 0; var offset = self.get("pager_index") * self.max_move_lines_displayed - deselected_lines_num; if (offset < 0) offset = 0; var limit = (self.get("pager_index")+1) * self.max_move_lines_displayed - deselected_lines_num; if (limit > self.max_move_lines_displayed) limit = self.max_move_lines_displayed; - var excluded_ids = self.getParent().excluded_move_lines_ids[self.partner_id]; var excluded_ids = _.collect(self.get("mv_lines_selected").concat(self.mv_lines_deselected), function(o) { return o.id; }); - var globally_excluded_ids = self.getParent().excluded_move_lines_ids[self.partner_id]; + var globally_excluded_ids = []; + if (self.st_line.has_no_partner) + _.each(self.getParent().excluded_move_lines_ids, function(o) { globally_excluded_ids = globally_excluded_ids.concat(o) }); + else + globally_excluded_ids = self.getParent().excluded_move_lines_ids[self.partner_id]; if (globally_excluded_ids !== undefined) for (var i=0; i<globally_excluded_ids.length; i++) if (excluded_ids.indexOf(globally_excluded_ids[i]) === -1) excluded_ids.push(globally_excluded_ids[i]); - var deferred_move_lines; - var move_lines = []; + limit += 1; // Let's fetch 1 more item than requested if (limit > 0) { - // Load move lines - deferred_move_lines = self.model_bank_statement_line + return self.model_bank_statement_line .call("get_move_lines_for_reconciliation_by_statement_line_id", [self.st_line.id, excluded_ids, self.filter, offset, limit]) .then(function (lines) { - _.each(lines, function(line) { - self.decorateMoveLine(line, self.st_line.currency_id); - move_lines.push(line); - }, self); + _.each(lines, function(line) { self.decorateMoveLine(line, self.st_line.currency_id) }, self); + // If we could fetch 1 more item than what we'll display, that means there are move lines left to be displayed (so we enable the pager) + self.can_fetch_more_move_lines = (lines.length === limit); + self.set("mv_lines", lines.slice(0, limit-1)); }); + } else { + self.set("mv_lines", []); } - - // Fetch the number of move lines corresponding to this statement line and this filter - var deferred_total_move_lines_num = self.model_bank_statement_line - .call("get_move_lines_for_reconciliation_by_statement_line_id", [self.st_line.id, excluded_ids, self.filter, 0, undefined, true]) - .then(function(num){ - move_lines_num = num; - }); - - return $.when(deferred_move_lines, deferred_total_move_lines_num).then(function(){ - self.total_move_lines_num = move_lines_num + deselected_lines_num; - self.set("mv_lines", move_lines); - }); }, // Changes the partner_id of the statement_line in the DB and reloads the widget - changePartner: function(partner_id, callback) { + changePartner: function(partner_id) { var self = this; self.is_consistent = false; return self.model_bank_statement_line @@ -1588,7 +1592,6 @@ openerp.account = function (instance) { self.do_load_reconciliation_proposition = true; self.is_consistent = true; self.set("mode", "match"); - if (callback) callback(); }); }); }, diff --git a/addons/auth_signup/res_users.py b/addons/auth_signup/res_users.py index 97bcea52bc1..620298c72d5 100644 --- a/addons/auth_signup/res_users.py +++ b/addons/auth_signup/res_users.py @@ -64,7 +64,6 @@ class res_partner(osv.Model): # when required, make sure the partner has a valid signup token if context.get('signup_valid') and not partner.user_ids: self.signup_prepare(cr, uid, [partner.id], context=context) - partner.refresh() route = 'login' # the parameters to encode for the query diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 495b8418045..4356ee676ca 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -1612,7 +1612,9 @@ class mail_thread(osv.AbstractModel): # _mail_flat_thread: automatically set free messages to the first posted message if self._mail_flat_thread and model and not parent_id and thread_id: - message_ids = mail_message.search(cr, uid, ['&', ('res_id', '=', thread_id), ('model', '=', model)], context=context, order="id ASC", limit=1) + message_ids = mail_message.search(cr, uid, ['&', ('res_id', '=', thread_id), ('model', '=', model), ('type', '=', 'email')], context=context, order="id ASC", limit=1) + if not message_ids: + message_ids = message_ids = mail_message.search(cr, uid, ['&', ('res_id', '=', thread_id), ('model', '=', model)], context=context, order="id ASC", limit=1) parent_id = message_ids and message_ids[0] or False # we want to set a parent: force to set the parent_id to the oldest ancestor, to avoid having more than 1 level of thread elif parent_id: diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py index 62d433dea21..856b56dbc73 100644 --- a/addons/mrp/mrp.py +++ b/addons/mrp/mrp.py @@ -934,8 +934,8 @@ class mrp_production(osv.osv): new_moves = stock_mov_obj.action_consume(cr, uid, [produce_product.id], (subproduct_factor * production_qty_uom), location_id=produce_product.location_id.id, restrict_lot_id=lot_id, context=context) stock_mov_obj.write(cr, uid, new_moves, {'production_id': production_id}, context=context) - if produce_product.product_id.id == production.product_id.id and new_moves: - main_production_move = new_moves[0] + if produce_product.product_id.id == production.product_id.id: + main_production_move = produce_product.id if production_mode in ['consume', 'consume_produce']: if wiz: @@ -1035,8 +1035,11 @@ class mrp_production(osv.osv): def _make_production_produce_line(self, cr, uid, production, context=None): stock_move = self.pool.get('stock.move') + proc_obj = self.pool.get('procurement.order') source_location_id = production.product_id.property_stock_production.id destination_location_id = production.location_dest_id.id + procs = proc_obj.search(cr, uid, [('production_id', '=', production.id)], context=context) + procurement_id = procs and procs[0] or False data = { 'name': production.name, 'date': production.date_planned, @@ -1048,6 +1051,7 @@ class mrp_production(osv.osv): 'location_id': source_location_id, 'location_dest_id': destination_location_id, 'move_dest_id': production.move_prod_id.id, + 'procurement_id': procurement_id, 'company_id': production.company_id.id, 'production_id': production.id, 'origin': production.name, diff --git a/addons/mrp_byproduct/mrp_byproduct.py b/addons/mrp_byproduct/mrp_byproduct.py index 5649604b57d..fa7c0784052 100644 --- a/addons/mrp_byproduct/mrp_byproduct.py +++ b/addons/mrp_byproduct/mrp_byproduct.py @@ -84,6 +84,7 @@ class mrp_production(osv.osv): """ Confirms production order and calculates quantity based on subproduct_type. @return: Newly generated picking Id. """ + move_obj = self.pool.get('stock.move') picking_id = super(mrp_production,self).action_confirm(cr, uid, ids, context=context) product_uom_obj = self.pool.get('product.uom') for production in self.browse(cr, uid, ids): @@ -113,10 +114,11 @@ class mrp_production(osv.osv): 'location_id': source, 'location_dest_id': production.location_dest_id.id, 'move_dest_id': production.move_prod_id.id, - 'state': 'waiting', 'production_id': production.id } - self.pool.get('stock.move').create(cr, uid, data) + move_id = move_obj.create(cr, uid, data, context=context) + move_obj.action_confirm(cr, uid, [move_id], context=context) + return picking_id def _get_subproduct_factor(self, cr, uid, production_id, move_id=None, context=None): diff --git a/addons/point_of_sale/point_of_sale.py b/addons/point_of_sale/point_of_sale.py index c10a6c42f8e..ae6be542e94 100644 --- a/addons/point_of_sale/point_of_sale.py +++ b/addons/point_of_sale/point_of_sale.py @@ -112,10 +112,21 @@ class pos_config(osv.osv): return False return True + def _check_company_payment(self, cr, uid, ids, context=None): + for config in self.browse(cr, uid, ids, context=context): + journal_ids = [j.id for j in config.journal_ids] + if self.pool['account.journal'].search(cr, uid, [ + ('id', 'in', journal_ids), + ('company_id', '!=', config.company_id.id) + ], count=True, context=context): + return False + return True + _constraints = [ (_check_cash_control, "You cannot have two cash controls in one Point Of Sale !", ['journal_ids']), (_check_company_location, "The company of the stock location is different than the one of point of sale", ['company_id', 'stock_location_id']), (_check_company_journal, "The company of the sale journal is different than the one of point of sale", ['company_id', 'journal_id']), + (_check_company_payment, "The company of a payment method is different than the one of point of sale", ['company_id', 'journal_ids']), ] def name_get(self, cr, uid, ids, context=None): diff --git a/addons/point_of_sale/report/pos_order_report.py b/addons/point_of_sale/report/pos_order_report.py index abdf3845079..aa25052974b 100644 --- a/addons/point_of_sale/report/pos_order_report.py +++ b/addons/point_of_sale/report/pos_order_report.py @@ -58,7 +58,7 @@ class pos_order_report(osv.osv): sum(l.qty * u.factor) as product_qty, sum(l.qty * l.price_unit) as price_total, sum((l.qty * l.price_unit) * (l.discount / 100)) as total_discount, - (sum(l.qty*l.price_unit)/sum(l.qty * u.factor))::decimal(16,2) as average_price, + (sum(l.qty*l.price_unit)/sum(l.qty * u.factor))::decimal as average_price, sum(cast(to_char(date_trunc('day',s.date_order) - date_trunc('day',s.create_date),'DD') as int)) as delay_validation, s.partner_id as partner_id, s.state as state, diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js index 0ac9ebe3162..ba5f66f4635 100644 --- a/addons/point_of_sale/static/src/js/models.js +++ b/addons/point_of_sale/static/src/js/models.js @@ -331,13 +331,14 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal c.height = height var ctx = c.getContext('2d'); ctx.drawImage(self.company_logo,0,0, width, height); - + self.company_logo_base64 = c.toDataURL(); logo_loaded.resolve(); }; self.company_logo.onerror = function(){ logo_loaded.reject(); }; + self.company_logo.crossOrigin = "anonymous"; self.company_logo.src = '/web/binary/company_logo' +'?_'+Math.random(); return logo_loaded; diff --git a/addons/project/report/project_report.py b/addons/project/report/project_report.py index 63650f9774b..2010a21ea16 100644 --- a/addons/project/report/project_report.py +++ b/addons/project/report/project_report.py @@ -85,7 +85,7 @@ class report_project_task_user(osv.osv): planned_hours as hours_planned, (extract('epoch' from (t.write_date-t.create_date)))/(3600*24) as closing_days, (extract('epoch' from (t.date_start-t.create_date)))/(3600*24) as opening_days, - abs((extract('epoch' from (t.date_deadline-t.write_date)))/(3600*24)) as delay_endings_days + (extract('epoch' from (t.date_deadline-now())))/(3600*24) as delay_endings_days FROM project_task t WHERE t.active = 'true' GROUP BY diff --git a/addons/purchase/purchase.py b/addons/purchase/purchase.py index e17b541f54e..338437a5ecf 100644 --- a/addons/purchase/purchase.py +++ b/addons/purchase/purchase.py @@ -701,7 +701,7 @@ class purchase_order(osv.osv): product_uom = self.pool.get('product.uom') price_unit = order_line.price_unit if order_line.product_uom.id != order_line.product_id.uom_id.id: - price_unit *= order_line.product_uom.factor + price_unit *= order_line.product_uom.factor / order_line.product_id.uom_id.factor if order.currency_id.id != order.company_id.currency_id.id: #we don't round the price_unit, as we may want to store the standard price with more digits than allowed by the currency price_unit = self.pool.get('res.currency').compute(cr, uid, order.currency_id.id, order.company_id.currency_id.id, price_unit, round=False, context=context) diff --git a/addons/sale/wizard/sale_make_invoice_advance.py b/addons/sale/wizard/sale_make_invoice_advance.py index 12081fae6b6..d18d4ec9b95 100644 --- a/addons/sale/wizard/sale_make_invoice_advance.py +++ b/addons/sale/wizard/sale_make_invoice_advance.py @@ -54,6 +54,9 @@ class sale_advance_payment_inv(osv.osv_memory): 'product_id': _get_advance_product, } + def _translate_advance(self, cr, uid, percentage=False, context=None): + return _("Advance of %s %%") if percentage else _("Advance of %s %s") + def onchange_method(self, cr, uid, ids, advance_payment_method, product_id, context=None): if advance_payment_method == 'percentage': return {'value': {'amount':0, 'product_id':False }} @@ -100,16 +103,17 @@ class sale_advance_payment_inv(osv.osv_memory): if wizard.advance_payment_method == 'percentage': inv_amount = sale.amount_total * wizard.amount / 100 if not res.get('name'): - res['name'] = _("Advance of %s %%") % (wizard.amount) + res['name'] = self._translate_advance(cr, uid, percentage=True, context=dict(context, lang=sale.partner_id.lang)) % (wizard.amount) else: inv_amount = wizard.amount if not res.get('name'): #TODO: should find a way to call formatLang() from rml_parse symbol = sale.pricelist_id.currency_id.symbol if sale.pricelist_id.currency_id.position == 'after': - res['name'] = _("Advance of %s %s") % (inv_amount, symbol) + symbol_order = (inv_amount, symbol) else: - res['name'] = _("Advance of %s %s") % (symbol, inv_amount) + symbol_order = (symbol, inv_amount) + res['name'] = self._translate_advance(cr, uid, context=dict(context, lang=sale.partner_id.lang)) % symbol_order # determine taxes if res.get('invoice_line_tax_id'): @@ -155,7 +159,6 @@ class sale_advance_payment_inv(osv.osv_memory): sale_obj.write(cr, uid, sale_id, {'invoice_ids': [(4, inv_id)]}, context=context) return inv_id - def create_invoices(self, cr, uid, ids, context=None): """ create invoices for the active sales orders """ sale_obj = self.pool.get('sale.order') diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 1bdaa3ed5f7..332151ec56e 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -1210,7 +1210,7 @@ class Binary(http.Controller): '/web/binary/company_logo', '/logo', '/logo.png', - ], type='http', auth="none") + ], type='http', auth="none", cors="*") def company_logo(self, dbname=None, **kw): imgname = 'logo.png' placeholder = functools.partial(get_module_resource, 'web', 'static', 'src', 'img') diff --git a/addons/website/models/ir_qweb.py b/addons/website/models/ir_qweb.py index 7eba7c585be..019eedd3686 100644 --- a/addons/website/models/ir_qweb.py +++ b/addons/website/models/ir_qweb.py @@ -438,6 +438,9 @@ class Contact(orm.AbstractModel): _name = 'website.qweb.field.contact' _inherit = ['ir.qweb.field.contact', 'website.qweb.field.many2one'] + def from_html(self, cr, uid, model, column, element, context=None): + return None + class QwebView(orm.AbstractModel): _name = 'website.qweb.field.qweb' _inherit = ['ir.qweb.field.qweb'] diff --git a/addons/website/static/src/js/website.editor.js b/addons/website/static/src/js/website.editor.js index 4dda0ffbd35..6eb75694d03 100644 --- a/addons/website/static/src/js/website.editor.js +++ b/addons/website/static/src/js/website.editor.js @@ -1484,11 +1484,17 @@ this.changed($(e.target)); }, 'click button.filepicker': function () { - this.$('input[type=file]').click(); + var filepicker = this.$('input[type=file]'); + if (!_.isEmpty(filepicker)){ + filepicker[0].click(); + } }, 'click .js_disable_optimization': function () { this.$('input[name="disable_optimization"]').val('1'); - this.$('button.filepicker').click(); + var filepicker = this.$('button.filepicker'); + if (!_.isEmpty(filepicker)){ + filepicker[0].click(); + } }, 'change input[type=file]': 'file_selection', 'submit form': 'form_submit', diff --git a/addons/website/views/snippets.xml b/addons/website/views/snippets.xml index 20db73d6388..f620a057c41 100644 --- a/addons/website/views/snippets.xml +++ b/addons/website/views/snippets.xml @@ -30,9 +30,9 @@ <a href="/page/website.contactus" class="btn btn-success btn-large">Contact us</a> </p> </div> - <span class="carousel-img col-md-6 hidden-sm hidden-xs"> + <div class="carousel-img col-md-6 hidden-sm hidden-xs"> <img class="img-responsive" src="/website/static/src/img/banner/banner_picture.png" alt="Banner Odoo Image"/> - </span> + </div> </div> </div> </div> diff --git a/addons/website_forum/controllers/main.py b/addons/website_forum/controllers/main.py index b7f4e0efd9e..251faf8e64f 100644 --- a/addons/website_forum/controllers/main.py +++ b/addons/website_forum/controllers/main.py @@ -295,12 +295,10 @@ class WebsiteForum(http.Controller): cr, uid, context = request.cr, request.uid, request.context if kwargs.get('comment') and post.forum_id.id == forum.id: # TDE FIXME: check that post_id is the question or one of its answers - request.registry['forum.post'].message_post( - cr, uid, post.id, + request.registry['forum.post']._post_comment( + cr, uid, post, body=kwargs.get('comment'), - type='comment', - subtype='mt_comment', - context=dict(context, mail_create_nosubcribe=True)) + context=context) return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), slug(question))) @http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/toggle_correct', type='json', auth="public", website=True) diff --git a/addons/website_forum/models/forum.py b/addons/website_forum/models/forum.py index 5b1baa4c786..e0b60611b3f 100644 --- a/addons/website_forum/models/forum.py +++ b/addons/website_forum/models/forum.py @@ -10,8 +10,9 @@ from openerp.osv import osv, fields from openerp.tools import html2plaintext from openerp.tools.translate import _ +from werkzeug.exceptions import Forbidden -class KarmaError(ValueError): +class KarmaError(Forbidden): """ Karma-related error, used for forum and posts. """ pass @@ -357,14 +358,14 @@ class Post(osv.Model): context = {} create_context = dict(context, mail_create_nolog=True) post_id = super(Post, self).create(cr, uid, vals, context=create_context) - post = self.browse(cr, SUPERUSER_ID, post_id, context=context) # SUPERUSER_ID to avoid read access rights issues when creating + post = self.browse(cr, uid, post_id, context=context) # deleted or closed questions if post.parent_id and (post.parent_id.state == 'close' or post.parent_id.active == False): osv.except_osv(_('Error !'), _('Posting answer on [Deleted] or [Closed] question is prohibited')) # karma-based access - if post.parent_id and not post.can_ask: + if not post.parent_id and not post.can_ask: raise KarmaError('Not enough karma to create a new question') - elif not post.parent_id and not post.can_answer: + elif post.parent_id and not post.can_answer: raise KarmaError('Not enough karma to answer to a question') # messaging and chatter base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url') @@ -554,6 +555,15 @@ class Post(osv.Model): res_id = post.parent_id and "%s#answer-%s" % (post.parent_id.id, post.id) or post.id return "/forum/%s/question/%s" % (post.forum_id.id, res_id) + def _post_comment(self, cr, uid, post, body, context=None): + context = dict(context or {}, mail_create_nosubcribe=True) + if not post.can_comment: + raise KarmaError('Not enough karma to comment') + return self.message_post(cr, uid, post.id, + body=body, + type='comment', + subtype='mt_comment', + context=context) class PostReason(osv.Model): _name = "forum.post.reason" diff --git a/addons/website_forum/views/website_forum.xml b/addons/website_forum/views/website_forum.xml index 326c06ca42b..5372f84face 100644 --- a/addons/website_forum/views/website_forum.xml +++ b/addons/website_forum/views/website_forum.xml @@ -111,7 +111,7 @@ <t t-raw="0"/> </div> <div class="col-sm-3" id="right-column"> - <div t-if="not header.get('ask_hide')" class="btn-group btn-block mb16"> + <div t-if="not header.get('ask_hide')" t-attf-class="btn-group btn-block mb16 #{user.karma >= forum.karma_ask and '' or 'karma_required'}" t-attf-data-karma="#{forum.karma_ask}"> <a type="button" class="btn btn-primary btn-lg col-sm-10" t-attf-href="/forum/#{slug(forum)}/#{forum.default_allow}"> <t t-if="forum.default_allow == 'ask_question'">Ask a Question</t> <t t-if="forum.default_allow == 'post_link'">Submit a Post</t> @@ -432,7 +432,8 @@ <br/> <input type="text" name="post_tags" placeholder="Tags" class="form-control load_tags"/> <br/> - <button class="btn btn-primary" id="btn_ask_your_question">Post Your Question</button> + <button t-attf-class="btn btn-primary #{(user.karma <= forum.karma_ask) and 'karma_required' or ''}" + id="btn_ask_your_question" t-att-data-karma="forum.karma_ask">Post Your Question</button> </form> </t> </template> @@ -525,7 +526,8 @@ <form t-attf-action="/forum/#{ slug(forum) }/#{slug(question)}/reply" method="post" role="form"> <input type="hidden" name="karma" t-attf-value="#{user.karma}" id="karma"/> <textarea name="content" t-attf-id="content-#{str(question.id)}" class="form-control load_editor" required="True"/> - <button class="btn btn-primary mt16" id="btn_ask_your_question">Post Your Reply</button> + <button t-attf-class="btn btn-primary mt16 #{not question.can_answer and 'karma_required' or ''}" + id="btn_ask_your_question" t-att-data-karma="question.karma_answer">Post Your Reply</button> </form> </template> @@ -604,7 +606,7 @@ </div> <ul class="list-inline" id="options"> <li t-if="question.type == 'question'"> - <a style="cursor: pointer" data-toggle="collapse" + <a style="cursor: pointer" t-att-data-toggle="question.can_comment and 'collapse' or ''" t-attf-class="fa fa-comment-o #{not question.can_comment and 'karma_required text-muted' or ''}" t-attf-data-karma="#{not question.can_comment and question.karma_comment or 0}" t-attf-data-target="#comment#{ question._name.replace('.','') + '-' + str(question.id) }"> @@ -718,7 +720,7 @@ <li t-if="question.type == 'question'"> <a t-attf-class="fa fa-comment-o #{not answer.can_comment and 'karma_required text-muted' or ''}" t-attf-data-karma="#{not answer.can_comment and answer.karma_comment or 0}" - style="cursor: pointer" data-toggle="collapse" + style="cursor: pointer" t-att-data-toggle="answer.can_comment and 'collapse' or ''" t-attf-data-target="#comment#{ answer._name.replace('.','') + '-' + str(answer.id) }"> Comment </a> </li> diff --git a/addons/website_sale/models/product.py b/addons/website_sale/models/product.py index 2c0156fcfbc..1ce85d53c27 100644 --- a/addons/website_sale/models/product.py +++ b/addons/website_sale/models/product.py @@ -194,7 +194,7 @@ class product_product(osv.Model): class product_attribute(osv.Model): _inherit = "product.attribute" _columns = { - 'type': fields.selection([('radio', 'Radio'), ('select', 'Select'), ('color', 'Color'), ('hidden', 'Hidden')], string="Type", type="char"), + 'type': fields.selection([('radio', 'Radio'), ('select', 'Select'), ('color', 'Color'), ('hidden', 'Hidden')], string="Type"), } _defaults = { 'type': lambda *a: 'radio', diff --git a/addons/website_sale/static/src/js/website_sale.js b/addons/website_sale/static/src/js/website_sale.js index 338369b46e3..34cf1fce863 100644 --- a/addons/website_sale/static/src/js/website_sale.js +++ b/addons/website_sale/static/src/js/website_sale.js @@ -94,6 +94,9 @@ $('.oe_website_sale').each(function () { var $parent = $(this).closest('.js_product'); $parent.find(".oe_default_price:first .oe_currency_value").html( price_to_str(+$(this).data('lst_price')) ); $parent.find(".oe_price:first .oe_currency_value").html(price_to_str(+$(this).data('price')) ); + + var $img = $(this).closest('tr.js_product, .oe_website_sale').find('span[data-oe-model^="product."][data-oe-type="image"] img, img.product_detail_img'); + $img.attr("src", "/website/image/product.product/" + $(this).val() + "/image"); }); $(oe_website_sale).on('change', 'input.js_variant_change, select.js_variant_change', function (ev) { @@ -126,7 +129,7 @@ $('.oe_website_sale').each(function () { } if (product_id) { - var $img = $(this).closest('tr.js_product, .oe_website_sale').find('span[data-oe-model^="product."][data-oe-type="image"] img'); + var $img = $(this).closest('tr.js_product, .oe_website_sale').find('span[data-oe-model^="product."][data-oe-type="image"] img, img.product_detail_img'); $img.attr("src", "/website/image/product.product/" + product_id + "/image"); $img.parent().attr('data-oe-model', 'product.product').attr('data-oe-id', product_id) .data('oe-model', 'product.product').data('oe-id', product_id); @@ -169,12 +172,15 @@ $('.oe_website_sale').each(function () { $select.find("option:not(:first)").hide(); var nb = $select.find("option[data-country_id="+($(this).val() || 0)+"]").show().size(); $select.parent().toggle(nb>1); - }).change(); + }); + $(oe_website_sale).find("select[name='country_id']").change(); + $(oe_website_sale).on('change', "select[name='shipping_country_id']", function () { var $select = $("select[name='shipping_state_id']"); $select.find("option:not(:first)").hide(); var nb = $select.find("option[data-country_id="+($(this).val() || 0)+"]").show().size(); $select.parent().toggle(nb>1); - }).change(); + }); + $(oe_website_sale).find("select[name='shipping_country_id']").change(); }); }); diff --git a/addons/website_sale/views/views.xml b/addons/website_sale/views/views.xml index 8324114faf7..9a3f24bda6a 100644 --- a/addons/website_sale/views/views.xml +++ b/addons/website_sale/views/views.xml @@ -55,6 +55,16 @@ </field> </field> </record> + <record id="attribute_tree_view" model="ir.ui.view"> + <field name="name">product.attribute.tree.type</field> + <field name="model">product.attribute</field> + <field name="inherit_id" ref="product.attribute_tree_view"></field> + <field name="arch" type="xml"> + <field name="name" position="after"> + <field name="type"/> + </field> + </field> + </record> <!-- Product Public Categories --> <record id="product_public_category_form_view" model="ir.ui.view"> diff --git a/addons/website_sale_options/static/src/js/website_sale.js b/addons/website_sale_options/static/src/js/website_sale.js index c0dba9eed10..72a45139b83 100644 --- a/addons/website_sale_options/static/src/js/website_sale.js +++ b/addons/website_sale_options/static/src/js/website_sale.js @@ -5,15 +5,18 @@ $(document).ready(function () { .click(function (event) { var $form = $(this).closest('form'); var quantity = parseFloat($form.find('input[name="add_qty"]').val() || 1); + var product_id = parseInt($form.find('input[type="hidden"][name="product_id"], input[type="radio"][name="product_id"]:checked').first().val(),10); event.preventDefault(); openerp.jsonRpc("/shop/modal", 'call', { - 'product_id': parseInt($form.find('input[name="product_id"]').val(),10), + 'product_id': product_id, kwargs: { context: openerp.website.get_context() }, }).then(function (modal) { var $modal = $(modal); + $modal.find('img:first').attr("src", "/website/image/product.product/" + product_id + "/image"); + $modal.appendTo($form) .modal() .on('hidden.bs.modal', function () { |
