diff --git a/addons/website_sale_quote/__openerp__.py b/addons/website_sale_quote/__openerp__.py index da6c2175db3..dd54fa609fa 100644 --- a/addons/website_sale_quote/__openerp__.py +++ b/addons/website_sale_quote/__openerp__.py @@ -9,7 +9,7 @@ OpenERP Sale Quote Roller """, 'author': 'OpenERP SA', - 'depends': ['website_sale','website','product','portal_sale', 'mail'], + 'depends': ['website_sale','portal_sale', 'mail'], 'data': [ 'views/website_sale_quote.xml', 'sale_quote_view.xml', diff --git a/addons/website_sale_quote/controllers/main.py b/addons/website_sale_quote/controllers/main.py index ca77fd5bdc5..fa90883858a 100644 --- a/addons/website_sale_quote/controllers/main.py +++ b/addons/website_sale_quote/controllers/main.py @@ -1,18 +1,33 @@ -import random -import uuid -import simplejson - -import werkzeug.exceptions +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2013-Today OpenERP SA (). +# +# 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 . +# +############################################################################## from openerp import SUPERUSER_ID -from openerp.osv import osv from openerp.addons.web import http from openerp.addons.web.http import request from openerp.addons.website.models import website + class sale_quote(http.Controller): - def get_quote(self, token): + def _get_quote(self, token): order_pool = request.registry.get('sale.order') order_id = order_pool.search(request.cr, SUPERUSER_ID, [('access_token', '=', token)], context=request.context) 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 return user_pool.search(request.cr, SUPERUSER_ID, [('partner_id', '=', partner)])[0] - @website.route(['/quote/','/quote/'], type='http', auth="public") + @website.route(['/quote/', '/quote/'], type='http', auth="public") def view(self, token=None, order_id=None, **post): values = {} order_pool = request.registry.get('sale.order') 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) - render_template = 'website_sale_quote.so_quotation' values.update({ - 'quotation' : quotation, - 'total_mail' : len(order_pool.search(request.cr, request.uid,[('id','=',order_id),('message_ids.type', '=', 'email')], context=request.context)), + 'quotation': quotation, }) - return request.website.render(render_template, values) + return request.website.render('website_sale_quote.so_quotation', values) @website.route(['/quote//accept'], type='http', auth="public") def accept(self, order_id=None, **post): - values = {} - quotation = request.registry.get('sale.order').write(request.cr, SUPERUSER_ID, [order_id], {'state': 'manual'}) + request.registry.get('sale.order').write(request.cr, SUPERUSER_ID, [order_id], {'state': 'manual'}) return request.redirect("/quote/%s" % self._get_token(order_id)) @website.route(['/quote//decline'], type='http', auth="public") def decline(self, order_id=None, **post): - values = {} - quotation = request.registry.get('sale.order').write(request.cr, SUPERUSER_ID, [order_id], {'state': 'cancel'}) + request.registry.get('sale.order').write(request.cr, SUPERUSER_ID, [order_id], {'state': 'cancel'}) return request.redirect("/quote/%s" % self._get_token(order_id)) @website.route(['/quote//post'], type='http', auth="public") def post(self, order_id=None, **post): - values = {} if post.get('new_message'): request.session.body = post.get('new_message') 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") def update(self, line_id=None, remove=False, unlink=False, order_id=None, **post): if unlink: - request.registry.get('sale.order.line').unlink(request.cr, SUPERUSER_ID,[int(line_id)], context=request.context) - return - else: - val = self._update_order_line(line_id=int(line_id), number=(remove and -1 or 1)) + return request.registry.get('sale.order.line').unlink(request.cr, SUPERUSER_ID, [int(line_id)], context=request.context) + 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) - 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_val = order_line_obj.read(request.cr, SUPERUSER_ID, [int(line_id)], [], context=request.context)[0] 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 diff --git a/addons/website_sale_quote/models/order.py b/addons/website_sale_quote/models/order.py index c3a8d81c7fe..5334499079e 100644 --- a/addons/website_sale_quote/models/order.py +++ b/addons/website_sale_quote/models/order.py @@ -23,87 +23,130 @@ from openerp.osv import osv, fields import hashlib 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): _inherit = "sale.order.line" _description = "Sales Order Line" _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): - 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) + 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) if product: desc = self.pool.get('product.product').browse(cr, uid, product, context).website_description res.get('value').update({'website_description': desc}) return res + class sale_order(osv.osv): _inherit = 'sale.order' _columns = { 'quote_url': fields.char('URL', readonly=True), - 'access_token':fields.char('Quotation Token', size=256), - 'template_id': fields.many2one('sale.order','Quote Template'), + 'access_token': fields.char('Quotation Token', size=256), + 'template_id': fields.many2one('sale.quote.template', 'Quote Template'), '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') - quotation_token = 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)} ) + return hashlib.sha256('%s-%s-%s' % (time.time(), db_uuid, ids[0])).hexdigest() 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) - 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 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) - self.new_quotation_token(cr, uid, ids,context) 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)]) user_wizard_pool = self.pool.get('portal.wizard.user') - order = self.browse(cr, uid, order_id, context=context) - 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,{ - 'wizard_id':wizard_id, - 'partner_id':order.partner_id.id, - 'email':order.partner_id.email, - 'in_portal':True} ) - return user_wizard_pool.action_apply(cr, uid, [user_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}) + user.append(user_wizard_pool.create(cr, uid, { + 'wizard_id': wizard_id, + 'partner_id': order.partner_id.id, + 'email': order.partner_id.email, + 'in_portal': True})) + 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): 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 - def _get_sale_order_line(self, cr, uid,template_id, context=None): - line_pool = self.pool.get('sale.order.line') + def _get_sale_order_line(self, cr, uid, template_id, context=None): + """create order line from selected quote template line.""" lines = [] - order_template = self.browse(cr, uid, template_id, context) - for line in order_template.order_line: - lines.append((0,0,{ + quote_template = self.pool.get('sale.quote.template').browse(cr, uid, template_id, context) + for line in quote_template.quote_line: + lines.append((0, 0, { 'name': line.name, - 'sequence': line.sequence, 'price_unit': line.price_unit, 'product_uom_qty': line.product_uom_qty, - 'discount': line.discount, 'product_id': line.product_id.id, - 'tax_id': [(6, 0, [x.id for x in line.tax_id])], - 'website_description':line.website_description, - 'state':'draft', + 'website_description': line.website_description, + '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) - 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 product_pool = self.pool.get('product.product') product_ids = [] diff --git a/addons/website_sale_quote/sale_quote_demo.xml b/addons/website_sale_quote/sale_quote_demo.xml index 85acb0dd55d..a53cbf3023c 100644 --- a/addons/website_sale_quote/sale_quote_demo.xml +++ b/addons/website_sale_quote/sale_quote_demo.xml @@ -12,6 +12,7 @@ Learn directly from our team and network of OpenERP experts. Choose from the available training sessions for a better functional understanding of OpenERP + QF11 @@ -28,6 +29,7 @@ Learn directly from our team and network of OpenERP experts. Choose from the available training sessions for a better technical understanding of OpenERP + QF12 @@ -44,6 +46,7 @@ Learn directly from our team and network of OpenERP experts. Choose from the available training sessions for a better functional understanding of OpenERP + QF13 @@ -60,17 +63,15 @@ Learn directly from our team and network of OpenERP experts. Choose from the available training sessions for a better functional understanding of OpenERP + QF14 - - - - - - - + + + Partnership Contract with Training + 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.
@@ -106,7 +107,7 @@
- +
@@ -145,13 +146,13 @@

- As a partner, you get a big discount on OpenERP Enterprise. - This allows you to offer reduced prices to your customers and/or + As a partner, you get a big discount on OpenERP Enterprise. + 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.

-
+

Benefit From A Dedicated Account Manager

Our role is to help you succeed

@@ -163,28 +164,28 @@

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.

-
+

Get access to our consultants and technical experts

Get access to experts for an extra fee

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.

-
+

Get recognition as an official certified partner

We give you visibility in our official partner list

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.

-
+

Access to the Lead Generation Program

We give you visibility in our official partner list

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..

-
+

Benefit from the OpenERP branding

Get rights to use the OpenERP trademark

@@ -230,7 +231,7 @@
-
+

Get access to online training materials

Train yourself on every new release using online videosGet rights to use the OpenERP trademark

@@ -246,7 +247,7 @@

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.

-
+

Get technical support services

We help your developers with bugs or support questions

@@ -259,7 +260,7 @@

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.

-
+

Test all your developments automatically

Your dedicated test integration platform

@@ -321,13 +322,11 @@ - - + + Fuctional Training 1 - 1 - 12950.00
@@ -366,13 +365,11 @@ - - + + Technical Training 1 - 1 - 00.00
@@ -406,15 +403,5 @@
- - - - - - - - manual - - diff --git a/addons/website_sale_quote/sale_quote_view.xml b/addons/website_sale_quote/sale_quote_view.xml index 4d522f45fec..c10701ead7e 100644 --- a/addons/website_sale_quote/sale_quote_view.xml +++ b/addons/website_sale_quote/sale_quote_view.xml @@ -6,33 +6,89 @@ sale.order - -
+