summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2014-10-21 14:59:56 +0200
committerChristophe Simonis <chs@odoo.com>2014-10-21 14:59:56 +0200
commita42167d085e8c4989412c39ec4e21685ebd93cd2 (patch)
treefc8cf942fe689de94aec631d5b8d7365693de5d0 /addons
parentd822766296fed8f72d3168c675d4cf0b89e73f0c (diff)
parent262eb662de489d98b76dece7305b594399161014 (diff)
[MERGE] forward port of branch 8.0 up to 262eb66
Diffstat (limited to 'addons')
-rw-r--r--addons/account/account_cash_statement.py4
-rw-r--r--addons/account/res_config.py8
-rw-r--r--addons/account/static/src/js/account_widgets.js83
-rw-r--r--addons/auth_signup/res_users.py1
-rw-r--r--addons/mail/mail_thread.py4
-rw-r--r--addons/mrp/mrp.py8
-rw-r--r--addons/mrp_byproduct/mrp_byproduct.py6
-rw-r--r--addons/point_of_sale/point_of_sale.py11
-rw-r--r--addons/point_of_sale/report/pos_order_report.py2
-rw-r--r--addons/point_of_sale/static/src/js/models.js3
-rw-r--r--addons/project/report/project_report.py2
-rw-r--r--addons/purchase/purchase.py2
-rw-r--r--addons/sale/wizard/sale_make_invoice_advance.py11
-rw-r--r--addons/web/controllers/main.py2
-rw-r--r--addons/website/models/ir_qweb.py3
-rw-r--r--addons/website/static/src/js/website.editor.js10
-rw-r--r--addons/website/views/snippets.xml4
-rw-r--r--addons/website_forum/controllers/main.py8
-rw-r--r--addons/website_forum/models/forum.py18
-rw-r--r--addons/website_forum/views/website_forum.xml12
-rw-r--r--addons/website_sale/models/product.py2
-rw-r--r--addons/website_sale/static/src/js/website_sale.js12
-rw-r--r--addons/website_sale/views/views.xml10
-rw-r--r--addons/website_sale_options/static/src/js/website_sale.js5
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 &gt;= 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 &lt;= 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 () {