[MERGE] forward port branch saas-14 up to 2fd28b2298

This commit is contained in:
Christophe Simonis
2017-07-11 15:08:36 +02:00
16 changed files with 92 additions and 32 deletions
+1 -1
View File
@@ -139,7 +139,7 @@ class EventEvent(models.Model):
'event.registration', 'event_id', string='Attendees', 'event.registration', 'event_id', string='Attendees',
readonly=False, states={'done': [('readonly', True)]}) readonly=False, states={'done': [('readonly', True)]})
# Date fields # Date fields
date_tz = fields.Selection('_tz_get', string='Timezone', required=True, default=lambda self: self.env.user.tz) date_tz = fields.Selection('_tz_get', string='Timezone', required=True, default=lambda self: self.env.user.tz or 'UTC')
date_begin = fields.Datetime( date_begin = fields.Datetime(
string='Start Date', required=True, string='Start Date', required=True,
track_visibility='onchange', states={'done': [('readonly', True)]}) track_visibility='onchange', states={'done': [('readonly', True)]})
+1
View File
@@ -2077,6 +2077,7 @@ class MailThread(models.AbstractModel):
partner_ids=[(4, pid) for pid in partner_ids], partner_ids=[(4, pid) for pid in partner_ids],
auto_delete=True, auto_delete=True,
auto_delete_message=True, auto_delete_message=True,
parent_id=False, # override accidental context defaults
subtype_id=self.env.ref('mail.mt_note').id) subtype_id=self.env.ref('mail.mt_note').id)
@api.multi @api.multi
+1 -1
View File
@@ -209,7 +209,7 @@ class PosOrder(models.Model):
have_to_group_by = session and session.config_id.group_by or False have_to_group_by = session and session.config_id.group_by or False
rounding_method = session and session.config_id.company_id.tax_calculation_rounding_method rounding_method = session and session.config_id.company_id.tax_calculation_rounding_method
for order in self.filtered(lambda o: not o.account_move or order.state == 'paid'): for order in self.filtered(lambda o: not o.account_move or o.state == 'paid'):
current_company = order.sale_journal.company_id current_company = order.sale_journal.company_id
account_def = IrProperty.get( account_def = IrProperty.get(
'property_account_receivable_id', 'res.partner') 'property_account_receivable_id', 'res.partner')
@@ -1109,6 +1109,7 @@ exports.Orderline = Backbone.Model.extend({
orderline.quantity = this.quantity; orderline.quantity = this.quantity;
orderline.quantityStr = this.quantityStr; orderline.quantityStr = this.quantityStr;
orderline.discount = this.discount; orderline.discount = this.discount;
orderline.price = this.price;
orderline.type = this.type; orderline.type = this.type;
orderline.selected = false; orderline.selected = false;
return orderline; return orderline;
+6 -2
View File
@@ -1405,8 +1405,12 @@
<div class="pos-center-align"><t t-esc="moment().format('L LT')"/> <t t-esc="order.name"/></div> <div class="pos-center-align"><t t-esc="moment().format('L LT')"/> <t t-esc="order.name"/></div>
<br /> <br />
<t t-esc="widget.pos.company.name"/><br /> <t t-esc="widget.pos.company.name"/><br />
Phone: <t t-esc="widget.pos.company.phone || ''"/><br /> <div class="receipt-phone">
User: <t t-esc="widget.pos.cashier ? widget.pos.cashier.name : widget.pos.user.name"/><br /> Phone: <t t-esc="widget.pos.company.phone || ''"/><br />
</div>
<div class="receipt-user">
User: <t t-esc="widget.pos.cashier ? widget.pos.cashier.name : widget.pos.user.name"/><br />
</div>
<br /> <br />
<t t-if="receipt.header"> <t t-if="receipt.header">
<div style='text-align:center'> <div style='text-align:center'>
+12
View File
@@ -1854,6 +1854,18 @@ msgstr ""
msgid "You cannot define the decimal precision of 'Account' as greater than the rounding factor of the company's main currency" msgid "You cannot define the decimal precision of 'Account' as greater than the rounding factor of the company's main currency"
msgstr "" msgstr ""
#. module: product
#: code:addons/product/wizard/product_price_list.py:26
#, python-format
msgid "You have to set a logo for your company."
msgstr ""
#. module: product
#: code:addons/product/wizard/product_price_list.py:28
#, python-format
msgid "You have to set your reports's header and footer layout."
msgstr ""
#. module: product #. module: product
#: model:ir.actions.act_window,help:product.product_uom_form_action #: model:ir.actions.act_window,help:product.product_uom_form_action
msgid "You must define a conversion rate between several Units of\n" msgid "You must define a conversion rate between several Units of\n"
+7 -1
View File
@@ -1,7 +1,8 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details. # Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models from odoo import api, fields, models, _
from odoo.exceptions import UserError
class product_price_list(models.TransientModel): class product_price_list(models.TransientModel):
@@ -21,6 +22,11 @@ class product_price_list(models.TransientModel):
To get the date and print the report To get the date and print the report
@return : return report @return : return report
""" """
if (not self.env.user.company_id.logo):
raise UserError(_("You have to set a logo or a layout for your company."))
elif (not self.env.user.company_id.external_report_layout):
raise UserError(_("You have to set your reports's header and footer layout."))
datas = {'ids': self.env.context.get('active_ids', [])} datas = {'ids': self.env.context.get('active_ids', [])}
res = self.read(['price_list', 'qty1', 'qty2', 'qty3', 'qty4', 'qty5']) res = self.read(['price_list', 'qty1', 'qty2', 'qty3', 'qty4', 'qty5'])
res = res and res[0] or {} res = res and res[0] or {}
+4 -3
View File
@@ -514,9 +514,10 @@ class SaleOrder(models.Model):
for tax in line.tax_id: for tax in line.tax_id:
group = tax.tax_group_id group = tax.tax_group_id
res.setdefault(group, 0.0) res.setdefault(group, 0.0)
amount = tax.compute_all(line.price_reduce + base_tax, quantity=line.product_uom_qty, taxes = tax.compute_all(line.price_reduce + base_tax, quantity=line.product_uom_qty,
product=line.product_id, partner=self.partner_shipping_id)['taxes'][0]['amount'] product=line.product_id, partner=self.partner_shipping_id)['taxes']
res[group] += amount for t in taxes:
res[group] += t['amount']
if tax.include_base_amount: if tax.include_base_amount:
base_tax += tax.compute_all(line.price_reduce + base_tax, quantity=1, product=line.product_id, base_tax += tax.compute_all(line.price_reduce + base_tax, quantity=1, product=line.product_id,
partner=self.partner_shipping_id)['taxes'][0]['amount'] partner=self.partner_shipping_id)['taxes'][0]['amount']
+6 -1
View File
@@ -59,7 +59,12 @@ class SaleOrderLine(models.Model):
def _product_margin(self): def _product_margin(self):
for line in self: for line in self:
currency = line.order_id.pricelist_id.currency_id currency = line.order_id.pricelist_id.currency_id
line.margin = currency.round(line.price_subtotal - ((line.purchase_price or line.product_id.standard_price) * line.product_uom_qty)) price = line.purchase_price
if not price:
from_cur = line.env.user.company_id.currency_id.with_context(date=line.order_id.date_order)
price = from_cur.compute(line.product_id.standard_price, currency, round=False)
line.margin = currency.round(line.price_subtotal - (price * line.product_uom_qty))
class SaleOrder(models.Model): class SaleOrder(models.Model):
+4 -3
View File
@@ -142,16 +142,17 @@ class WebsiteSale(http.Controller):
(variant id, [visible attribute ids], variant price, variant sale price) (variant id, [visible attribute ids], variant price, variant sale price)
""" """
# product attributes with at least two choices # product attributes with at least two choices
product = product.with_context(quantity=1) quantity = product._context.get('quantity') or 1
product = product.with_context(quantity=quantity)
visible_attrs_ids = product.attribute_line_ids.filtered(lambda l: len(l.value_ids) > 1).mapped('attribute_id').ids visible_attrs_ids = product.attribute_line_ids.filtered(lambda l: len(l.value_ids) > 1).mapped('attribute_id').ids
to_currency = request.website.get_current_pricelist().currency_id to_currency = request.website.get_current_pricelist().currency_id
attribute_value_ids = [] attribute_value_ids = []
for variant in product.product_variant_ids: for variant in product.product_variant_ids:
if to_currency != product.currency_id: if to_currency != product.currency_id:
price = variant.currency_id.compute(variant.website_public_price, to_currency) price = variant.currency_id.compute(variant.website_public_price, to_currency) / quantity
else: else:
price = variant.website_public_price price = variant.website_public_price / quantity
visible_attribute_ids = [v.id for v in variant.attribute_value_ids if v.attribute_id.id in visible_attrs_ids] visible_attribute_ids = [v.id for v in variant.attribute_value_ids if v.attribute_id.id in visible_attrs_ids]
attribute_value_ids.append([variant.id, visible_attribute_ids, variant.website_price, price]) attribute_value_ids.append([variant.id, visible_attribute_ids, variant.website_price, price])
return attribute_value_ids return attribute_value_ids
@@ -86,23 +86,30 @@ odoo.define('website_sale.website_sale', function (require) {
$(oe_website_sale).on("change", 'input[name="add_qty"]', function (event) { $(oe_website_sale).on("change", 'input[name="add_qty"]', function (event) {
var product_ids = []; var product_ids = [];
var product_dom = $(".js_product .js_add_cart_variants[data-attribute_value_ids]").last(); var product_dom = $(".js_product .js_add_cart_variants[data-attribute_value_ids]");
var qty = $(event.target).closest('form').find('input[name="add_qty"]').val();
if (!product_dom.length) { if (!product_dom.length) {
return; return;
} }
_.each(product_dom.data("attribute_value_ids"), function(entry) { _.each(product_dom, function (prod) {
product_ids.push(entry[0]);}); _.each($(prod).data("attribute_value_ids"), function(entry) {
var qty = $(event.target).closest('form').find('input[name="add_qty"]').val(); if (product_ids.indexOf(entry[0]) === -1) {
product_ids.push(entry[0]);
}
});
});
if ($("#product_detail").length) { if ($("#product_detail").length) {
// display the reduction from the pricelist in function of the quantity // display the reduction from the pricelist in function of the quantity
ajax.jsonRpc("/shop/get_unit_price", 'call', {'product_ids': product_ids,'add_qty': parseInt(qty)}) ajax.jsonRpc("/shop/get_unit_price", 'call', {'product_ids': product_ids,'add_qty': parseInt(qty)})
.then(function (data) { .then(function (data) {
var current = product_dom.data("attribute_value_ids"); _.each(product_dom, function (prod) {
for(var j=0; j < current.length; j++){ var current = $(prod).data("attribute_value_ids");
current[j][2] = data[current[j][0]]; for(var j=0; j < current.length; j++){
} current[j][2] = data[current[j][0]];
product_dom.attr("data-attribute_value_ids", JSON.stringify(current)).trigger("change"); }
$(prod).trigger("change");
});
}); });
} }
}); });
@@ -296,17 +303,18 @@ odoo.define('website_sale.website_sale', function (require) {
$(oe_website_sale).on('change', 'input.js_variant_change, select.js_variant_change, ul[data-attribute_value_ids]', function (ev) { $(oe_website_sale).on('change', 'input.js_variant_change, select.js_variant_change, ul[data-attribute_value_ids]', function (ev) {
var $ul = $(ev.target).closest('.js_add_cart_variants'); var $ul = $(ev.target).closest('.js_add_cart_variants');
var $parent = $ul.closest('.js_product'); var $parent = $ul.closest('.js_product');
var $product_id = $parent.find('input.product_id').first(); var $product_id = $parent.find('.product_id').first();
var $price = $parent.find(".oe_price:first .oe_currency_value") var $price = $parent.find(".oe_price:first .oe_currency_value");
.add($('#product_confirmation').find(".oe_price")); var $default_price = $parent.find(".oe_default_price:first .oe_currency_value");
var $default_price = $parent.find(".oe_default_price:first .oe_currency_value")
.add($('#product_confirmation').find(".oe_default_price:first .oe_currency_value"));
var $optional_price = $parent.find(".oe_optional:first .oe_currency_value"); var $optional_price = $parent.find(".oe_optional:first .oe_currency_value");
var variant_ids = $ul.data("attribute_value_ids"); var variant_ids = $ul.data("attribute_value_ids");
var values = []; var values = [];
var unchanged_values = $parent.find('div.oe_unchanged_value_ids').data('unchanged_value_ids') || [];
$parent.find('input.js_variant_change:checked, select.js_variant_change').each(function () { $parent.find('input.js_variant_change:checked, select.js_variant_change').each(function () {
values.push(+$(this).val()); values.push(+$(this).val());
}); });
values = values.concat(unchanged_values);
$parent.find("label").removeClass("text-muted css_not_available"); $parent.find("label").removeClass("text-muted css_not_available");
@@ -320,8 +328,10 @@ odoo.define('website_sale.website_sale', function (require) {
if (variant_ids[k][3]-variant_ids[k][2]>0.01) { if (variant_ids[k][3]-variant_ids[k][2]>0.01) {
$default_price.closest('.oe_website_sale').addClass("discount"); $default_price.closest('.oe_website_sale').addClass("discount");
$optional_price.closest('.oe_optional').show().css('text-decoration', 'line-through'); $optional_price.closest('.oe_optional').show().css('text-decoration', 'line-through');
$default_price.parent().removeClass('hidden');
} else { } else {
$optional_price.closest('.oe_optional').hide(); $optional_price.closest('.oe_optional').hide();
$default_price.parent().addClass('hidden');
} }
product_id = variant_ids[k][0]; product_id = variant_ids[k][0];
update_product_image(this, product_id); update_product_image(this, product_id);
+2 -1
View File
@@ -451,7 +451,8 @@
<div class="col-sm-5 col-lg-4 col-lg-offset-1" id="product_details"> <div class="col-sm-5 col-lg-4 col-lg-offset-1" id="product_details">
<h1 itemprop="name" t-field="product.name">Product Name</h1> <h1 itemprop="name" t-field="product.name">Product Name</h1>
<span itemprop="url" style="display:none;" t-esc="'/shop/product/%s' % slug(product)" /> <span itemprop="url" style="display:none;" t-esc="'/shop/product/%s' % slug(product)" />
<form action="/shop/cart/update" class="js_add_cart_variants" t-att-data-attribute_value_ids="product.product_variant_ids.ids" method="POST"> <t t-set="attribute_value_ids" t-value="get_attribute_value_ids(product)"/>
<form action="/shop/cart/update" class="js_add_cart_variants" t-att-data-attribute_value_ids="attribute_value_ids" method="POST">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()" /> <input type="hidden" name="csrf_token" t-att-value="request.csrf_token()" />
<div class="js_product" t-if="product.product_variant_ids"> <div class="js_product" t-if="product.product_variant_ids">
<t t-placeholder="select"> <t t-placeholder="select">
@@ -54,6 +54,7 @@ class WebsiteSaleOptions(WebsiteSale):
def modal(self, product_id, **kw): def modal(self, product_id, **kw):
pricelist = request.website.get_current_pricelist() pricelist = request.website.get_current_pricelist()
product_context = dict(request.context) product_context = dict(request.context)
quantity = kw['kwargs']['context']['quantity']
if not product_context.get('pricelist'): if not product_context.get('pricelist'):
product_context['pricelist'] = pricelist.id product_context['pricelist'] = pricelist.id
# fetch quantity from custom context # fetch quantity from custom context
@@ -63,8 +64,18 @@ class WebsiteSaleOptions(WebsiteSale):
to_currency = pricelist.currency_id to_currency = pricelist.currency_id
compute_currency = lambda price: request.env['res.currency']._compute(from_currency, to_currency, price) compute_currency = lambda price: request.env['res.currency']._compute(from_currency, to_currency, price)
product = request.env['product.product'].with_context(product_context).browse(int(product_id)) product = request.env['product.product'].with_context(product_context).browse(int(product_id))
main_product_attr_ids = self.get_attribute_value_ids(product)
for variant in main_product_attr_ids:
if variant[0] == product.id:
# We indeed need a list of lists (even with only 1 element)
main_product_attr_ids = [variant]
break
return request.env['ir.ui.view'].render_template("website_sale_options.modal", { return request.env['ir.ui.view'].render_template("website_sale_options.modal", {
'product': product, 'product': product,
'quantity': quantity,
'compute_currency': compute_currency, 'compute_currency': compute_currency,
'get_attribute_value_ids': self.get_attribute_value_ids, 'get_attribute_value_ids': self.get_attribute_value_ids,
'main_product_attr_ids': main_product_attr_ids,
}) })
@@ -15,3 +15,8 @@ div#modal_optional_products table tr td {
display: none; display: none;
} }
} }
.oe_striked_price {
text-decoration: line-through;
white-space: nowrap;
}
@@ -85,7 +85,7 @@ $('.oe_website_sale #add_to_cart, .oe_website_sale #products_grid .a-submit')
var product_id = $($modal.find('span.oe_price[data-product-id]')).first().data('product-id'); var product_id = $($modal.find('span.oe_price[data-product-id]')).first().data('product-id');
var product_ids = [product_id]; var product_ids = [product_id];
var $products_dom = []; var $products_dom = [];
$modal.find(".js_add_cart_variants[data-attribute_value_ids]").each(function(){ $("ul.js_add_cart_variants[data-attribute_value_ids]").each(function(){
var $el = $(this); var $el = $(this);
$products_dom.push($el); $products_dom.push($el);
_.each($el.data("attribute_value_ids"), function (values) { _.each($el.data("attribute_value_ids"), function (values) {
@@ -42,7 +42,7 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr id="product_confirmation"> <tr id="product_confirmation" class="js_product">
<td class='td-img'> <td class='td-img'>
<span t-field="product.image_medium" t-options='{"widget": "image" }'/> <span t-field="product.image_medium" t-options='{"widget": "image" }'/>
</td> </td>
@@ -65,16 +65,18 @@
</div> </div>
</td> </td>
<td class="text-center td-price" name="price"> <td class="text-center td-price" name="price">
<span t-attf-class="text-danger oe_default_price" style="text-decoration: line-through; white-space: nowrap;" <ul class="hidden js_add_cart_variants" t-att-data-attribute_value_ids="main_product_attr_ids"></ul>
<div class="hidden oe_unchanged_value_ids" t-att-data-unchanged_value_ids="main_product_attr_ids[0][1]" ></div>
<span t-attf-class="text-danger oe_default_price oe_striked_price {{ (compute_currency(product.lst_price) - product.website_price) &lt; 0.01 and 'hidden' }}"
t-field="product.lst_price" t-field="product.lst_price"
t-options='{ t-options='{
"widget": "monetary", "widget": "monetary",
"from_currency": product.currency_id, "from_currency": product.currency_id,
"display_currency": website.currency_id "display_currency": website.currency_id
}'/> }'/>
<span class="oe_price" style="white-space: nowrap;" <span class="oe_price product_id" style="white-space: nowrap;"
t-att-data-product-id="product.id" t-att-data-product-id="product.id"
t-field="product.with_context(quantity=1).website_price" t-esc="product.website_price / quantity"
t-options='{ t-options='{
"widget": "monetary", "widget": "monetary",
"display_currency": website.currency_id "display_currency": website.currency_id