[IMP] website_quote: UOM onchange, respect pricelists on SO, layout fixes

* add on_change_uom behaviour to quote templates lines
* fixes frontend layout issues
* use action_button_confirm instead of signal_workflow
  when confirming the quote in the frontend to trigger
  all events properly
* adapt prices using pricelist on onchange_template_id
   on sale orders
This commit is contained in:
Damien Bouvy
2015-05-28 19:04:13 +02:00
committed by Olivier Dony
parent 8b5a1f1035
commit 5047f4ecad
5 changed files with 108 additions and 52 deletions
+1 -1
View File
@@ -72,7 +72,7 @@ class sale_quote(http.Controller):
if token != order.access_token:
return request.website.render('website.404')
attachments=sign and [('signature.png', sign.decode('base64'))] or []
order_obj.signal_workflow(request.cr, SUPERUSER_ID, [order_id], 'order_confirm', context=request.context)
order_obj.action_button_confirm(request.cr, SUPERUSER_ID, [order_id], context=request.context)
message = _('Order signed by %s') % (signer,)
self.__message_post(message, order_id, type='comment', subtype='mt_comment', attachments=attachments)
return True
+70 -19
View File
@@ -64,8 +64,8 @@ class sale_quote_line(osv.osv):
'discount': 0.0,
'sequence': 10,
}
def on_change_product_id(self, cr, uid, ids, product, context=None):
vals = {}
def on_change_product_id(self, cr, uid, ids, product, uom_id=None, context=None):
vals, domain = {}, []
product_obj = self.pool.get('product.product').browse(cr, uid, product, context=context)
name = product_obj.name
if product_obj.description_sale:
@@ -75,8 +75,22 @@ class sale_quote_line(osv.osv):
'product_uom_id': product_obj.uom_id.id,
'website_description': product_obj and (product_obj.quote_description or product_obj.website_description) or '',
'name': name,
'product_uom_id': uom_id or product_obj.uom_id.id,
})
return {'value': vals}
uom_obj = self.pool.get('product.uom')
if vals['product_uom_id'] != product_obj.uom_id.id:
selected_uom = uom_obj.browse(cr, uid, vals['product_uom_id'], context=context)
new_price = uom_obj._compute_price(cr, uid, product_obj.uom_id.id, vals['price_unit'], vals['product_uom_id'])
vals['price_unit'] = new_price
if not uom_id:
domain = {'product_uom_id': [('category_id', '=', product_obj.uom_id.category_id.id)]}
return {'value': vals, 'domain': domain}
def product_uom_change(self, cr, uid, ids, product, uom_id, context=None):
context = context or {}
if not uom_id:
return {'value': {'price_unit': 0.0, 'uom_id': False}}
return self.on_change_product_id(cr, uid, ids, product, uom_id=uom_id, context=context)
def _inject_quote_description(self, cr, uid, values, context=None):
values = dict(values or {})
@@ -169,7 +183,7 @@ class sale_order(osv.osv):
'url': '/quote/%s' % (quote.id)
}
def onchange_template_id(self, cr, uid, ids, template_id, partner=False, fiscal_position=False, context=None):
def onchange_template_id(self, cr, uid, ids, template_id, partner=False, fiscal_position=False, pricelist_id=False, context=None):
if not template_id:
return True
@@ -177,6 +191,8 @@ class sale_order(osv.osv):
context = dict(context or {})
context['lang'] = self.pool['res.partner'].browse(cr, uid, partner, context).lang
pricelist_obj = self.pool['product.pricelist']
lines = [(5,)]
quote_template = self.pool.get('sale.quote.template').browse(cr, uid, template_id, context=context)
for line in quote_template.quote_line:
@@ -185,11 +201,16 @@ class sale_order(osv.osv):
line.product_uom_id.id, line.name, partner, False, True, time.strftime('%Y-%m-%d'),
False, fiscal_position, True, context)
data = res.get('value', {})
if pricelist_id:
price = pricelist_obj.price_get(cr, uid, [pricelist_id], line.product_id.id, 1, context=context)[pricelist_id]
else:
price = line.price_unit
if 'tax_id' in data:
data['tax_id'] = [(6, 0, data['tax_id'])]
data.update({
'name': line.name,
'price_unit': line.price_unit,
'price_unit': price,
'discount': line.discount,
'product_uom_qty': line.product_uom_qty,
'product_id': line.product_id.id,
@@ -270,18 +291,34 @@ class sale_quote_option(osv.osv):
_defaults = {
'quantity': 1,
}
def on_change_product_id(self, cr, uid, ids, product, context=None):
vals = {}
def on_change_product_id(self, cr, uid, ids, product, uom_id=None, context=None):
vals, domain = {}, []
product_obj = self.pool.get('product.product').browse(cr, uid, product, context=context)
name = product_obj.name
if product_obj.description_sale:
name += '\n' + product_obj.description_sale
vals.update({
'price_unit': product_obj.list_price,
'website_description': product_obj.product_tmpl_id.quote_description,
'name': product_obj.name,
'uom_id': product_obj.product_tmpl_id.uom_id.id,
'name': name,
'uom_id': uom_id or product_obj.uom_id.id,
})
if product_obj.description_sale:
vals['name'] += '\n'+product_obj.description_sale
return {'value': vals}
uom_obj = self.pool.get('product.uom')
if vals['uom_id'] != product_obj.uom_id.id:
selected_uom = uom_obj.browse(cr, uid, vals['uom_id'], context=context)
new_price = uom_obj._compute_price(cr, uid, product_obj.uom_id.id,
vals['price_unit'], vals['uom_id'])
vals['price_unit'] = new_price
if not uom_id:
domain = {'uom_id': [('category_id', '=', product_obj.uom_id.category_id.id)]}
return {'value': vals, 'domain': domain}
def product_uom_change(self, cr, uid, ids, product, uom_id, context=None):
if not uom_id:
return {'value': {'price_unit': 0.0, 'uom_id': False}}
return self.on_change_product_id(cr, uid, ids, product, uom_id=uom_id, context=context)
class sale_order_option(osv.osv):
_name = "sale.order.option"
@@ -302,20 +339,34 @@ class sale_order_option(osv.osv):
_defaults = {
'quantity': 1,
}
def on_change_product_id(self, cr, uid, ids, product, context=None):
vals = {}
def on_change_product_id(self, cr, uid, ids, product, uom_id=None, context=None):
vals, domain = {}, []
if not product:
return vals
product_obj = self.pool.get('product.product').browse(cr, uid, product, context=context)
name = product_obj.name
if product_obj.description_sale:
name += '\n'+product_obj.description_sale
vals.update({
'price_unit': product_obj.list_price,
'website_description': product_obj and (product_obj.quote_description or product_obj.website_description),
'name': product_obj.name,
'uom_id': product_obj.product_tmpl_id.uom_id.id,
'name': name,
'uom_id': uom_id or product_obj.uom_id.id,
})
if product_obj.description_sale:
vals['name'] += '\n'+product_obj.description_sale
return {'value': vals}
uom_obj = self.pool.get('product.uom')
if vals['uom_id'] != product_obj.uom_id.id:
selected_uom = uom_obj.browse(cr, uid, vals['uom_id'], context=context)
new_price = uom_obj._compute_price(cr, uid, product_obj.uom_id.id, vals['price_unit'], vals['uom_id'])
vals['price_unit'] = new_price
if not uom_id:
domain = {'uom_id': [('category_id', '=', product_obj.uom_id.category_id.id)]}
return {'value': vals, 'domain': domain}
def product_uom_change(self, cr, uid, ids, product, uom_id, context=None):
context = context or {}
if not uom_id:
return {'value': {'price_unit': 0.0, 'uom_id': False}}
return self.on_change_product_id(cr, uid, ids, product, uom_id=uom_id, context=context)
class product_template(osv.Model):
_inherit = "product.template"
@@ -6,7 +6,7 @@
}
/* mobile preview: the left menu overlaps the quote */
@media (max-width: 768px) {
@media (max-width: 992px) {
.o_website_quote .bs-sidebar {
position: relative;
}
@@ -42,11 +42,16 @@
padding-left: 30px;
font-size: 90%;
}
@media (max-width: 991px) {
.o_website_quote .bs-sidebar {
position: static;
}
/* Table Styling */
.wq-table {
table-layout: auto !important;
}
.wq-table th, .wq-table td {
border-top: none !important;
}
@media (min-width: 992px) {
.o_website_quote .bs-sidebar .nav > .active > ul {
display: block;
@@ -13,7 +13,7 @@
<template id="pricing" name="Price">
<section id="quote">
<h1 class="page-header">Pricing</h1>
<table class="table">
<table class="table wq-table">
<thead>
<tr>
<th>Products</th>
@@ -47,24 +47,22 @@
</strong>
</td>
<td>
<strong class="text-right">
<div t-field="line.price_unit"
t-field-options='{"widget": "monetary", "display_currency": "quotation.pricelist_id.currency_id"}'
t-att-style="line.discount and 'text-decoration: line-through' or ''"
t-att-class="line.discount and 'text-danger' or ''"/>
<!-- TODO: apply monetary widget formating -->
<div t-if="line.discount">
<t t-esc="'%.2f' % ((1-line.discount / 100.0) * line.price_unit)"/>
</div>
</strong>
<div t-field="line.price_unit"
t-field-options='{"widget": "monetary", "display_currency": "quotation.pricelist_id.currency_id"}'
t-att-style="line.discount and 'text-decoration: line-through' or ''"
t-att-class="(line.discount and 'text-danger' or '') + 'text-right'"/>
<!-- TODO: apply monetary widget formating -->
<div t-if="line.discount">
<t t-esc="'%.2f' % ((1-line.discount / 100.0) * line.price_unit)"/>
</div>
</td>
<td>
<div class="text-right"
t-field="line.price_subtotal"
t-field-options='{"widget": "monetary", "display_currency": "quotation.pricelist_id.currency_id"}'/>
</td>
<td>
<a t-attf-href="./update_line/#{ line.id }/?order_id=#{ quotation.id }&amp;unlink=True&amp;token=#{ quotation.access_token }" class="mb8 js_update_line_json pull-right hidden-print" t-if="line.option_line_id">
<td class="text-center">
<a t-attf-href="./update_line/#{ line.id }/?order_id=#{ quotation.id }&amp;unlink=True&amp;token=#{ quotation.access_token }" class="mb8 js_update_line_json hidden-print" t-if="line.option_line_id">
<span class="fa fa-trash-o"></span>
</a>
</td>
@@ -449,7 +447,9 @@
<template id="optional_products">
<section t-if="quotation.options" id="options">
<h1 class="page-header">Options</h1>
<table class="table table-hover">
</section>
<section id="options">
<table class="table table-hover wq-table">
<thead>
<tr>
<th>Products</th>
@@ -463,7 +463,7 @@
<tr t-foreach="quotation.options" t-as="option">
<t t-if="not option.line_id">
<td>
<div t-field="option.product_id.name"/>
<div t-field="option.product_id.name_template"/>
</td>
<td>
<div t-field="option.name"/>
@@ -484,9 +484,9 @@
</div>
</strong>
</td>
<td>
<a t-if="quotation.state in ['draft', 'sent']" t-attf-href="/quote/add_line/#{ option.id }/#{ quotation.id }/#{ quotation.access_token }" class="mb8 hidden-print">
<span class="fa fa-shopping-cart" title="Buy the product"/>
<td class="text-center" t-if="quotation.state in ['draft', 'sent']">
<a t-attf-href="/quote/add_line/#{ option.id }/#{ quotation.id }/#{ quotation.access_token }" class="mb8 hidden-print">
<span class="fa fa-shopping-cart"/>
</a>
</td>
</t>
@@ -31,10 +31,10 @@
<field name="quote_viewed" invisible="1"/>
<field name="options">
<tree string="Sales Quotation Template Lines" editable="bottom">
<field name="product_id" on_change="on_change_product_id(product_id)"/>
<field name="product_id" on_change="on_change_product_id(product_id, uom_id)"/>
<field name="name"/>
<field name="quantity"/>
<field name="uom_id" groups="product.group_uom"/>
<field name="uom_id" groups="product.group_uom" on_change="product_uom_change(product_id, uom_id)"/>
<field name="price_unit"/>
<field name="discount" groups="sale.group_discount_per_so_line"/>
<field name="website_description" invisible="1"/>
@@ -42,8 +42,8 @@
</field>
</page>
</xpath>
<xpath expr="//field[@name='payment_term']" position="after">
<field name="template_id" on_change="onchange_template_id(template_id, partner_id, fiscal_position)"/>
<xpath expr="//field[@name='project_id']" position="before">
<field name="template_id" on_change="onchange_template_id(template_id, partner_id, fiscal_position, pricelist_id)"/>
</xpath>
<xpath expr="//field[@name='client_order_ref']" position="after">
<field name="website_description" invisible="1"/>
@@ -79,7 +79,7 @@
<form string="Sales Quotation Template Lines">
<group>
<group>
<field name="product_id" on_change="on_change_product_id(product_id)"/>
<field name="product_id" on_change="on_change_product_id(product_id, product_uom_id)"/>
<label for="product_uom_qty"/>
<div>
<field
@@ -103,10 +103,10 @@
</form>
<tree string="Sales Quotation Template Lines" editable="bottom">
<field name="sequence" widget="handle"/>
<field name="product_id" on_change="on_change_product_id(product_id)"/>
<field name="product_id" on_change="on_change_product_id(product_id, product_uom_id)"/>
<field name="name"/>
<field name="product_uom_qty"/>
<field name="product_uom_id" groups="product.group_uom"/>
<field name="product_uom_id" groups="product.group_uom" on_change="product_uom_change(product_id, product_uom_id"/>
<field name="discount" groups="sale.group_discount_per_so_line"/>
<field name="price_unit"/>
<field name="website_description" invisible="1"/>
@@ -116,10 +116,10 @@
<page string="Suggested Products">
<field name="options">
<tree string="Sales Quotation Template Lines" editable="bottom">
<field name="product_id" on_change="on_change_product_id(product_id)"/>
<field name="product_id" on_change="on_change_product_id(product_id, uom_id)"/>
<field name="name"/>
<field name="quantity"/>
<field name="uom_id" groups="product.group_uom"/>
<field name="uom_id" groups="product.group_uom" on_change="product_uom_change(product_id, uom_id)"/>
<field name="price_unit"/>
<field name="discount" groups="sale.group_discount_per_so_line"/>
<field name="website_description" invisible="1"/>