[IMP] website_quote: adding layout categories to website quotations
This commit is contained in:
committed by
David Monjoie
parent
b391c8d494
commit
293c1c06e6
@@ -148,10 +148,12 @@ class sale_quote(http.Controller):
|
||||
'name': option.name,
|
||||
'order_id': order.id,
|
||||
'product_id': option.product_id.id,
|
||||
'layout_category_id': option.layout_category_id.id,
|
||||
'product_uom_qty': option.quantity,
|
||||
'product_uom': option.uom_id.id,
|
||||
'discount': option.discount,
|
||||
}
|
||||
|
||||
line = request.registry.get('sale.order.line').create(request.cr, SUPERUSER_ID, vals, context=request.context)
|
||||
request.registry.get('sale.order.line')._compute_tax_id(request.cr, SUPERUSER_ID, [line], context=request.context)
|
||||
option_obj.write(request.cr, SUPERUSER_ID, [option.id], {'line_id': line}, context=request.context)
|
||||
|
||||
@@ -36,6 +36,7 @@ class sale_quote_template(osv.osv):
|
||||
'url': '/quote/template/%d' % quote_id[0]
|
||||
}
|
||||
|
||||
|
||||
class sale_quote_line(osv.osv):
|
||||
_name = "sale.quote.line"
|
||||
_description = "Quotation Template Lines"
|
||||
@@ -44,6 +45,7 @@ class sale_quote_line(osv.osv):
|
||||
'quote_id': fields.many2one('sale.quote.template', 'Quotation Template Reference', required=True, ondelete='cascade', select=True),
|
||||
'name': fields.text('Description', required=True, translate=True),
|
||||
'product_id': fields.many2one('product.product', 'Product', domain=[('sale_ok', '=', True)], required=True),
|
||||
'layout_category_id': fields.many2one('sale.layout_category', string='Section'),
|
||||
'website_description': fields.related('product_id', 'product_tmpl_id', 'quote_description', string='Line Description', type='html', translate=True),
|
||||
'price_unit': fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Product Price')),
|
||||
'discount': fields.float('Discount (%)', digits_compute= dp.get_precision('Discount')),
|
||||
@@ -217,6 +219,7 @@ class sale_order(osv.osv):
|
||||
'discount': line.discount,
|
||||
'product_uom_qty': line.product_uom_qty,
|
||||
'product_id': line.product_id.id,
|
||||
'layout_category_id': line.layout_category_id,
|
||||
'product_uom': line.product_uom_id.id,
|
||||
'website_description': line.website_description,
|
||||
'state': 'draft',
|
||||
@@ -232,6 +235,7 @@ class sale_order(osv.osv):
|
||||
price = option.price_unit
|
||||
options.append((0, 0, {
|
||||
'product_id': option.product_id.id,
|
||||
'layout_category_id': option.layout_category_id,
|
||||
'name': option.name,
|
||||
'quantity': option.quantity,
|
||||
'uom_id': option.uom_id.id,
|
||||
@@ -309,6 +313,7 @@ class sale_quote_option(osv.osv):
|
||||
'template_id': fields.many2one('sale.quote.template', 'Quotation Template Reference', ondelete='cascade', select=True, required=True),
|
||||
'name': fields.text('Description', required=True, translate=True),
|
||||
'product_id': fields.many2one('product.product', 'Product', domain=[('sale_ok', '=', True)], required=True),
|
||||
'layout_category_id': fields.many2one('sale.layout_category', string='Section'),
|
||||
'website_description': fields.html('Option Description', translate=True),
|
||||
'price_unit': fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Product Price')),
|
||||
'discount': fields.float('Discount (%)', digits_compute= dp.get_precision('Discount')),
|
||||
@@ -356,6 +361,7 @@ class sale_order_option(osv.osv):
|
||||
'line_id': fields.many2one('sale.order.line', on_delete="set null"),
|
||||
'name': fields.text('Description', required=True),
|
||||
'product_id': fields.many2one('product.product', 'Product', domain=[('sale_ok', '=', True)]),
|
||||
'layout_category_id': fields.many2one('sale.layout_category', string='Section'),
|
||||
'website_description': fields.html('Line Description'),
|
||||
'price_unit': fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Product Price')),
|
||||
'discount': fields.float('Discount (%)', digits_compute= dp.get_precision('Discount')),
|
||||
@@ -418,6 +424,37 @@ class sale_order_option(osv.osv):
|
||||
domain = {'uom_id': [('category_id', '=', self.product_id.uom_id.category_id.id)]}
|
||||
return {'domain': domain}
|
||||
|
||||
@api.multi
|
||||
def button_add_to_order(self):
|
||||
order = self.order_id
|
||||
if order.state not in ['draft', 'sent']:
|
||||
return False
|
||||
option = self
|
||||
|
||||
if option.product_id in [line.product_id for line in order.order_line]:
|
||||
line = [line for line in order.order_line if line.product_id == option.product_id][0]
|
||||
vals = {
|
||||
'product_uom_qty': line.product_uom_qty + 1,
|
||||
}
|
||||
line.write(vals)
|
||||
else:
|
||||
vals = {
|
||||
'price_unit': option.price_unit,
|
||||
'website_description': option.website_description,
|
||||
'name': option.name,
|
||||
'order_id': order.id,
|
||||
'product_id': option.product_id.id,
|
||||
'layout_category_id': option.layout_category_id.id,
|
||||
'product_uom_qty': option.quantity,
|
||||
'product_uom': option.uom_id.id,
|
||||
'discount': option.discount,
|
||||
}
|
||||
line = self.env['sale.order.line'].create(vals)
|
||||
|
||||
self.env['sale.order.line']._compute_tax_id()
|
||||
self.env['sale.order.option'].write({'line_id': line})
|
||||
return {'type':'ir.actions.client', 'tag':'reload'}
|
||||
|
||||
|
||||
class product_template(osv.Model):
|
||||
_inherit = "product.template"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
</div>
|
||||
</xpath>
|
||||
<xpath expr="//div[@class='page']/p[@id='fiscal_position_remark']" position="after">
|
||||
<div t-if="doc.options and doc.state in ['draft', 'sent']">
|
||||
<div t-if="doc.options and doc.state in ['draft', 'sent']" style="page-break-before:always;">
|
||||
<h2>
|
||||
<span>Suggested Products</span>
|
||||
</h2>
|
||||
|
||||
@@ -26,47 +26,96 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr t-foreach="quotation.order_line" t-as="line">
|
||||
<td>
|
||||
<span t-field="line.name"/>
|
||||
</td>
|
||||
<td>
|
||||
<div id="quote_qty">
|
||||
<span t-field="line.product_uom_qty"/>
|
||||
<span t-field="line.product_uom"/>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div t-foreach="line.tax_id" t-as="tax">
|
||||
<t t-esc="tax.name"/>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<strong t-if="line.discount" class="text-info">
|
||||
<t t-esc="((line.discount % 1) and '%s' or '%d') % line.discount"/>% discount
|
||||
</strong>
|
||||
</td>
|
||||
<td>
|
||||
<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 class="text-center">
|
||||
<a t-attf-href="./update_line/#{ line.id }/?order_id=#{ quotation.id }&unlink=True&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>
|
||||
</tr>
|
||||
<t t-foreach="quotation.layout_categories()" t-as="layout_category">
|
||||
|
||||
<t t-if="layout_category_size > 1" groups="sale.group_sale_layout">
|
||||
<tr class="active">
|
||||
<td colspan="7" style="font-weight: bold; border-bottom: 1px solid black;">&bull;
|
||||
<t t-esc="layout_category['name']"/>
|
||||
</td>
|
||||
</tr>
|
||||
</t>
|
||||
|
||||
<!-- Lines associated -->
|
||||
<t t-foreach="layout_category['lines']" t-as="line">
|
||||
<tr>
|
||||
<td>
|
||||
<span t-field="line.name"/>
|
||||
</td>
|
||||
<td>
|
||||
<div id="quote_qty">
|
||||
<span t-field="line.product_uom_qty"/>
|
||||
<span t-field="line.product_uom"/>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div t-foreach="line.tax_id" t-as="tax">
|
||||
<t t-esc="tax.name"/>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<strong t-if="line.discount" class="text-info">
|
||||
<t t-esc="((line.discount % 1) and '%s' or '%d') % line.discount"/>% discount
|
||||
</strong>
|
||||
</td>
|
||||
<td>
|
||||
<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 class="text-center">
|
||||
<a t-attf-href="./update_line/#{ line.id }/?order_id=#{ quotation.id }&unlink=True&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>
|
||||
</tr>
|
||||
</t>
|
||||
|
||||
<t t-if="layout_category_size > 1 and layout_category['subtotal']" groups="sale.group_sale_layout">
|
||||
<tr>
|
||||
<td></td><td></td><td></td><td></td>
|
||||
<td class="text-right"><strong>Subtotal:</strong></td>
|
||||
<td class="text-right">
|
||||
<t t-set="subtotal" t-value="sum(line.price_subtotal for line in layout_category['lines'])"/>
|
||||
<strong data-id="total_amount" t-esc="subtotal" t-esc-options='{"widget": "monetary","display_currency": "quotation.pricelist_id.currency_id"}'/>
|
||||
</td>
|
||||
</tr>
|
||||
</t>
|
||||
|
||||
<t t-if="layout_category_size > 1 and layout_category['pagebreak']" groups="sale.group_sale_layout">
|
||||
<![CDATA[
|
||||
</tbody>
|
||||
</table>
|
||||
<p style="page-break-before:always;"> </p>
|
||||
<table class="table table-condensed">
|
||||
]]>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Products</th>
|
||||
<th>Quantity</th>
|
||||
<th>Taxes</th>
|
||||
<th><span t-if="True in [line.discount > 0 for line in quotation.order_line]">Discount</span></th>
|
||||
<th class="text-right">Unit Price</th>
|
||||
<th class="text-right">Tax Excluded Price</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<![CDATA[
|
||||
<tbody>
|
||||
]]>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<tr>
|
||||
<td></td><td></td><td></td><td></td>
|
||||
<td class="text-right"><strong>Subtotal:</strong></td>
|
||||
@@ -74,6 +123,7 @@
|
||||
<strong data-id="total_amount" t-field="quotation.amount_untaxed" t-field-options='{"widget": "monetary","display_currency": "quotation.pricelist_id.currency_id"}'/>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td></td><td></td><td></td><td></td>
|
||||
<td class="text-right">Taxes:</td>
|
||||
|
||||
@@ -18,11 +18,13 @@
|
||||
<tree string="Sales Quotation Template Lines" editable="bottom">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="product_id"/>
|
||||
<field name="layout_category_id" groups="sale.group_sale_layout"/>
|
||||
<field name="name"/>
|
||||
<field name="quantity"/>
|
||||
<field name="uom_id" groups="product.group_uom"/>
|
||||
<field name="price_unit"/>
|
||||
<field name="discount" groups="sale.group_discount_per_so_line"/>
|
||||
<button name="button_add_to_order" class="oe_link" icon="fa-shopping-cart" string="Add to order lines" type="object"/>
|
||||
<field name="website_description" invisible="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
@@ -72,6 +74,7 @@
|
||||
<group>
|
||||
<group>
|
||||
<field name="product_id" on_change="on_change_product_id(product_id, product_uom_id)"/>
|
||||
<field name="layout_category_id" groups="sale.group_sale_layout"/>
|
||||
<label for="product_uom_qty"/>
|
||||
<div>
|
||||
<field
|
||||
@@ -96,6 +99,7 @@
|
||||
<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, product_uom_id)"/>
|
||||
<field name="layout_category_id" groups="sale.group_sale_layout"/>
|
||||
<field name="name"/>
|
||||
<field name="product_uom_qty"/>
|
||||
<field name="product_uom_id" groups="product.group_uom" on_change="product_uom_change(product_id, product_uom_id"/>
|
||||
@@ -105,6 +109,20 @@
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
<page string="Suggested Products">
|
||||
<field name="options">
|
||||
<tree string="Sales Quotation Template Lines" editable="bottom">
|
||||
<field name="product_id"/>
|
||||
<field name="layout_category_id" groups="sale.group_sale_layout"/>
|
||||
<field name="name"/>
|
||||
<field name="quantity"/>
|
||||
<field name="uom_id" groups="product.group_uom"/>
|
||||
<field name="price_unit"/>
|
||||
<field name="discount" groups="sale.group_discount_per_so_line"/>
|
||||
<field name="website_description" invisible="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
<page string="Suggested Products">
|
||||
<field name="options">
|
||||
<tree string="Sales Quotation Template Lines" editable="bottom">
|
||||
@@ -163,10 +181,10 @@
|
||||
<p class="oe_view_nocontent_create">
|
||||
Create a Quotation, the first step of a new sale.
|
||||
</p><p>
|
||||
Your next actions should flow efficiently: confirm the Quotation
|
||||
Your next actions should flow efficiently: confirm the Quotation
|
||||
to a Sale Order, then create the Invoice and collect the Payment.
|
||||
</p><p>
|
||||
Note that once a Quotation becomes a Sale Order, it will be moved
|
||||
Note that once a Quotation becomes a Sale Order, it will be moved
|
||||
from the Quotations list to the Sales Order list.
|
||||
</p>
|
||||
</field>
|
||||
|
||||
Reference in New Issue
Block a user