[ADD]: object sale.quote.template and improve code

bzr revid: aja@tinyerp.com-20131216052451-rqz5tdqzqj4cv5ar
This commit is contained in:
ajay javiya (OpenERP) 2013-12-16 10:54:51 +05:30
parent 558e5fdf9b
commit 68443085e1
8 changed files with 254 additions and 150 deletions

View File

@ -9,7 +9,7 @@ OpenERP Sale Quote Roller
""", """,
'author': 'OpenERP SA', 'author': 'OpenERP SA',
'depends': ['website_sale','website','product','portal_sale', 'mail'], 'depends': ['website_sale','portal_sale', 'mail'],
'data': [ 'data': [
'views/website_sale_quote.xml', 'views/website_sale_quote.xml',
'sale_quote_view.xml', 'sale_quote_view.xml',

View File

@ -1,18 +1,33 @@
import random # -*- coding: utf-8 -*-
import uuid ##############################################################################
import simplejson #
# OpenERP, Open Source Management Solution
import werkzeug.exceptions # Copyright (C) 2013-Today OpenERP SA (<http://www.openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp import SUPERUSER_ID from openerp import SUPERUSER_ID
from openerp.osv import osv
from openerp.addons.web import http from openerp.addons.web import http
from openerp.addons.web.http import request from openerp.addons.web.http import request
from openerp.addons.website.models import website from openerp.addons.website.models import website
class sale_quote(http.Controller): class sale_quote(http.Controller):
def get_quote(self, token): def _get_quote(self, token):
order_pool = request.registry.get('sale.order') order_pool = request.registry.get('sale.order')
order_id = order_pool.search(request.cr, SUPERUSER_ID, [('access_token', '=', token)], context=request.context) order_id = order_pool.search(request.cr, SUPERUSER_ID, [('access_token', '=', token)], context=request.context)
return order_id return order_id
@ -28,35 +43,30 @@ class sale_quote(http.Controller):
partner = order_pool.browse(request.cr, SUPERUSER_ID, order_id, context=request.context).partner_id.id partner = order_pool.browse(request.cr, SUPERUSER_ID, order_id, context=request.context).partner_id.id
return user_pool.search(request.cr, SUPERUSER_ID, [('partner_id', '=', partner)])[0] return user_pool.search(request.cr, SUPERUSER_ID, [('partner_id', '=', partner)])[0]
@website.route(['/quote/<token>','/quote/<int:order_id>'], type='http', auth="public") @website.route(['/quote/<token>', '/quote/<int:order_id>'], type='http', auth="public")
def view(self, token=None, order_id=None, **post): def view(self, token=None, order_id=None, **post):
values = {} values = {}
order_pool = request.registry.get('sale.order') order_pool = request.registry.get('sale.order')
if token: if token:
order_id = self.get_quote(token)[0] order_id = self._get_quote(token)[0]
quotation = order_pool.browse(request.cr, SUPERUSER_ID, order_id) quotation = order_pool.browse(request.cr, SUPERUSER_ID, order_id)
render_template = 'website_sale_quote.so_quotation'
values.update({ values.update({
'quotation' : quotation, 'quotation': quotation,
'total_mail' : len(order_pool.search(request.cr, request.uid,[('id','=',order_id),('message_ids.type', '=', 'email')], context=request.context)),
}) })
return request.website.render(render_template, values) return request.website.render('website_sale_quote.so_quotation', values)
@website.route(['/quote/<int:order_id>/accept'], type='http', auth="public") @website.route(['/quote/<int:order_id>/accept'], type='http', auth="public")
def accept(self, order_id=None, **post): def accept(self, order_id=None, **post):
values = {} request.registry.get('sale.order').write(request.cr, SUPERUSER_ID, [order_id], {'state': 'manual'})
quotation = request.registry.get('sale.order').write(request.cr, SUPERUSER_ID, [order_id], {'state': 'manual'})
return request.redirect("/quote/%s" % self._get_token(order_id)) return request.redirect("/quote/%s" % self._get_token(order_id))
@website.route(['/quote/<int:order_id>/decline'], type='http', auth="public") @website.route(['/quote/<int:order_id>/decline'], type='http', auth="public")
def decline(self, order_id=None, **post): def decline(self, order_id=None, **post):
values = {} request.registry.get('sale.order').write(request.cr, SUPERUSER_ID, [order_id], {'state': 'cancel'})
quotation = request.registry.get('sale.order').write(request.cr, SUPERUSER_ID, [order_id], {'state': 'cancel'})
return request.redirect("/quote/%s" % self._get_token(order_id)) return request.redirect("/quote/%s" % self._get_token(order_id))
@website.route(['/quote/<int:order_id>/post'], type='http', auth="public") @website.route(['/quote/<int:order_id>/post'], type='http', auth="public")
def post(self, order_id=None, **post): def post(self, order_id=None, **post):
values = {}
if post.get('new_message'): if post.get('new_message'):
request.session.body = post.get('new_message') request.session.body = post.get('new_message')
if 'body' in request.session and request.session.body: if 'body' in request.session and request.session.body:
@ -71,16 +81,14 @@ class sale_quote(http.Controller):
@website.route(['/quote/update_line'], type='json', auth="public") @website.route(['/quote/update_line'], type='json', auth="public")
def update(self, line_id=None, remove=False, unlink=False, order_id=None, **post): def update(self, line_id=None, remove=False, unlink=False, order_id=None, **post):
if unlink: if unlink:
request.registry.get('sale.order.line').unlink(request.cr, SUPERUSER_ID,[int(line_id)], context=request.context) return request.registry.get('sale.order.line').unlink(request.cr, SUPERUSER_ID, [int(line_id)], context=request.context)
return val = self._update_order_line(line_id=int(line_id), number=(remove and -1 or 1))
else:
val = self._update_order_line(line_id=int(line_id), number=(remove and -1 or 1))
order = request.registry.get('sale.order').browse(request.cr, SUPERUSER_ID, order_id) order = request.registry.get('sale.order').browse(request.cr, SUPERUSER_ID, order_id)
return [val , order.amount_total] return [val, order.amount_total]
def _update_order_line(self,line_id, number): def _update_order_line(self, line_id, number):
order_line_obj = request.registry.get('sale.order.line') order_line_obj = request.registry.get('sale.order.line')
order_line_val = order_line_obj.read(request.cr, SUPERUSER_ID, [int(line_id)], [], context=request.context)[0] order_line_val = order_line_obj.read(request.cr, SUPERUSER_ID, [int(line_id)], [], context=request.context)[0]
quantity = order_line_val['product_uom_qty'] + number quantity = order_line_val['product_uom_qty'] + number
order_line_obj.write(request.cr, SUPERUSER_ID, [int(line_id)], {'product_uom_qty':(quantity)}, context=request.context) order_line_obj.write(request.cr, SUPERUSER_ID, [int(line_id)], {'product_uom_qty': (quantity)}, context=request.context)
return quantity return quantity

View File

@ -23,87 +23,130 @@ from openerp.osv import osv, fields
import hashlib import hashlib
import time import time
class sale_quote_template(osv.osv):
_name = "sale.quote.template"
_description = "Sale Quotation Template"
_columns = {
'name': fields.char('Quotation Template', size=256, required=True),
'website_description': fields.html('Description'),
'quote_line': fields.one2many('sale.quote.line', 'quote_id', 'Quote Template Lines'),
'note': fields.text('Terms and conditions'),
}
class sale_quote_line(osv.osv):
_name = "sale.quote.line"
_description = "Quotation Template Lines"
_columns = {
'quote_id': fields.many2one('sale.quote.template', 'Quotation Template Reference', required=True, ondelete='cascade', select=True),
'name': fields.text('Description', required=True),
'product_id': fields.many2one('product.product', 'Product', domain=[('sale_ok', '=', True)], change_default=True),
'website_description': fields.html('Line Description'),
'price_unit': fields.float('Unit Price', required=True),
'product_uom_qty': fields.float('Quantity', required=True),
}
_defaults = {
'product_uom_qty': 1,
}
def on_change_product_id(self, cr, uid, ids, product, context=None):
vals = {}
product_obj = self.pool.get('product.product')
product_obj = product_obj.browse(cr, uid, product, context=context)
vals.update({
'price_unit': product_obj.list_price,
'website_description': product_obj.website_description,
'name': product_obj.name,
})
return {'value': vals}
class sale_order_line(osv.osv): class sale_order_line(osv.osv):
_inherit = "sale.order.line" _inherit = "sale.order.line"
_description = "Sales Order Line" _description = "Sales Order Line"
_columns = { _columns = {
'website_description':fields.html('Line Description'), 'website_description': fields.html('Line Description'),
} }
def product_id_change(self, cr, uid, ids, pricelist, product, qty=0,uom=False, qty_uos=0, uos=False, name='', partner_id=False,lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False, flag=False, context=None): def product_id_change(self, cr, uid, ids, pricelist, product, qty=0, uom=False, qty_uos=0, uos=False, name='', partner_id=False, lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False, flag=False, context=None):
res = super(sale_order_line, self).product_id_change(cr, uid, ids, pricelist, product, qty,uom, qty_uos, uos, name, partner_id,lang, update_tax, date_order, packaging, fiscal_position, flag, context) res = super(sale_order_line, self).product_id_change(cr, uid, ids, pricelist, product, qty, uom, qty_uos, uos, name, partner_id, lang, update_tax, date_order, packaging, fiscal_position, flag, context)
if product: if product:
desc = self.pool.get('product.product').browse(cr, uid, product, context).website_description desc = self.pool.get('product.product').browse(cr, uid, product, context).website_description
res.get('value').update({'website_description': desc}) res.get('value').update({'website_description': desc})
return res return res
class sale_order(osv.osv): class sale_order(osv.osv):
_inherit = 'sale.order' _inherit = 'sale.order'
_columns = { _columns = {
'quote_url': fields.char('URL', readonly=True), 'quote_url': fields.char('URL', readonly=True),
'access_token':fields.char('Quotation Token', size=256), 'access_token': fields.char('Quotation Token', size=256),
'template_id': fields.many2one('sale.order','Quote Template'), 'template_id': fields.many2one('sale.quote.template', 'Quote Template'),
'website_description': fields.html('Description'), 'website_description': fields.html('Description'),
'is_template': fields.boolean('Is Template'),
} }
def new_quotation_token(self, cr, uid, ids,context=None): def _get_token(self, cr, uid, ids, context=None):
"""
Generate token for sale order on action_quotation_send , send it to customer.
"""
db_uuid = self.pool.get('ir.config_parameter').get_param(cr, uid, 'database.uuid') db_uuid = self.pool.get('ir.config_parameter').get_param(cr, uid, 'database.uuid')
quotation_token = hashlib.sha256('%s-%s-%s' % (time.time(), db_uuid, ids[0])).hexdigest() return hashlib.sha256('%s-%s-%s' % (time.time(), db_uuid, ids[0])).hexdigest()
return self.write(cr, uid, ids,{'access_token': quotation_token,'quote_url': self._get_signup_url(cr, uid, False,quotation_token, context)} )
def create(self, cr, uid, vals, context=None): def create(self, cr, uid, vals, context=None):
template_id = vals.get('template_id', False)
new_id = super(sale_order, self).create(cr, uid, vals, context=context) new_id = super(sale_order, self).create(cr, uid, vals, context=context)
self.create_portal_user(cr, uid, new_id, context=context) self.write(cr, uid, [new_id], {'quote_url': self._get_signup_url(cr, uid, new_id, False, context)})
self.write(cr, uid, [new_id],{'quote_url': self._get_signup_url(cr, uid, new_id, False, context)} )
return new_id return new_id
def action_quotation_send(self, cr, uid, ids, context=None): def action_quotation_send(self, cr, uid, ids, context=None):
token = self._get_token(cr, uid, ids, context)
self._create_portal_user(cr, uid, ids, context=context)
self.write(cr, uid, ids, {'access_token': token, 'quote_url': self._get_signup_url(cr, uid, False, token, context)})
res = super(sale_order, self).action_quotation_send(cr, uid, ids, context=context) res = super(sale_order, self).action_quotation_send(cr, uid, ids, context=context)
self.new_quotation_token(cr, uid, ids,context)
return res return res
def create_portal_user(self, cr, uid, order_id, context=None): def _create_portal_user(self, cr, uid, ids, context=None):
"""
create portal user of customer in quotation , when action_quotation_send perform.
"""
user = []
portal_ids = self.pool.get('res.groups').search(cr, uid, [('is_portal', '=', True)]) portal_ids = self.pool.get('res.groups').search(cr, uid, [('is_portal', '=', True)])
user_wizard_pool = self.pool.get('portal.wizard.user') user_wizard_pool = self.pool.get('portal.wizard.user')
order = self.browse(cr, uid, order_id, context=context) for order in self.browse(cr, uid, ids, context=context):
wizard_id = self.pool.get('portal.wizard').create(cr, uid,{'portal_id': portal_ids and portal_ids[0] or False}) wizard_id = self.pool.get('portal.wizard').create(cr, uid, {'portal_id': portal_ids and portal_ids[0] or False})
user_id = user_wizard_pool.create(cr, uid,{ user.append(user_wizard_pool.create(cr, uid, {
'wizard_id':wizard_id, 'wizard_id': wizard_id,
'partner_id':order.partner_id.id, 'partner_id': order.partner_id.id,
'email':order.partner_id.email, 'email': order.partner_id.email,
'in_portal':True} ) 'in_portal': True}))
return user_wizard_pool.action_apply(cr, uid, [user_id], context=context) return user_wizard_pool.action_apply(cr, uid, user, context=context)
def _get_signup_url(self, cr, uid, order_id=False, token=False, context=None): def _get_signup_url(self, cr, uid, order_id=False, token=False, context=None):
base_url = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url', default='http://localhost:8069', context=context) base_url = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url', default='http://localhost:8069', context=context)
url = "%s/quote/%s" % (base_url ,token and token or order_id) url = "%s/quote/%s" % (base_url, token and token or order_id)
return url return url
def _get_sale_order_line(self, cr, uid,template_id, context=None): def _get_sale_order_line(self, cr, uid, template_id, context=None):
line_pool = self.pool.get('sale.order.line') """create order line from selected quote template line."""
lines = [] lines = []
order_template = self.browse(cr, uid, template_id, context) quote_template = self.pool.get('sale.quote.template').browse(cr, uid, template_id, context)
for line in order_template.order_line: for line in quote_template.quote_line:
lines.append((0,0,{ lines.append((0, 0, {
'name': line.name, 'name': line.name,
'sequence': line.sequence,
'price_unit': line.price_unit, 'price_unit': line.price_unit,
'product_uom_qty': line.product_uom_qty, 'product_uom_qty': line.product_uom_qty,
'discount': line.discount,
'product_id': line.product_id.id, 'product_id': line.product_id.id,
'tax_id': [(6, 0, [x.id for x in line.tax_id])], 'website_description': line.website_description,
'website_description':line.website_description, 'state': 'draft',
'state':'draft',
})) }))
return {'order_line':lines,'website_description': order_template.website_description} return {'order_line': lines, 'website_description': quote_template.website_description, 'note': quote_template.note}
def onchange_template_id(self, cr, uid,ids, template_id, context=None): def onchange_template_id(self, cr, uid, ids, template_id, context=None):
data = self._get_sale_order_line(cr, uid, template_id, context) data = self._get_sale_order_line(cr, uid, template_id, context)
return {'value':data} return {'value': data}
def recommended_products(self, cr, uid, ids,context=None): def recommended_products(self, cr, uid, ids, context=None):
order_line = self.browse(cr, uid, ids[0], context=context).order_line order_line = self.browse(cr, uid, ids[0], context=context).order_line
product_pool = self.pool.get('product.product') product_pool = self.pool.get('product.product')
product_ids = [] product_ids = []

View File

@ -12,6 +12,7 @@
<field name="uom_po_id" ref="product.product_uom_unit"/> <field name="uom_po_id" ref="product.product_uom_unit"/>
<field name="description_sale">Learn directly from our team and network of OpenERP experts. Choose from the available training sessions for a better functional understanding of OpenERP</field> <field name="description_sale">Learn directly from our team and network of OpenERP experts. Choose from the available training sessions for a better functional understanding of OpenERP</field>
</record> </record>
<record id="product_product_quote_1" model="product.product"> <record id="product_product_quote_1" model="product.product">
<field name="product_tmpl_id" ref="product_template_quote_1"/> <field name="product_tmpl_id" ref="product_template_quote_1"/>
<field name="default_code">QF11</field> <field name="default_code">QF11</field>
@ -28,6 +29,7 @@
<field name="uom_po_id" ref="product.product_uom_unit"/> <field name="uom_po_id" ref="product.product_uom_unit"/>
<field name="description_sale">Learn directly from our team and network of OpenERP experts. Choose from the available training sessions for a better technical understanding of OpenERP</field> <field name="description_sale">Learn directly from our team and network of OpenERP experts. Choose from the available training sessions for a better technical understanding of OpenERP</field>
</record> </record>
<record id="product_product_quote_2" model="product.product"> <record id="product_product_quote_2" model="product.product">
<field name="product_tmpl_id" ref="product_template_quote_2"/> <field name="product_tmpl_id" ref="product_template_quote_2"/>
<field name="default_code">QF12</field> <field name="default_code">QF12</field>
@ -44,6 +46,7 @@
<field name="uom_po_id" ref="product.product_uom_unit"/> <field name="uom_po_id" ref="product.product_uom_unit"/>
<field name="description_sale">Learn directly from our team and network of OpenERP experts. Choose from the available training sessions for a better functional understanding of OpenERP</field> <field name="description_sale">Learn directly from our team and network of OpenERP experts. Choose from the available training sessions for a better functional understanding of OpenERP</field>
</record> </record>
<record id="product_product_quote_3" model="product.product"> <record id="product_product_quote_3" model="product.product">
<field name="product_tmpl_id" ref="product_template_quote_3"/> <field name="product_tmpl_id" ref="product_template_quote_3"/>
<field name="default_code">QF13</field> <field name="default_code">QF13</field>
@ -60,17 +63,15 @@
<field name="uom_po_id" ref="product.product_uom_unit"/> <field name="uom_po_id" ref="product.product_uom_unit"/>
<field name="description_sale">Learn directly from our team and network of OpenERP experts. Choose from the available training sessions for a better functional understanding of OpenERP</field> <field name="description_sale">Learn directly from our team and network of OpenERP experts. Choose from the available training sessions for a better functional understanding of OpenERP</field>
</record> </record>
<record id="product_product_quote_4" model="product.product"> <record id="product_product_quote_4" model="product.product">
<field name="product_tmpl_id" ref="product_template_quote_4"/> <field name="product_tmpl_id" ref="product_template_quote_4"/>
<field name="default_code">QF14</field> <field name="default_code">QF14</field>
</record> </record>
<record id="website_sale_order_1" model="sale.order">
<field name="partner_id" ref="base.res_partner_2"/> <record id="website_quote_template_1" model="sale.quote.template">
<field name="partner_invoice_id" ref="base.res_partner_2"/> <field name="name">Partnership Contract with Training</field>
<field name="partner_shipping_id" ref="base.res_partner_2"/> <field name="note">The 5-day training is modular, which means that you can choose to participate in the full training or to just 1 or 2 modules. Nevertheless, the first day of the training is compulsory for everyone. The Monday is compulsory because the introduction of OpenERP is important before going through the other modules.</field>
<field name="user_id" ref="base.user_demo"/>
<field name="pricelist_id" ref="product.list0"/>
<field name="is_template" eval="True"/>
<field name="website_description" type="html"> <field name="website_description" type="html">
<section id="whatsuit" class="tab-pane active oe_section jumbotron"> <section id="whatsuit" class="tab-pane active oe_section jumbotron">
<div class="container panel panel-default tab-pane active oe_section"> <div class="container panel panel-default tab-pane active oe_section">
@ -106,7 +107,7 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Untitled"> <form string="Untitled">
<group col="6" colspan="4"> <group col="6" colspan="4">
</group> </group>
</form> </form>
</field> </field>
@ -145,13 +146,13 @@
</div> </div>
<div class="col-md-8 col-md-offset-2 mb32 text-center"> <div class="col-md-8 col-md-offset-2 mb32 text-center">
<p> <p>
As a partner, you get a big discount on OpenERP Enterprise. As a partner, you get a big discount on OpenERP Enterprise.
This allows you to offer reduced prices to your customers and/or This allows you to offer reduced prices to your customers and/or
to benefit from a commission on every subscription you sell to your customers. to benefit from a commission on every subscription you sell to your customers.
</p> </p>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-12 text-center"> <div class="col-xs-12 col-md-12 text-center">
<h2><strong>Benefit From A Dedicated Account Manager</strong></h2> <h2><strong>Benefit From A Dedicated Account Manager</strong></h2>
<h3><small>Our role is to help you succeed</small></h3> <h3><small>Our role is to help you succeed</small></h3>
@ -163,28 +164,28 @@
<p>A dedicated account manager is assigned to every partner to help develop the OpenERP business. The account manager helps you get leads, close deals, gives you feedback and best practices, delivers sales training and is a direct point of contact for any request you may have.</p> <p>A dedicated account manager is assigned to every partner to help develop the OpenERP business. The account manager helps you get leads, close deals, gives you feedback and best practices, delivers sales training and is a direct point of contact for any request you may have.</p>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-12 text-center"> <div class="col-xs-12 col-md-12 text-center">
<h2><strong>Get access to our consultants and technical experts</strong></h2> <h2><strong>Get access to our consultants and technical experts</strong></h2>
<h3><small>Get access to experts for an extra fee</small></h3> <h3><small>Get access to experts for an extra fee</small></h3>
<p>For an extra fee, partners can get access to OpenERP's core developers and functional experts. This can help you succeed in delivering more complex or bigger projects by getting the support of highly experienced consultants on demand.</p> <p>For an extra fee, partners can get access to OpenERP's core developers and functional experts. This can help you succeed in delivering more complex or bigger projects by getting the support of highly experienced consultants on demand.</p>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-12 text-center"> <div class="col-xs-12 col-md-12 text-center">
<h2><strong>Get recognition as an official certified partner</strong></h2> <h2><strong>Get recognition as an official certified partner</strong></h2>
<h3><small>We give you visibility in our official partner list</small></h3> <h3><small>We give you visibility in our official partner list</small></h3>
<p>OpenERP promotes its partners through various ways: publication on our website, official communication, publication of your success stories, etc. As soon as you become an OpenERP partner and have followed the official trainings, you will be visible on the partner directory listing.</p> <p>OpenERP promotes its partners through various ways: publication on our website, official communication, publication of your success stories, etc. As soon as you become an OpenERP partner and have followed the official trainings, you will be visible on the partner directory listing.</p>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-12 text-center"> <div class="col-xs-12 col-md-12 text-center">
<h2><strong>Access to the Lead Generation Program</strong></h2> <h2><strong>Access to the Lead Generation Program</strong></h2>
<h3><small>We give you visibility in our official partner list</small></h3> <h3><small>We give you visibility in our official partner list</small></h3>
<p>Every year, we redirect more than 100,000 customer requests to our official partners. These are prospects that filled a form on the OpenERP website and wanted to use OpenERP. The right partner to fulfill the customer request is selected based on the customer localization (nearest partner) and the grade of the partner..</p> <p>Every year, we redirect more than 100,000 customer requests to our official partners. These are prospects that filled a form on the OpenERP website and wanted to use OpenERP. The right partner to fulfill the customer request is selected based on the customer localization (nearest partner) and the grade of the partner..</p>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-12 text-center"> <div class="col-xs-12 col-md-12 text-center">
<h2><strong>Benefit from the OpenERP branding</strong></h2> <h2><strong>Benefit from the OpenERP branding</strong></h2>
<h3><small>Get rights to use the OpenERP trademark</small></h3> <h3><small>Get rights to use the OpenERP trademark</small></h3>
@ -230,7 +231,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-12 text-center"> <div class="col-xs-12 col-md-12 text-center">
<h2><strong>Get access to online training materials</strong></h2> <h2><strong>Get access to online training materials</strong></h2>
<h3><small>Train yourself on every new release using online videosGet rights to use the OpenERP trademark</small></h3> <h3><small>Train yourself on every new release using online videosGet rights to use the OpenERP trademark</small></h3>
@ -246,7 +247,7 @@
<p>As you go through your first implementation of an OpenERP system it is normal to need some support. We are here to answer your questions regarding the functionality of the software, or how to configure the solution. Each partner is entitled to a certain number of support hours thanks to his or her partner program.</p> <p>As you go through your first implementation of an OpenERP system it is normal to need some support. We are here to answer your questions regarding the functionality of the software, or how to configure the solution. Each partner is entitled to a certain number of support hours thanks to his or her partner program.</p>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-12 text-center"> <div class="col-xs-12 col-md-12 text-center">
<h2><strong>Get technical support services</strong></h2> <h2><strong>Get technical support services</strong></h2>
<h3><small>We help your developers with bugs or support questions</small></h3> <h3><small>We help your developers with bugs or support questions</small></h3>
@ -259,7 +260,7 @@
<p>The OpenERP Support Team is 100% dedicated to helping our customers. You can contact the Support Team for any functional or technical questions and issues with regard to OpenERP development. They can help you develop custom modules.</p> <p>The OpenERP Support Team is 100% dedicated to helping our customers. You can contact the Support Team for any functional or technical questions and issues with regard to OpenERP development. They can help you develop custom modules.</p>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-12 text-center"> <div class="col-xs-12 col-md-12 text-center">
<h2><strong>Test all your developments automatically</strong></h2> <h2><strong>Test all your developments automatically</strong></h2>
<h3><small>Your dedicated test integration platform</small></h3> <h3><small>Your dedicated test integration platform</small></h3>
@ -321,13 +322,11 @@
</field> </field>
</record> </record>
<record id="website_sale_order_line_1" model="sale.order.line"> <record id="website_sale_order_line_1" model="sale.quote.line">
<field name="order_id" ref="website_sale_order_1"/> <field name="quote_id" ref="website_quote_template_1"/>
<field name="name">Fuctional Training</field> <field name="name">Fuctional Training</field>
<field name="product_id" ref="product_product_quote_1"/> <field name="product_id" ref="product_product_quote_1"/>
<field name="product_uom_qty">1</field> <field name="product_uom_qty">1</field>
<field name="product_uos_qty">1</field>
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">12950.00</field> <field name="price_unit">12950.00</field>
<field name="website_description" type="html"> <field name="website_description" type="html">
<section data-snippet-id="text-image" class="tab-pane oe_section jumbotron"> <section data-snippet-id="text-image" class="tab-pane oe_section jumbotron">
@ -366,13 +365,11 @@
</field> </field>
</record> </record>
<record id="website_sale_order_line_2" model="sale.order.line"> <record id="website_sale_order_line_2" model="sale.quote.line">
<field name="order_id" ref="website_sale_order_1"/> <field name="quote_id" ref="website_quote_template_1"/>
<field name="name">Technical Training</field> <field name="name">Technical Training</field>
<field name="product_id" ref="product_product_quote_2"/> <field name="product_id" ref="product_product_quote_2"/>
<field name="product_uom_qty">1</field> <field name="product_uom_qty">1</field>
<field name="product_uos_qty">1</field>
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">00.00</field> <field name="price_unit">00.00</field>
<field name="website_description" type="html"> <field name="website_description" type="html">
<section id="whatsuit" class="tab-pane active oe_section jumbotron"> <section id="whatsuit" class="tab-pane active oe_section jumbotron">
@ -406,15 +403,5 @@
</section> </section>
</field> </field>
</record> </record>
<record id="sale_order_2" model="sale.order">
<field name="partner_id" ref="base.res_partner_7"/>
<field name="partner_invoice_id" ref="base.res_partner_address_13"/>
<field name="partner_shipping_id" ref="base.res_partner_address_13"/>
<field name="user_id" ref="base.user_root"/>
<field name="pricelist_id" ref="product.list0"/>
<field name="order_policy">manual</field>
</record>
</data> </data>
</openerp> </openerp>

View File

@ -6,33 +6,89 @@
<field name="model">sale.order</field> <field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/> <field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//button[@name='action_quotation_send']" position="replace">
<button name="action_quotation_send" string="Send by Email" type="object" class="oe_highlight" groups="base.group_user" attrs="{'invisible': ['|',('is_template', '=', True),('state','!=','draft')]}"/>
</xpath>
<xpath expr="//button[@string='Print'][@states='draft']" position="replace">
<button name="print_quotation" string="Print" type="object" class="oe_highlight" groups="base.group_user" attrs="{'invisible': ['|',('is_template', '=', True),('state','!=','draft')]}"/>
</xpath>
<xpath expr="//button[@string='Confirm Sale'][@states='draft']" position="replace">
<button name="action_button_confirm" string="Confirm Sale" type="object" groups="base.group_user" attrs="{'invisible': ['|',('is_template', '=', True),('state','!=','draft')]}"/>
</xpath>
<xpath expr="//button[@string='Cancel Quotation']" position="replace">
<button name="cancel" string="Cancel Quotation" groups="base.group_user" attrs="{'invisible': ['|',('is_template', '=', True),('state','not in',('draft','sent'))]}"/>
</xpath>
<xpath expr="//header" position="after"> <xpath expr="//header" position="after">
<div class="oe_form_box_info oe_text_center" attrs="{'invisible': ['|',('quote_url', '=', False),('template_id','=',False)]}"> <div class="oe_form_box_info oe_text_center" attrs="{'invisible': ['|',('quote_url', '=', False),('template_id','=',False)]}">
<field name="quote_url" widget="url"/> <field name="quote_url" widget="url"/>
</div> </div>
</xpath> </xpath>
<xpath expr="//field[@name='client_order_ref']" position="after"> <xpath expr="//field[@name='client_order_ref']" position="after">
<field name="is_template"/> <field name="template_id" on_change="onchange_template_id(template_id)"/>
<field name="template_id" domain ="[('is_template','=',True)]" attrs="{'invisible': [('is_template', '=', True)]}" on_change="onchange_template_id(template_id)"/>
</xpath>
<xpath expr="//notebook" position="inside">
<page string="Introduction">
<field name="website_description"/>
</page>
</xpath> </xpath>
</field> </field>
</record> </record>
<record model="ir.ui.view" id="view_sale_quote_template_form">
<field name="name">sale.quote.template.form</field>
<field name="model">sale.quote.template</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Sale Quotation Template" version="7.0">
<sheet>
<h1>
<label string="Quotation Template"/>
<field name="name"/>
</h1>
<notebook>
<page string="Quote Lines">
<field name="quote_line">
<form string="Sales Quote Template Lines" version="7.0">
<group>
<group>
<field name="product_id" on_change="on_change_product_id(product_id)"/>
<label for="product_uom_qty"/>
<div>
<field
name="product_uom_qty" class="oe_inline"/>
</div>
<field name="price_unit"/>
</group>
</group>
<notebook colspan="4">
<page string="Description">
<field name="name" />
</page>
<page string="Website Description">
<field name="website_description" />
</page>
</notebook>
</form>
<tree string="Sales Quote Template Lines" editable="bottom">
<field name="product_id" on_change="on_change_product_id(product_id)"/>
<field name="name"/>
<field name="product_uom_qty"/>
<field name="price_unit"/>
</tree>
</field>
</page>
<page string="Website Description">
<field name="website_description"/>
</page>
<page string="Terms &amp; Conditions">
<field name="note" placeholder="Terms and conditions..."/>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record model="ir.ui.view" id="view_sale_quote_template_tree">
<field name="name">sale.quote.template.tree</field>
<field name="model">sale.quote.template</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Sale Quote Template">
<field name="name"/>
</tree>
</field>
</record>
<record id="action_sale_quotation_template" model="ir.actions.act_window">
<field name="name">Quote Template</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">sale.quote.template</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem action="action_sale_quotation_template" id="menu_sale_quote_template" parent="base.menu_base_config" sequence="6" groups="base.group_sale_salesman,base.group_sale_manager"/>
</data> </data>
</openerp> </openerp>

View File

@ -1,13 +1,12 @@
body { padding-top:30px; body { padding-top:30px; }
} .panel-chatter .panel-body { padding:0px; }
.widget .panel-body { padding:0px; } .panel-chatter .list-group { margin-bottom: 0; }
.widget .list-group { margin-bottom: 0; } .panel-chatter .panel-title { display:inline }
.widget .panel-title { display:inline } .panel-chatter .label-info { float: right; }
.widget .label-info { float: right; } .panel-chatter li.list-group-item {border-radius: 0;border: 0;border-top: 1px solid #ddd;}
.widget li.list-group-item {border-radius: 0;border: 0;border-top: 1px solid #ddd;} .panel-chatter li.list-group-item:hover { background-color: rgba(86,61,124,.1); }
.widget li.list-group-item:hover { background-color: rgba(86,61,124,.1); } .panel-chatter .mic-info { color: #666666;font-size: 11px; }
.widget .mic-info { color: #666666;font-size: 11px; } .panel-chatter .action { margin-top:5px; }
.widget .action { margin-top:5px; } .panel-chatter .comment-text { font-size: 12px; }
.widget .comment-text { font-size: 12px; } .panel-chatter .btn-block { border-top-left-radius:0px;border-top-right-radius:0px; }
.widget .btn-block { border-top-left-radius:0px;border-top-right-radius:0px; }
.oe_section { padding-top:40px; } .oe_section { padding-top:40px; }

View File

@ -8,9 +8,9 @@ $(document).ready(function () {
console.log(line_id); console.log(line_id);
openerp.jsonRpc("/quote/update_line/", 'call', { openerp.jsonRpc("/quote/update_line/", 'call', {
'line_id': line_id[1], 'line_id': line_id[1],
'order_id':parseInt(order_id[1]), 'order_id': parseInt(order_id[1]),
'remove': $link.is('[href*="remove"]'), 'remove': $link.is('[href*="remove"]'),
'unlink': $link.is('[href*="unlink"]'), 'unlink': $link.is('[href*="unlink"]')
}) })
.then(function (data) { .then(function (data) {
if(!data){ if(!data){

View File

@ -29,7 +29,6 @@
<meta name="keywords" t-att-value="main_object and 'website_meta_keywords' in main_object <meta name="keywords" t-att-value="main_object and 'website_meta_keywords' in main_object
and main_object.website_meta_keywords or website_meta_keywords"/> and main_object.website_meta_keywords or website_meta_keywords"/>
<!-- Load stylesheets before scripts to avoid blocking -->
<link rel='stylesheet' href='/web/static/lib/fontawesome/css/font-awesome.css'/> <link rel='stylesheet' href='/web/static/lib/fontawesome/css/font-awesome.css'/>
<t t-if="editable"> <t t-if="editable">
<link rel='stylesheet' href='/website/static/src/css/snippets.css'/> <link rel='stylesheet' href='/website/static/src/css/snippets.css'/>
@ -166,7 +165,7 @@
</a> </a>
</li> </li>
<li> <li>
<a type="submit" t-if="quotation.state != 'cancel'" t-href="/quote/#{ quotation.id }/decline"> <a href="#" class="btn" t-if="quotation.state != 'cancel'" id="cancelQuotation">
<span class="fa-stack"> <span class="fa-stack">
<i class="fa fa-circle fa-stack-2x" style="color:#d9534f;"></i> <i class="fa fa-circle fa-stack-2x" style="color:#d9534f;"></i>
<i class="fa fa-times fa-stack-1x fa-inverse"></i> <i class="fa fa-times fa-stack-1x fa-inverse"></i>
@ -180,7 +179,7 @@
<i class="fa fa-circle fa-stack-2x" style="color:#428bca;"></i> <i class="fa fa-circle fa-stack-2x" style="color:#428bca;"></i>
<i class="fa fa-comment fa-stack-1x fa-inverse"></i> <i class="fa fa-comment fa-stack-1x fa-inverse"></i>
</span>Discuss </span>Discuss
<sup class="label label-info"><t t-esc="total_mail"/></sup> <sup class="label label-info"><t t-esc="len(quotation.message_ids)"/></sup>
</a> </a>
</li> </li>
</ul> </ul>
@ -188,7 +187,7 @@
</div> </div>
</template> </template>
<template id="chatter"> <template id="chatter">
<div id="chat" class="panel panel-default widget"> <div id="chat" class="panel panel-default panel-chatter">
<div class="panel-heading"> <div class="panel-heading">
<span class="glyphicon glyphicon-comment"></span> <span class="glyphicon glyphicon-comment"></span>
<h3 class="panel-title">Recent Comments</h3> <h3 class="panel-title">Recent Comments</h3>
@ -196,23 +195,21 @@
<div class="panel-body"> <div class="panel-body">
<ul class="list-group"> <ul class="list-group">
<t t-foreach="quotation.message_ids" t-as="message"> <t t-foreach="quotation.message_ids" t-as="message">
<t t-if="message.type == 'email'"> <li class="list-group-item">
<li class="list-group-item"> <div class="row">
<div class="row"> <div class="col-xs-2 col-md-1">
<div class="col-xs-2 col-md-1"> <img t-att-src="'data:image/png;base64,' + message.author_id.image_small" class="img-circle img-responsive" alt="" /></div>
<img t-att-src="'data:image/png;base64,' + message.author_id.image_small" class="img-circle img-responsive" alt="" /></div> <div class="col-xs-10 col-md-11">
<div class="col-xs-10 col-md-11"> <div>
<div> <a href="http://www.jquery2dotnet.com/2013/10/google-style-login-page-desing-usign.html"/>
<a href="http://www.jquery2dotnet.com/2013/10/google-style-login-page-desing-usign.html"/> <t t-raw="message.body"/>
<t t-raw="message.body"/> <div class="mic-info">
<div class="mic-info"> By: <a href="#"><t t-esc="message.author_id.name"/></a> on <t t-esc="message.date"/>
By: <a href="#"><t t-esc="message.author_id.name"/></a> on <t t-esc="message.date"/>
</div>
</div> </div>
</div> </div>
</div> </div>
</li> </div>
</t> </li>
</t> </t>
</ul> </ul>
</div> </div>
@ -234,6 +231,7 @@
</section> </section>
</t> </t>
<t t-call="website_sale_quote.pricing"/> <t t-call="website_sale_quote.pricing"/>
<t t-call="website_sale_quote.terms_and_conditions"/>
<t t-call="website_sale_quote.product_recommendation"/> <t t-call="website_sale_quote.product_recommendation"/>
<t t-call="website_sale_quote.chatter"/> <t t-call="website_sale_quote.chatter"/>
</div> </div>
@ -244,6 +242,7 @@
<li><a t-att-href="'#%s'% line.id" data-toggle="tab"><i class="icon-chevron-right"></i><t t-raw="line.product_id.name_template"/> </a></li> <li><a t-att-href="'#%s'% line.id" data-toggle="tab"><i class="icon-chevron-right"></i><t t-raw="line.product_id.name_template"/> </a></li>
</t> </t>
<li><a href="#quote" data-toggle="tab"><i class="icon-chevron-right"></i> Quotation</a></li> <li><a href="#quote" data-toggle="tab"><i class="icon-chevron-right"></i> Quotation</a></li>
<li><a href="#terms" data-toggle="tab"><i class="icon-chevron-right"></i> Terms &amp; Conditions</a></li>
</ul> </ul>
</div> </div>
</t> </t>
@ -263,5 +262,17 @@
</div> </div>
</div> </div>
</template> </template>
<template id="terms_and_conditions" name="Terms &amp; Conditions">
<section id="terms" class="tab-pane oe_section">
<div class="container panel panel-default tab-pane oe_section">
<div class="row panel-body">
<div class="text-center">
<h2><strong>Terms &amp; Conditions</strong></h2>
<p class="lead" t-field="quotation.note"/>
</div>
</div>
</div>
</section>
</template>
</data> </data>
</openerp> </openerp>