[MERGE]Merge lp:~openerp-dev/openobject-addons/trunk-website-al.

bzr revid: bth@tinyerp.com-20130816062420-4a04olf1ulf2v4vy
This commit is contained in:
bth-openerp
2013-08-16 11:54:20 +05:30
57 changed files with 3277 additions and 1413 deletions
+130 -6
View File
@@ -29,14 +29,17 @@ class product(osv.osv):
'event_type_id': fields.many2one('event.type', 'Type of Event', help='Select event types so when we use this product in sales order lines, it will filter events of this type only.'),
}
def onchange_event_ok(self, cr, uid, ids, event_ok, context=None):
return {'value': {'type': event_ok and 'service' or False}}
def onchange_event_ok(self, cr, uid, ids, type, event_ok, context=None):
return {'value': {'type': event_ok and 'service' or type != 'service' and type or False}}
class sale_order_line(osv.osv):
_inherit = 'sale.order.line'
_columns = {
'event_id': fields.many2one('event.event', 'Event', help="Choose an event and it will automatically create a registration for this event."),
'event_id': fields.many2one('event.event', 'Event',
help="Choose an event and it will automatically create a registration for this event."),
'event_ticket_id': fields.many2one('event.event.ticket', 'Event Ticket',
help="Choose an event ticket and it will automatically create a registration for this event ticket."),
#those 2 fields are used for dynamic domains and filled by onchange
'event_type_id': fields.related('product_id','event_type_id', type='many2one', relation="event.type", string="Event Type"),
'event_ok': fields.related('product_id', 'event_ok', string='event_ok', type='boolean'),
@@ -73,9 +76,8 @@ class sale_order_line(osv.osv):
if context is None:
context = {}
registration_obj = self.pool.get('event.registration')
sale_obj = self.pool.get('sale.order')
for order_line in self.browse(cr, uid, ids, context=context):
if order_line.event_id.id:
if order_line.event_id:
dic = {
'name': order_line.order_id.partner_invoice_id.name,
'partner_id': order_line.order_id.partner_id.id,
@@ -84,9 +86,131 @@ class sale_order_line(osv.osv):
'phone': order_line.order_id.partner_id.phone,
'origin': order_line.order_id.name,
'event_id': order_line.event_id.id,
'event_ticket_id': order_line.event_ticket_id and order_line.event_ticket_id.id or None,
}
message = _("The registration has been created for event <i>%s</i> from the Sale Order %s. ") % (order_line.event_id.name, order_line.order_id.name)
print dic
if order_line.event_ticket_id:
if order_line.event_ticket_id.register_avail != 9999 and dic['nb_register'] > order_line.event_ticket_id.register_avail:
raise osv.except_osv(_('Error!'), _('There are not enough tickets available (%s) for %s' % (order_line.event_ticket_id.register_avail, order_line.event_ticket_id.name)))
message = _("The registration has been created for event <i>%s</i> with the ticket <i>%s</i> from the Sale Order %s. ") % (order_line.event_id.name, order_line.event_ticket_id.name, order_line.order_id.name)
else:
message = _("The registration has been created for event <i>%s</i> from the Sale Order %s. ") % (order_line.event_id.name, order_line.order_id.name)
context.update({'mail_create_nolog': True})
registration_id = registration_obj.create(cr, uid, dic, context=context)
registration_obj.message_post(cr, uid, [registration_id], body=message, context=context)
return super(sale_order_line, self).button_confirm(cr, uid, ids, context=context)
def onchange_event_ticket_id(self, cr, uid, ids, event_ticket_id=False, context=None):
price = event_ticket_id and self.pool.get("event.event.ticket").browse(cr, uid, event_ticket_id, context=context).price or False
return {'value': {'price_unit': price}}
class event_event(osv.osv):
_inherit = 'event.event'
def _get_register_max(self, cr, uid, ids, field_name, arg, context=None):
result = dict.fromkeys(ids, 0)
for rec in self.browse(cr, uid, ids, context=context):
result[rec.id] = sum([ep.register_max for ep in rec.event_ticket_ids])
return result
_columns = {
'website_published': fields.boolean('Available in the website'),
'description_website': fields.html('Description for the website'),
'event_ticket_ids': fields.one2many('event.event.ticket', "event_id", "Event Ticket"),
'organizer_id': fields.many2one('res.partner', "Orgonizer"),
'phone': fields.related('orgonizer_id', 'phone', type='char', string='Phone'),
'email': fields.related('orgonizer_id', 'email', type='char', string='Email'),
'register_max': fields.function(_get_register_max,
string='Maximum Registrations',
help="The maximum registration level is equal to the sum of the maximum registration of event ticket." +
"If you have too much registrations you are not able to confirm your event. (0 to ignore this rule )",
type='integer', store=True)
}
def check_registration_limits(self, cr, uid, ids, context=None):
for event in self.browse(cr, uid, ids, context=context):
if event.event_ticket_ids:
event.event_ticket_ids.check_registration_limits_before(0)
return super(event_event, self).check_registration_limits(cr, uid, ids, context=context)
class event_ticket(osv.osv):
_name = 'event.event.ticket'
def _get_register(self, cr, uid, ids, fields, args, context=None):
"""Get Confirm or uncofirm register value.
@param ids: List of Event Ticket registration type's id
@param fields: List of function fields(register_current and register_prospect).
@param context: A standard dictionary for contextual values
@return: Dictionary of function fields value.
"""
res = {}
for event in self.browse(cr, uid, ids, context=context):
res[event.id] = {}
reg_open = reg_done = reg_draft =0
for registration in event.registration_ids:
if registration.state == 'open':
reg_open += registration.nb_register
elif registration.state == 'done':
reg_done += registration.nb_register
elif registration.state == 'draft':
reg_draft += registration.nb_register
for field in fields:
number = 0
if field == 'register_current':
number = reg_open
elif field == 'register_attended':
number = reg_done
elif field == 'register_prospect':
number = reg_draft
elif field == 'register_avail':
#the number of ticket is unlimited if the event.register_max field is not set.
#In that cas we arbitrary set it to 9999, it is used in the kanban view to special case the display of the 'subscribe' button
number = event.register_max - reg_open if event.register_max != 0 else 9999
res[event.id][field] = number
return res
_columns = {
'name': fields.char('Name', size=64, required=True),
'event_id': fields.many2one('event.event', "Event", required=True),
'product_id': fields.many2one('product.product', 'Product', required=True, domain=[("event_type_id", "!=", False)]),
'registration_ids': fields.one2many('event.registration', 'event_ticket_id', 'Registrations'),
'deadline': fields.date("Sales End"),
'price': fields.float('Price'),
'register_max': fields.integer('Maximum Registrations'),
'register_current': fields.function(_get_register, string='Current Registrations', type='integer', multi='register_numbers'),
'register_avail': fields.function(_get_register, string='Available Registrations', type='integer', multi='register_numbers'),
'register_prospect': fields.function(_get_register, string='Unconfirmed Registrations', type='integer', multi='register_numbers'),
'register_attended': fields.function(_get_register, string='# of Participations', type='integer', multi='register_numbers'),
}
def check_registration_limits_before(self, cr, uid, ids, number, context=None):
for ticket in self.browse(cr, uid, ids, context=context):
if ticket.register_max:
if not ticket.register_avail:
raise osv.except_osv(_('Warning!'),_('No Tickets Available for "%s"' % ticket.name))
elif number + ticket.register_current > ticket.register_max:
raise osv.except_osv(_('Warning!'), _('There only %d tickets available for "%s"' % (ticket.register_avail, ticket.name)))
return True
def onchange_product_id(self, cr, uid, ids, product_id=False, context=None):
return {'value': {'price': self.pool.get("product.product").browse(cr, uid, product_id).list_price or 0}}
class event_registration(osv.osv):
"""Event Registration"""
_inherit= 'event.registration'
_columns = {
'event_ticket_id': fields.many2one('event.event.ticket', 'Event Ticket'),
}
def registration_open(self, cr, uid, ids, context=None):
""" Open Registration
"""
for registration in self.browse(cr, uid, ids, context=context):
if registration.event_ticket_id:
registration.event_ticket_id.check_registration_limits_before(1)
return super(event_registration, self).registration_open(cr, uid, ids, context=context)
+31 -1
View File
@@ -7,7 +7,7 @@
<field name="inherit_id" ref="product.product_normal_form_view" />
<field name="arch" type="xml">
<div name="options" position="inside">
<field name="event_ok" on_change="onchange_event_ok(event_ok, context)"/>
<field name="event_ok" on_change="onchange_event_ok(type, event_ok, context)"/>
<label for="event_ok"/>
</div>
<div name='ean' position="after">
@@ -23,6 +23,8 @@
<field name="arch" type="xml">
<xpath expr="//field[@name='product_id']" position="after">
<field name="event_id" domain="['|', ('type','=', False),('type', '=', event_type_id)]" attrs="{'invisible': [('event_ok', '=', False)],'required': [('event_ok', '!=', False)]}"/>
<field name="event_ticket_id" domain="[('event_id', '=', event_id), ('register_avail', '>', 0)]" attrs="{'invisible': [('event_id', '=', False)]}"
on_change="onchange_event_ticket_id(event_ticket_id, context)"/>
<field name="event_type_id" invisible="1"/>
<field name="event_ok" invisible="1"/>
</xpath>
@@ -34,5 +36,33 @@
<field name="groups_id" eval="[(4, ref('event.group_event_user'))]"/>
</record>
<record id="view_event_form" model="ir.ui.view">
<field name="name">view_event_form</field>
<field name="model">event.event</field>
<field name="inherit_id" ref="event.view_event_form"/>
<field name="arch" type="xml">
<data>
<xpath expr="//notebook" position="inside">
<page string="Tarifs">
<field name="event_ticket_ids" context="{'default_name': name}">
<tree string="Payments" editable="bottom">
<field name="name"/>
<field name="product_id" on_change='onchange_product_id(product_id)'/>
<field name="deadline"/>
<field name="price"/>
<field name="register_max"/>
<field name="register_current"/>
<field name="register_prospect"/>
</tree>
</field>
</page>
</xpath>
<field name="address_id" position="after">
<field name="organizer_id"/>
</field>
</data>
</field>
</record>
</data>
</openerp>
@@ -0,0 +1,115 @@
<section class="oe_container">
<div class="oe_row oe_spaced">
<div class="oe_span12">
<h2 class="oe_slogan">Open Source Job Board</h2>
<h3 class="oe_slogan">Organize your job postings and applications</h3>
</div>
<div class="oe_span6">
<div class="oe_demo oe_picture oe_screenshot">
<a href="https://www.openerp.com/saas_master/demo?lang=en_US&module=website_hr">
<img src="">
</a>
<div class="oe_demo_footer oe_centeralign">Online Demo</div>
</div>
</div>
<div class="oe_span6">
<p class='oe_mt32'>
Organize your job board, promote your job announces and keep
track of application submissions easily. Follow every applicant
and build up a database of skills and profiles with indexed
documents.
</p>
<div class="oe_centeralign oe_websiteonly">
<a href="http://www.openerp.com/start?app=website_hr" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> online store</a>
</div>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row">
<h2 class="oe_slogan">Post Your Jobs on Best Job Boards</h2>
<h3 class="oe_slogan">LinkedIn, Monster, Kraigslist, Careerbuilder,...</h3>
<div class="oe_span6">
<img class="oe_picture oe_screenshot" src="">
</div>
<div class="oe_span6">
<p class='oe_mt32'>
Connect automatically to most famous job board websites;
linkedIn, Monster, Kraigslist, ... Every job position has a new
email address automatically assigned to route applications
automatically to the right job position.
</p><p>
Whether applicants contact you by email or using an online
form, you get all the data indexed automatically (resumes,
motivation letter) and you can answer in just a click, reusing
templates of answers.
</p>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row">
<h2 class="oe_slogan">Customize Your Recruitment Process</h2>
<h3 class="oe_slogan">Define your own stages and interviewers</h3>
<div class="oe_span6">
<p class='oe_mt32'>
Use the kanban view and customize the steps of your recruitments
process; pre-qualification, first interview, second interview,
negociaiton, ...
</p><p>
Get accurate statistics on your recruitment pipeline. Get reports
to compare the performance of your different investments on
external job boards.
</p>
</div>
<div class="oe_span6">
<img class="oe_picture oe_screenshot" src="">
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row">
<h2 class="oe_slogan">Streamline Your Recruitment Process</h2>
<h3 class="oe_slogan">Index resumes, track applicants, search profiles</h3>
<div class="oe_span6">
<img class="oe_picture oe_screenshot" src="hr_recruitment.png">
</div>
<div class="oe_span6">
<p class='oe_mt32'>
Follow applicants in your recruitment process with the smart
kanban view. Save time by automating some communications with
email templates.
</p><p>
Documents like resumes and motivation letters are indexed
automatically, allowing you to easily find for specific skills
and build up a database of profiles.
</p>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row">
<h2 class="oe_slogan">Integrated Surveys</h2>
<h3 class="oe_slogan">Define your own online or offline surveys</h3>
<div class="oe_span6">
<div class="oe_bg_img">
<img class="oe_picture" src="">
</div>
</div>
<div class="oe_span6">
<p class='oe_mt32'>
Create your own interview canvas based on our best practices.
Use the survey designer to adapt questions to your own process.
Ask the applicant to fill in the survey online, or the
interviewer to use it during real interviews.
</p>
</div>
</div>
</section>
@@ -42,7 +42,6 @@ allowing teams to optimize their job.
<div class="oe_span4 ">
<h3>Gantt Charts</h3>
<img class="oe_picture oe_screenshot" src="project_gantt.png">
</p>
</div>
<div class="oe_span4 ">
<h3>Calendar</h3>
+3 -1
View File
@@ -1,3 +1,5 @@
import controllers
import res_config
from website import website
from website import website
import view
+2 -9
View File
@@ -1,6 +1,7 @@
{
'name': 'Website',
'category': 'CMS',
'category': 'Website',
'summary': 'Create Your Enterprise Website',
'version': '1.0',
'description': """
OpenERP Website CMS
@@ -14,13 +15,5 @@ OpenERP Website CMS
'views/views.xml',
'views/res_config.xml',
'website_data.xml',
],
'js': [
'static/lib/bootstrap/js/bootstrap.js',
'static/src/js/website.js',
],
'css': [
'static/src/css/editor.css',
],
'qweb': ['static/src/xml/*.xml'],
}
+105 -4
View File
@@ -2,21 +2,31 @@
import base64
import json
import logging
import urllib
import cStringIO
from PIL import Image, ImageOps
from PIL import Image
import openerp
from openerp.addons.web import http
from openerp.addons.web.controllers.main import manifest_list
from openerp.addons.web.http import request
import werkzeug
import werkzeug.exceptions
import werkzeug.wrappers
import hashlib
import os
logger = logging.getLogger(__name__)
def auth_method_public():
registry = openerp.modules.registry.RegistryManager.get(request.db)
if not request.session.uid:
request.uid = registry['website'].get_public_user().id
else:
request.uid = request.session.uid
http.auth_methods['public'] = auth_method_public
class Website(openerp.addons.web.controllers.main.Home):
@http.route('/', type='http', auth="admin")
def index(self, **kw):
@@ -52,7 +62,7 @@ class Website(openerp.addons.web.controllers.main.Home):
return werkzeug.utils.redirect("/page/%s" % path)
@http.route('/page/<path:path>', type='http', auth="admin")
def page(self, path):
def page(self, path, **kwargs):
website = request.registry.get("website")
values = website.get_rendering_context({
'path': path
@@ -63,6 +73,45 @@ class Website(openerp.addons.web.controllers.main.Home):
html = website.render('website.404', values)
return html
@http.route('/website/customize_template_toggle', type='json', auth='admin') # FIXME: auth
def customize_template_set(self, view_id):
view_obj = request.registry.get("ir.ui.view")
view = view_obj.browse(request.cr, request.uid, int(view_id), context=request.context)
if view.inherit_id:
print '*', view.inherit_id
value = False
else:
value = view.inherit_option_id and view.inherit_option_id.id or False
print '*', view.inherit_id, 'no', value, view
view_obj.write(request.cr, request.uid, [view_id], {
'inherit_id': value
}, context=request.context)
print 'Wrote', value, 'on', view_id
return True
@http.route('/website/customize_template_get', type='json', auth='admin') # FIXME: auth
def customize_template_get(self, xml_id):
view = request.registry.get("ir.ui.view")
views = view._views_get(request.cr, request.uid, xml_id, request.context)
done = {}
result = []
for v in views:
if v.inherit_option_id:
if v.inherit_option_id.id not in done:
result.append({
'name': v.inherit_option_id.name,
'header': True,
'active': False
})
done[v.inherit_option_id.id] = True
result.append({
'name': v.name,
'id': v.id,
'header': False,
'active': v.inherit_id.id == v.inherit_option_id.id
})
return result
@http.route('/website/attach', type='http', auth='admin') # FIXME: auth
def attach(self, CKEditorFuncNum, CKEditor, langCode, upload):
req = request.httprequest
@@ -107,4 +156,56 @@ class Website(openerp.addons.web.controllers.main.Home):
return response
@http.route('/website/image', type='http', auth="public")
def image(self, model, id, field, **kw):
last_update = '__last_update'
Model = request.registry[model]
headers = [('Content-Type', 'image/png')]
etag = request.httprequest.headers.get('If-None-Match')
hashed_session = hashlib.md5(request.session_id).hexdigest()
retag = hashed_session
try:
if etag:
date = Model.read(request.cr, request.uid, [id], [last_update], request.context)[0].get(last_update)
if hashlib.md5(date).hexdigest() == etag:
return werkzeug.wrappers.Response(status=304)
res = Model.read(request.cr, request.uid, [id], [last_update, field], request.context)[0]
retag = hashlib.md5(res.get(last_update)).hexdigest()
image_base64 = res.get(field)
if kw.get('resize'):
resize = kw.get('resize').split(',')
if len(resize) == 2 and int(resize[0]) and int(resize[1]):
width = int(resize[0])
height = int(resize[1])
# resize maximum 500*500
if width > 500: width = 500
if height > 500: height = 500
image_base64 = openerp.tools.image_resize_image(base64_source=image_base64, size=(width, height), encoding='base64', filetype='PNG')
image_data = base64.b64decode(image_base64)
except Exception:
image_data = open(os.path.join(http.addons_manifest['web']['addons_path'], 'web', 'static', 'src', 'img', 'placeholder.png'), 'rb').read()
headers.append(('ETag', retag))
headers.append(('Content-Length', len(image_data)))
try:
ncache = int(kw.get('cache'))
headers.append(('Cache-Control', 'no-cache' if ncache == 0 else 'max-age=%s' % (ncache)))
except:
pass
return request.make_response(image_data, headers)
@http.route(['/website/publish/'], type='http', auth="public")
def publish(self, **post):
_id = int(post['id'])
_object = request.registry[post['object']]
obj = _object.browse(request.cr, request.uid, _id)
_object.write(request.cr, request.uid, [_id], {'website_published': not obj.website_published})
obj = _object.browse(request.cr, request.uid, _id)
return obj.website_published and "1" or "0"
# vim:expandtab:tabstop=4:softtabstop=4:shiftwidth=4:
+100 -25
View File
@@ -2,7 +2,7 @@
<div class="oe_row oe_spaced">
<div class="oe_span12">
<h2 class="oe_slogan">Enterprise Website Builder</h2>
<h3 class="oe_slogan">Get an awesome website. Customize easily.</h3>
<h3 class="oe_slogan">Get an awesome website, easily customizable</h3>
</div>
<div class="oe_span6">
<div class="oe_demo oe_picture oe_screenshot">
@@ -14,9 +14,10 @@
</div>
<div class="oe_span6">
<p class='oe_mt32'>
Create enterprise-grade website with our super easy builder; no backend, everything
is editable inline. Benefit from out-of-the-box business features; shop, events, blogs,
jobs announces, "our team" pages, etc.
Create enterprise grade website with our super easy builder; no
backend, everything is editable inline. Benefit from
out-of-the-box business features; ecommerce, events, blogs,
jobs announces, our references, "our team" page, call-to-actions, etc.
</p>
<div class="oe_centeralign oe_websiteonly">
<a href="http://www.openerp.com/start?app=website" class="oe_button oe_big oe_tacky">Create your <span class="oe_emph">free</span> website</a>
@@ -66,6 +67,9 @@ jobs announces, "our team" pages, etc.
Whether it's for products descriptions, blogs or static pages,
you don't need to be a professioanl designer to create modern
and clean web pages.
</p><p>
Get rid of traditional WYSIWYG editors that does not allow to
design clean and mobile friendly pages.
</p>
</div>
</div>
@@ -98,8 +102,53 @@ jobs announces, "our team" pages, etc.
<section class="oe_container">
<div class="oe_row">
<h2 class="oe_slogan">Multi-languages Without Pain</h2>
<h3 class="oe_slogan">Automate updates and transaltions easily</h3>
<h2 class="oe_slogan">A Great Mobile Experience</h2>
<h3 class="oe_slogan">Responsive content on all pages</h3>
<div class="oe_span6">
<div class="oe_bg_img">
<img class="oe_picture oe_screenshot" src="">
</div>
</div>
<div class="oe_span6">
<p class='oe_mt32'>
Get a mobile friendly website thanks to our responsive design
based on bootstrap. The layout of every page and content adapts
automatically to the screen size. (mobile phones, tablets, desktop)
You don't have to worry about mobile contents, it works by default.
<p></p>
Our building blocks allows to reuse responsive components to
structure your website pages, which is not possible with
traditional WYSIWYG editors.
</p>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row">
<h2 class="oe_slogan">Optimize your online presence efficiently</h2>
<h3 class="oe_slogan">SEO tools at your finger tips</h3>
<div class="oe_span6">
<p class='oe_mt32'>
SEO tools are ready to use, with no configuration required.
OpenERP suggests keywords according to Google most searched
terms, Google Analytics tracks your shopping cart events,
sitemap and structuered content are created automatically for
Google indexation, etc.
</p>
</div>
<div class="oe_span6">
<div class="oe_bg_img">
<img class="oe_picture oe_screenshot" src="">
</div>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row">
<h2 class="oe_slogan">Multilanguage Without Pain</h2>
<h3 class="oe_slogan">Propagate changes and automate translation updates</h3>
<div class="oe_span6">
<div class="oe_bg_img">
<img class="oe_picture" src="">
@@ -109,13 +158,13 @@ jobs announces, "our team" pages, etc.
<p class='oe_mt32'>
Get your website translated in multiple languages with no effort.
OpenERP proposes and propagates translations automatically
across pages.
across pages, following what you edit on the master page.
</p>
Our translation "on demand" features allows you to benefit from
professional translators to translate all your changes
professional translators to translate all your contents
automatically. Just change any part of your website (a new blog
post, a new pages, updated products, ...) and the translated
versions are updated automatically in around 32 hours.
post, new pages, updated products, ...) and the translated
versions are updated automatically in around 24 hours.
</p>
</div>
</div>
@@ -144,23 +193,49 @@ jobs announces, "our team" pages, etc.
</div>
</section>
<section class="oe_container oe_dark">
<section class="oe_container">
<div class="oe_row">
<h2 class="oe_slogan">Optimize your online presence efficiently</h2>
<h3 class="oe_slogan">SEO tools at your finger tips</h3>
<div class="oe_span6">
<p class='oe_mt32'>
SEO tools are ready to use, with no configuration required.
OpenERP suggests keywords according to Google most searched
terms, Google Analytics tracks your shopping cart events,
sitemap and structuered content are created automatically for
Google indexation, etc.
</p>
<h2 class="oe_slogan">Fully Integrated With Others Apps</h2>
<h3 class="oe_slogan">Get hundreds of open source apps for free</h3>
<div class="oe_span4">
<a href="/apps/website_sale">
<h3>eCommerce</h3>
<div class="oe_row_img oe_centered">
<img class="oe_picture oe_screenshot" src="">
</div>
</a>
<p>
Promote products, sell online, optimize visitors' shopping experiences.
</p>
</div>
<div class="oe_span6">
<div class="oe_bg_img">
<img class="oe_picture oe_screenshot" src="">
</div>
<div class="oe_span4">
<a href="/apps/website_mail">
<h3>Blogs</h3>
<div class="oe_row_img oe_centered">
<img class="oe_picture oe_screenshot" src="">
</div>
</a>
<p>
Write news, attract new visitors, build customer loyalty.
</p>
</div>
<div class="oe_span4">
<a href="/apps/website_event">
<h3>Online Events</h3>
<div class="oe_row_img oe_centered">
<img class="oe_picture oe_screenshot" src="">
</div>
</a>
<p>
Schedule, organize, promote or sell events online; conferences,
webinars, trainings, etc.
</p>
</div>
<div class="oe_span12 oe_centered oe_muted">
<a href="/apps">
and hundreds more applications...
</a>
</div>
</div>
</section>
+1
View File
@@ -1,3 +1,4 @@
sass:
sass -t expanded --unix-newlines --watch website.sass:website.css&
sass -t expanded --unix-newlines --watch website-flatly.sass:website-flatly.css&
sass -t expanded --unix-newlines --watch editor.sass:editor.css&
@@ -0,0 +1,50 @@
@charset "utf-8";
/* THIS CSS FILE IS FOR WEBSITE THEMING CUSTOMIZATION ONLY
*
* css for editor buttons, openerp widget included in the website and other
* stuff must go to the editor.css
*
*/
/* ----- GENERIC LAYOUTING HELPERS ---- */
/* Theming pagination inside navbar */
.navbar-inner > .pagination {
margin: 6px 0;
}
.navbar-inner > .pagination ul {
position: relative;
top: 2px;
border: solid 2px rgba(0, 0, 0, 0.05);
border-radius: 8px;
}
/* ---- HOMEPAGE THEME CUSTOMIZATION ---- */
.subheader {
letter-spacing: 3px;
font-weight: 300;
}
.dark {
background: #eff8f8;
padding: 64px;
}
h5 {
font-weight: bold;
}
#myCarousel .item {
min-height: 300px;
color: white;
}
.thumbnail {
background: white;
}
.navbar .nav > li a {
float: none;
padding: 15px 15px 15px;
color: white;
text-decoration: none;
text-shadow: 0 1px 0 #2c3e50;
}
@@ -0,0 +1,49 @@
@charset "utf-8"
/*
* THIS CSS FILE IS FOR WEBSITE THEMING CUSTOMIZATION ONLY
*
* css for editor buttons, openerp widget included in the website and other
* stuff must go to the editor.css
*
*/
/* ----- GENERIC LAYOUTING HELPERS ---- */
/* Theming pagination inside navbar */
.navbar-inner > .pagination
margin: 6px 0
ul
position: relative
top: 2px
border: solid 2px rgba(0,0,0,0.05)
border-radius: 8px
/* ---- HOMEPAGE THEME CUSTOMIZATION ---- */
.subheader
letter-spacing: 3px
font-weight: 300
.dark
background: rgb(239, 248, 248)
padding: 64px
h5
font-weight: bold
#myCarousel .item
min-height: 300px
color: white
.thumbnail
background: white
.navbar .nav > li a
float: none
padding: 15px 15px 15px
color: #ffffff
text-decoration: none
text-shadow: 0 1px 0 #2c3e50
+14 -54
View File
@@ -1,3 +1,4 @@
@charset "utf-8";
/* THIS CSS FILE IS FOR WEBSITE THEMING CUSTOMIZATION ONLY
*
* css for editor buttons, openerp widget included in the website and other
@@ -112,17 +113,6 @@
vertical-align: bottom;
}
/* Theming pagination inside navbar */
.navbar-inner > .pagination {
margin: 6px 0;
}
.navbar-inner > .pagination ul {
position: relative;
top: 2px;
border: solid 2px rgba(0, 0, 0, 0.05);
border-radius: 8px;
}
/* ----- BOOTSTRAP HACK FOR STICKY FOOTER ----- */
html, body {
height: 100%;
@@ -141,42 +131,10 @@ html, body {
footer {
box-sizing: border-box;
height: 300px;
height: 380px;
background: #eff8f8;
padding-top: 64px;
padding-bottom: 64px;
}
/* ---- HOMEPAGE THEME CUSTOMIZATION ---- */
.subheader {
letter-spacing: 3px;
font-weight: 300;
}
header.navbar-fixed-top {
position: static;
}
.dark {
background: #eff8f8;
padding: 64px;
}
h5 {
font-weight: bold;
}
#myCarousel .item {
min-height: 300px;
color: white;
}
.nav > .pull-right {
float: right !important;
}
.thumbnail {
background: white;
padding-top: 48px;
padding-bottom: 48px;
}
/* ---- HACK FOR COVERING UP CK EDITOR BOGUS P INSERTION --- */
@@ -188,14 +146,16 @@ h5 {
text-shadow: none;
}
.navbar .nav > li a {
float: none;
padding: 15px 15px 15px;
color: white;
text-decoration: none;
text-shadow: 0 1px 0 #2c3e50;
}
.nav > li a {
display: block;
}
/* ---- HOMEPAGE THEME CUSTOMIZATION ---- */
header.navbar-fixed-top {
position: static;
}
#myCarousel .item {
min-height: 300px;
color: white;
}
+13 -45
View File
@@ -76,15 +76,6 @@
text-align: left
vertical-align: bottom
/* Theming pagination inside navbar */
.navbar-inner > .pagination
margin: 6px 0
ul
position: relative
top: 2px
border: solid 2px rgba(0,0,0,0.05)
border-radius: 8px
/* ----- BOOTSTRAP HACK FOR STICKY FOOTER ----- */
html,body
@@ -102,37 +93,11 @@ html,body
footer
box-sizing: border-box
height: 300px
height: 380px
background: rgb(239, 248, 248) // rgb(221, 235, 227)
padding-top: 64px
padding-bottom: 64px
padding-top: 48px
padding-bottom: 48px
/* ---- HOMEPAGE THEME CUSTOMIZATION ---- */
.subheader
letter-spacing: 3px
font-weight: 300
header.navbar-fixed-top
position: static
.dark
background: rgb(239, 248, 248)
padding: 64px
h5
font-weight: bold
#myCarousel .item
min-height: 300px
color: white
.nav > .pull-right
float: right !important //bugfix for flatly theme
.thumbnail
background: white
/* ---- HACK FOR COVERING UP CK EDITOR BOGUS P INSERTION --- */
@@ -142,13 +107,16 @@ h5
.navbar .nav > li a
text-shadow: none
.navbar .nav > li a
float: none
padding: 15px 15px 15px
color: #ffffff
text-decoration: none
text-shadow: 0 1px 0 #2c3e50
.nav > li a
display: block
/* ---- HOMEPAGE THEME CUSTOMIZATION ---- */
header.navbar-fixed-top
position: static
#myCarousel .item
min-height: 300px
color: white
+133 -49
View File
@@ -1,20 +1,36 @@
openerp.website = function(instance) {
// Ugly. I'll clean this monday
$(function () { if ($('html').attr('data-editable') !== '1') return;
instance.web.ActionManager.include({
// Temporary fix until un-webclientization of the editorbar
ir_actions_client: function (action) {
if (instance.web.client_actions.get_object(action.tag)) {
return this._super.apply(this, arguments);
} else {
console.warn("Action '%s' not found in registry", action.tag);
return $.when();
}
}
});
// TODO fme: put everything in openerp.website scope and load templates on
// next tick or document ready
// Also check with xmo if jquery.keypress.js is still needed.
var _lt = instance.web._lt;
var QWeb = instance.web.qweb;
instance.website.EditorBar = instance.web.Widget.extend({
var doc_ready = $.Deferred();
$(doc_ready.resolve);
var templates = [
'/website/static/src/xml/website.xml'
];
function loadTemplates(templates) {
var def = $.Deferred();
var count = templates.length;
templates.forEach(function(t) {
openerp.qweb.add_template(t, function(err) {
if (err) {
def.reject();
} else {
count--;
if (count < 1) {
def.resolve();
}
}
});
});
return def;
}
var EditorBar = openerp.Widget.extend({
template: 'Website.EditorBar',
events: {
'click button[data-action=edit]': 'edit',
@@ -23,26 +39,55 @@ instance.website.EditorBar = instance.web.Widget.extend({
'click button[data-action=snippet]': 'snippet',
},
container: 'body',
init: function () {
this._super.apply(this, arguments);
this.saving_mutex = new $.Mutex();
customize_setup: function() {
var self = this;
var view_name = $('html').data('view-xmlid');
var menu = $('#customize-menu');
this.$('#customize-menu-button').click(function(event) {
menu.empty();
openerp.jsonRpc('/website/customize_template_get', 'call', { 'xml_id': view_name }).then(
function(result) {
_.each(result, function (item) {
if (item.header) {
menu.append('<li class="nav-header">' + item.name + '</li>');
} else {
menu.append(_.str.sprintf('<li><a href="#" data-view-id="%s"><strong class="icon-check%s"></strong> %s</a></li>',
item.id, item.active ? '' : '-empty', item.name));
}
});
}
);
});
menu.on('click', 'a', function (event) {
var view_id = $(event.target).data('view-id');
openerp.jsonRpc('/website/customize_template_toggle', 'call', {
'view_id': view_id
}).then( function(result) {
window.location.reload();
});
});
},
start: function() {
var self = this;
this.$('button[data-action]').prop('disabled', true)
.parent().hide();
this.saving_mutex = new openerp.Mutex();
this.$('#website-top-edit').hide();
this.$('#website-top-view').show();
$('.dropdown-toggle').dropdown();
this.customize_setup();
this.$buttons = {
edit: this.$('button[data-action=edit]'),
save: this.$('button[data-action=save]'),
cancel: this.$('button[data-action=cancel]'),
snippet: this.$('button[data-action=snippet]'),
};
this.$buttons.edit.prop('disabled', false).parent().show();
self.snippet_start();
this.rte = new instance.website.RTE(this);
this.rte = new RTE(this);
this.rte.on('change', this, this.proxy('rte_changed'));
return $.when(
@@ -51,10 +96,14 @@ instance.website.EditorBar = instance.web.Widget.extend({
);
},
edit: function () {
this.$buttons.edit.prop('disabled', true).parent().hide();
this.$buttons.cancel.add(this.$buttons.snippet).prop('disabled', false)
.add(this.$buttons.save)
.parent().show();
this.$buttons.edit.prop('disabled', true);
this.$('#website-top-view').hide();
this.$('#website-top-edit').show();
// this.$buttons.cancel.add(this.$buttons.snippet).prop('disabled', false)
// .add(this.$buttons.save)
// .parent().show();
//
// TODO: span edition changing edition state (save button)
var $editables = $('[data-oe-model]')
.not('link, script')
@@ -62,7 +111,7 @@ instance.website.EditorBar = instance.web.Widget.extend({
.not('.oe_snippet_editor')
.prop('contentEditable', true)
.addClass('oe_editable');
var $rte_ables = $editables.filter('div, p, li, section, header, footer').not('[data-oe-type]');
var $rte_ables = $editables.not('[data-oe-type]');
var $raw_editables = $editables.not($rte_ables);
// temporary fix until we fix ckeditor
@@ -121,7 +170,11 @@ instance.website.EditorBar = instance.web.Widget.extend({
.prop('contentEditable', false);
html = $w.wrap('<div>').parent().html();
}
return (new instance.web.DataSet(this, 'ir.ui.view')).call('save', [data.oeModel, data.oeId, data.oeField, html, xpath]);
return openerp.jsonRpc('/web/dataset/call', 'call', {
model: 'ir.ui.view',
method: 'save',
args: [data.oeModel, data.oeId, data.oeField, html, xpath]
});
},
cancel: function () {
window.location.reload();
@@ -159,7 +212,7 @@ instance.website.EditorBar = instance.web.Widget.extend({
},
});
instance.website.RTE = instance.web.Widget.extend({
var RTE = openerp.Widget.extend({
tagName: 'li',
id: 'oe_rte_toolbar',
className: 'oe_right oe_rte_toolbar',
@@ -191,6 +244,9 @@ instance.website.RTE = instance.web.Widget.extend({
'magicline'
];
return {
// Disable auto-generated titles
// FIXME: accessibility, need to generate user-sensible title, used for @title and @aria-label
title: false,
removePlugins: removed_plugins.join(','),
uiColor: '',
// Ensure no config file is loaded
@@ -205,14 +261,22 @@ instance.website.RTE = instance.web.Widget.extend({
// Place toolbar in controlled location
sharedSpaces: { top: 'oe_rte_toolbar' },
toolbar: [
{name: 'items', items: [
{name: 'basicstyles', items: [
"Bold", "Italic", "Underline", "Strike", "Subscript",
"Superscript", "TextColor", "BGColor", "RemoveFormat",
"Superscript", "TextColor", "BGColor", "RemoveFormat"
]},{
name: 'span', items: [
"Link", "Unlink", "Blockquote", "BulletedList",
"NumberedList", "Image", "Indent", "Outdent",
"JustifyLeft", "JustifyCenter", "JustifyRight",
"JustifyBlock", "Table", "Font", "FontSize", "Format",
"Styles"
"NumberedList", "Indent", "Outdent",
]},{
name: 'justify', items: [
"JustifyLeft", "JustifyCenter", "JustifyRight", "JustifyBlock"
]},{
name: 'special', items: [
"Image", "Table"
]},{
name: 'styles', items: [
"Format", "Styles"
]}
],
// styles dropdown in toolbar
@@ -232,7 +296,7 @@ instance.website.RTE = instance.web.Widget.extend({
var self = this;
$('.carousel .js_carousel_options .label').on('click', function (e) {
e.preventDefault();
var $button = $(e.currentTarget)
var $button = $(e.currentTarget);
var $c = $button.parents(".carousel:first");
if($button.hasClass("js_add")) {
@@ -251,7 +315,12 @@ instance.website.RTE = instance.web.Widget.extend({
}
});
$(function(){
$.when(doc_ready, loadTemplates(templates)).then(function() {
var editor = new EditorBar();
editor.prependTo($('body'));
$('body').css('padding-top', '50px'); // Not working properly: editor.$el.outerHeight());
// TODO: Create an openerp.Widget out of this
function make_static(){
$('.oe_snippet_demo').removeClass('oe_new');
@@ -307,6 +376,12 @@ $(function(){
});
}
function customier_option_get(event){
event.preventDefault();
}
function append_snippet(event){
console.log('click',this,event.button);
if(event.button === 0){
@@ -330,17 +405,26 @@ $(function(){
}
});
instance.web.ActionRedirect = function(parent, action) {
var url = $.deparam(window.location.href).url;
if (url) {
window.location.href = url;
}
};
instance.web.client_actions.add("redirect", "instance.web.ActionRedirect");
});
// }()); I'll clean this monday
instance.web.GoToWebsite = function(parent, action) {
window.location.href = window.location.href.replace(/[?#].*/, '').replace(/\/admin[\/]?$/, '');
};
instance.web.client_actions.add("website.gotowebsite", "instance.web.GoToWebsite");
};
$(function () {
$(document).on('click', '.js_publish, .js_unpublish', function (e) {
e.preventDefault();
var $link = $(this).parent();
$link.find('.js_publish, .js_unpublish').addClass("hidden");
var $unp = $link.find(".js_unpublish");
var $p = $link.find(".js_publish");
$.post('/website/publish', {'id': $link.data('id'), 'object': $link.data('object')}, function (result) {
if (+result) {
$p.addClass("hidden");
$unp.removeClass("hidden");
} else {
$p.removeClass("hidden");
$unp.addClass("hidden");
}
});
});
});
@@ -1,19 +0,0 @@
$(function() {
// Init headless webclient
// TODO: Webclient research : use iframe embedding mode
// Meanwhile, let's HACK !!!
var s = new openerp.init(['web', 'website']);
s.web.WebClient.bind_hashchange = s.web.WebClient.show_common = s.web.blockUI = s.web.unblockUI = function() {};
s.web.WebClient.include({ do_push_state: function() {} });
var wc = new s.web.WebClient();
wc.start();
var instance = openerp.instances[wc.session.name];
// Another hack since we have no callback when webclient has loaded modules.
instance.web.qweb.add_template('/website/static/src/xml/website.xml');
$(function() {
var editor = new instance.website.EditorBar(instance.webclient);
editor.prependTo($('body'));
$('body').css('padding-top', '32px'); // Not working properly: editor.$el.outerHeight());
});
});
+37 -6
View File
@@ -3,12 +3,43 @@
-->
<templates id="template" xml:space="preserve">
<t t-name="Website.EditorBar">
<ul class="oe_website_editorbar openerp">
<li><button data-action="edit">Edit</button></li>
<li><button data-action="save">Save</button></li>
<li><button data-action="cancel">Cancel</button></li>
<li class="oe_right"><button data-action="snippet">Building Blocks</button></li>
</ul>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-inner" id="website-top-view">
<form class="navbar-form pull-left">
<button data-action="edit" class="btn btn-primary">Edit</button>
</form>
<ul class="nav pull-right">
<li class="active"><a href="#"><span class="icon-desktop"/></a></li>
<li><a href="#"><span class="icon-mobile-phone"/></a></li>
<li class="divider-vertical"></li>
<li><a href="#">Promote<!-- <sup><span class="badge">1</span></sup> --></a></li>
<li><a href="#">Translate</a></li>
<li class="dropdown">
<a id="customize-menu-button" class="dropdown-toggle" data-toggle="dropdown" href="#">Customize <span class="caret"></span></a>
<div class="dropdown-menu">
<ul class="nav nav-list" id="customize-menu">
<!-- filled in JS -->
</ul>
</div>
</li>
<li>
<a href="/admin#action=website.action_module_website">Apps</a>
</li>
</ul>
</div>
<div class="navbar-inner" id="website-top-edit">
<form class="navbar-form pull-left">
<button data-action="save" class="btn btn-primary">Save</button>
<button data-action="cancel" class="btn">Cancel</button>
</form>
<ul class="nav pull-right">
<li><button data-action="snippet" class="btn btn-primary">Building Blocks</button></li>
</ul>
</div>
</div>
</t>
<t t-name="Website.ActionGroup">
<div class="dropdown">
+47
View File
@@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-
from lxml import etree
from openerp.osv import osv, fields
class view(osv.osv):
_inherit = "ir.ui.view"
_columns = {
'inherit_option_id': fields.many2one('ir.ui.view','Optional Inheritancy'),
'inherited_option_ids': fields.one2many('ir.ui.view','inherit_option_id','Optional Inheritancies'),
}
# Returns all views (called and inherited) related to a view
# Used by translation mechanism, SEO and optional templates
def _views_get(self, cr, uid, view, options=True, context=None, root=True, stack_result=None):
if not context:
context = {}
if not stack_result:
stack_result = []
def view_obj(view):
if type(view) in (str, unicode):
mod_obj = self.pool.get("ir.model.data")
m, n = view.split('.')
_, view = mod_obj.get_object_reference(cr, uid, m, n)
if type(view) == int:
view_obj = self.pool.get("ir.ui.view")
view = view_obj.browse(cr, uid, view, context=context)
return view
view = view_obj(view)
while root and view.inherit_id:
view = view.inherit_id
result = [view]
todo = view.inherit_children_ids
if options:
todo += filter(lambda x: not x.inherit_id, view.inherited_option_ids)
for child_view in todo:
result += self._views_get(cr, uid, child_view, options=options, context=context, root=False, stack_result=result)
node = etree.fromstring(view.arch)
for child in node.xpath("//t[@t-call]"):
call_view = view_obj(child.get('t-call'))
if call_view not in stack_result:
result += self._views_get(cr, uid, call_view, options=options, context=context, stack_result=result)
return result
+211 -88
View File
@@ -3,80 +3,68 @@
-->
<openerp>
<data>
<template id="header">
<div class="container">
<a href='/page/website.homepage' class='brand'>
<em>Open</em><b>ERP</b>
<!--<img t-att-alt="res_company.name" src='/web/binary/company_logo'/></a>-->
</a>
<ul class="nav pull-right">
<li class='pull-right'><a href="/admin">Sign in</a></li>
<li class='pull-right'><a href="/page/website.contactus">Contact us</a></li>
</ul>
</div>
<!--
Files used in the generic theme, mostly bootstrap and a few OpenERP tags
-->
<template id="theme" name="Theme">
<link id="bootstrap_css" rel='stylesheet' href='/website/static/lib/bootstrap/css/bootstrap.css' t-ignore="true"/>
<link id="website_css" rel='stylesheet' href='/website/static/src/css/website.css' t-ignore="true"/>
</template>
<template id="footer">
<div class="container">
<div class="row">
<div class="span4" name="product">
<h5>Product and services</h5>
<ul class='unstyled'>
<li><a href="https://www.openerp.com/start?download">Download</a></li>
<li><a href="https://launchpad.net/openobject">Launchpad</a></li>
<li><a href="http://runbot.openerp.com">Automated Tests</a></li>
</ul>
</div>
<div class="span4" name="social">
<h5>Social</h5>
<ul class='unstyled'>
<li><a href="http://twitter.com/openerp"><i class="icon-twitter-sign"></i>Twitter</a></li>
<li><a href="http://www.facebook.com/OpenERP"><i class="icon-facebook-sign"></i>Facebook</a></li>
<li><a href="https://plus.google.com/+openerp/posts"><i class="icon-google-plus-sign"></i>Google+</a></li>
</ul>
</div>
<div class="span4" name="about_us">
<h5 t-field="res_company.name">Company name</h5>
<ul class='unstyled'>
<li><a href="/page/website.contactus">Contact us</a></li>
<li><a href="/page/website.news">News</a></li>
<li><a href="/page/website.contactus">About us</a></li>
<li><a href='#'>&amp;#x2706; <span t-field="res_company.phone"/></a></li>
</ul>
</div>
</div>
</div>
<template id="theme_flatly" name="Flat Theme" inherit_option_id="website.theme">
<xpath expr="//link[@id='bootstrap_css']" position="replace">
<link rel='stylesheet' href='/website/static/lib/bootstrap/css/bootstrap-flatly.css' t-ignore="true"/>
<link rel='stylesheet' href='/website/static/src/css/website-flatly.css' t-ignore="true"/>
</xpath>
</template>
<template id="layout">
&lt;!DOCTYPE html&gt;
<html>
<html t-att-data-view-xmlid="__stack__[0]" t-att-data-editable="'1' if editable else '0'">
<head>
<title t-raw="title"><t t-esc="res_company.name"/></title>
<title><t t-esc="title or res_company.name"/></title>
<script type="text/javascript" src="/web/static/lib/underscore/underscore.js"></script>
<script type="text/javascript" src="/web/static/lib/underscore.string/lib/underscore.string.js"></script>
<script type="text/javascript" src="/web/static/lib/jquery/jquery.js"></script>
<script type="text/javascript" src="/website/static/lib/bootstrap/js/bootstrap.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/ckeditor/4.2/ckeditor.js"></script>
<script type="text/javascript" src="/website/static/lib/ckeditor.sharedspace/plugin.js"></script>
<script type="text/javascript">
CKEDITOR.disableAutoInline = true;
CKEDITOR.dtd.$editable.li = 1;
// EDIT ALL THE THINGS
CKEDITOR.dtd.$editable = $.extend(
{}, CKEDITOR.dtd.$block, CKEDITOR.dtd.$inline);
</script>
<t t-if="editable">
<t t-raw="css"/>
<t t-raw="script"/>
<link rel='stylesheet' href='/website/static/src/css/snippets.css'/>
<script type="text/javascript" src="/website/static/src/js/website_bootstrap.js"></script>
<link rel='stylesheet' href='/website/static/src/css/editor.css'/>
<script type="text/javascript" src="/web/static/lib/jquery.ui/js/jquery-ui-1.9.1.custom.js"></script>
<script type="text/javascript" src="/web/static/lib/qweb/qweb2.js"></script>
<script type="text/javascript" src="/web/static/src/js/openerpframework.js"></script>
</t>
<t t-raw="head"/>
<link rel='stylesheet' href='/website/static/lib/bootstrap/css/bootstrap-flatly.css'/>
<script type="text/javascript" src="/website/static/src/js/website.js"></script>
<t t-raw="head or ''"/>
<t t-call="website.theme"/>
<link rel='stylesheet' href='/web/static/lib/fontawesome/css/font-awesome.css'/>
<link rel='stylesheet' href='/website/static/src/css/website.css'/>
<link rel='stylesheet' href='/website/static/lib/bootstrap/css/bootstrap-responsive.css'/>
</head>
<body>
<header class='navbar navbar-fixed-top'>
<header class='navbar navbar-static-top'>
<div class='navbar-inner'>
<t t-call="website.header"/>
<div class="container">
<a href='/page/website.homepage' class='brand'>
<em>Open</em><b>ERP</b>
<!--<img t-att-alt="res_company.name" src='/web/binary/company_logo'/></a>-->
</a>
<ul class="nav pull-right" id="top_menu">
<li><a href="/page/website.contactus">Contact us</a></li>
<li><a href="/admin">Sign in</a></li>
</ul>
</div>
</div>
</header>
<div t-raw="0" id="wrap">
@@ -85,8 +73,53 @@
</div>
</div>
<footer>
<t t-call="website.footer"/>
<p class="text-center">&amp;copy; <span t-field="res_company.name">Company name</span>.</p>
<div class="container" id="footer_container">
<div class="row">
<div class="span3" name="product">
<h5>Our products</h5>
<ul class='unstyled' name="products">
<li><a href="/">Home</a></li>
</ul>
</div>
<div class="span3" name="info">
<h5 name="info_title">Connect with us</h5>
<ul class='unstyled'>
<li><a href="/page/website.aboutus">About us</a></li>
<li><a href="/page/website.contactus">Contact us</a></li>
</ul>
<ul class='unstyled'>
<li><i class="icon-phone"></i> <span t-field="res_company.phone"/></li>
<li><i class="icon-envelope"></i> <span t-field="res_company.email"></span></li>
</ul>
</div>
<div class="span5 offset1" name="about_us">
<h5 t-field="res_company.name">About us</h5>
<p>
We are a team of passionated people whose goal
is to improve everyone's life through
disruptive products. We build great products to
solve your business problems.
</p><p>
Our products are designed for small to medium
companies willing to optimize their
performance.
</p>
<h1 style="padding: 12px 24px">
<a href="http://twitter.com/openerp"><i class="icon-twitter-sign"></i></a>
<a href="http://facebook.com/OpenERP"><i class="icon-facebook-sign"></i></a>
<a href="https://plus.google.com/+openerp/posts"><i class="icon-google-plus-sign"></i></a>
</h1>
</div>
</div>
</div>
<div class="container mt16">
<div class="pull-right" t-ignore="1">
Create a <a href="http://openerp.com/apps/website">free website</a> with <a class="label label-important" href="https://openerp.com/apps/website">OpenERP</a>
</div>
<div class="pull-left muted">
Copyright &amp;copy; <span t-field="res_company.name">Company name</span> - <a href="/sitemap">Sitemap</a>
</div>
</div>
</footer>
<div class='oe_snippet_editor' style="display: none;">
@@ -194,6 +227,12 @@
</html>
</template>
<template id="footer_custom" inherit_option_id="website.layout" name="Custom Footer">
<xpath expr="//div[@id='footer_container']" position="attributes">
<attribute name="style">display: none</attribute>
</xpath>
</template>
<template id="homepage">
<t t-call="website.layout">
@@ -207,15 +246,16 @@
<div class="carousel-inner">
<div class="item active" style="background-image: url(/website/static/src/img/greenfields.jpg); background-size: cover;" >
<div class='container'>
<h1 class='mt64'>A Nice Bidule</h1>
<h2>A convincing subtitle</h2>
<a href='#' class='btn btn-success btn-large mt16'>And a <em>Call To Action</em></a>
<div class="mt64"> </div>
<h1>Create Awesome Websites</h1>
<h3>Super easy, fully flexible</h3>
<a href='/page/website.contactus' class='btn btn-success btn-large mt16'>Contact us</a>
</div>
</div>
</div>
<!-- Carousel nav -->
<a class="carousel-control left" href="#myCarousel" data-slide="prev">&amp;lsaquo;</a>
<a class="carousel-control right" href="#myCarousel" data-slide="next">&amp;rsaquo;</a>
<a class="carousel-control left" href="#myCarousel" data-slide="prev" t-ignore="1">&amp;lsaquo;</a>
<a class="carousel-control right" href="#myCarousel" data-slide="next" t-ignore="1">&amp;rsaquo;</a>
</div>
</section>
@@ -315,38 +355,73 @@
<template id="404">
<t t-call="website.layout">
<div class="container" t-if="editable">
<div class="well mt32">
<p>
This page does not exists, but you can create
it as you are administrator of this site.
</p>
<a class="btn btn-primary" t-att-href="'/pagenew/'+path">Create Page</a> <span class="muted"> or </span> <a href="/sitemap">Search a Page</a>
</div>
<div class="text-center muted">
Edit the content bellow this line to adapt the default "page not found" page.
</div>
</div>
<hr/>
<div class="container">
<div class="row">
<div class="span12">
<h1>404: Page not found!</h1>
<p>
The page you were looking for could not be
found; it is possible you have typed the
address incorrectly, but it has most
probably been removed due to the recent
website reorganisation.
</p><p>
Maybe you were looking for one of these
popular pages ?
</p>
<ul>
<li><a href="/">Homepage</a></li>
<li><a href="/">Contact Us</a></li>
</ul>
</div>
</div>
<div class="row">
<div class="span12 mt32">
<a class="btn btn-primary" t-att-href="'/pagenew/'+path" t-if="editable">Create Page</a>
</div>
</div>
<h1 class="mt32">404: Page not found!</h1>
<p>
The page you were looking for could not be
found; it is possible you have typed the
address incorrectly, but it has most
probably been removed due to the recent
website reorganisation.
</p><p>
Maybe you were looking for one of these
popular pages ?
</p>
<ul>
<li><a href="/">Homepage</a></li>
<li><a href="/">Contact Us</a></li>
</ul>
</div>
</t>
</template>
<template id="contactus">
<template id="500">
<t t-call="website.layout">
<t t-set="title">Contact us - <t t-esc="res_company.name"/></t>
<div class="container">
<h1 class="mt32">500: Internal Server Error!</h1>
<pre t-esc="traceback"/>
</div>
</t>
</template>
<template id="401">
<t t-call="website.layout">
<div class="container">
<h1 class="mt32">401: Unauthorized Access!</h1>
<p>
The page you were looking for could not be
authorized.
</p><p>
Maybe you were looking for one of these
popular pages ?
</p>
<pre class="hidden" t-esc="error"/>
<ul>
<li><a href="/">Homepage</a></li>
<li><a href="/">Contact Us</a></li>
</ul>
</div>
</t>
</template>
<template id="contactus" name="Contact us">
<t t-call="website.layout">
<t t-set="title">Contact us - <t t-raw="res_company.name"/></t>
<div class="container">
<h2>Contact us</h2>
<div class="row">
@@ -363,19 +438,67 @@
<div class="span4">
<address>
<strong t-field="res_company.name">Name</strong><br/>
<span t-field="res_company.street"/><br/>
<span t-field="res_company.city"/>, <span t-field="res_company.zip"/><br/>
<span t-field="res_company.street"/> <span t-field="res_company.state_id"/><br/>
<span t-field="res_company.zip"/> <span t-field="res_company.city"/><br/>
<span t-field="res_company.country_id"> </span><br/>
<br/>
<span>&amp;#x2706; <span t-field="res_company.phone"></span></span><br/>
<i class="icon-envelope"></i> <span t-field="res_company.email"></span>
</address>
<img class="thumbnail" t-att-src="google_map_url"/>
<a t-att-href="res_company.partner_id.google_map_link()" target="_BLANK">
<img class="thumbnail" t-att-src="res_company.partner_id.google_map_img()"/>
</a>
</div>
</div>
</div>
</t>
</template>
<template id="aboutus">
<t t-call="website.layout">
<t t-set="title">About us - <t t-raw="res_company.name"/></t>
<div class="container">
<h2>About us</h2>
<div class="row">
<div class="span4">
<h3>Our vision</h3>
<p>
Contact us about anything related to our company or services.
</p><p>
We'll do our best to get back to you as soon as possible.
</p>
</div>
<div class="span8">
</div>
</div>
</div>
</t>
</template>
<template id="pager">
<div t-if="pager['page_count'] > 1" t-attf-class="#{ classname or '' } pagination">
<ul>
<li t-att-class=" 'disabled' if pager['page']['num'] == 1 else '' " >
<a t-att-href=" pager['page_start']['url'] if pager['page']['num'] != 1 else '' ">Prev</a>
</li>
<t t-foreach="pager['pages']">
<li t-att-class=" 'active' if num == pager['page']['num'] else '' ">
<a t-att-href="url" t-raw="num"></a>
</li>
</t>
<li t-att-class=" 'disabled' if pager['page']['num'] == pager['page_count'] else '' " >
<a t-att-href=" pager['page_end']['url'] if pager['page']['num'] != pager['page_count'] else '' ">Next</a>
</li>
</ul>
</div>
</template>
<template id="publish">
<a href="#" t-att-data-id="object.id" t-att-data-object="object._name" class="pull-right" t-if="editable" t-ignore="true">
<span t-att-class="'label label-success js_unpublish %%s' %% (not object.website_published and 'hidden' or '')">Unpublish</span>
<span t-att-class="'label label-important js_publish %%s' %% (object.website_published and 'hidden' or '')">Publish</span>
</a>
</template>
</data>
</openerp>
+92 -8
View File
@@ -1,10 +1,17 @@
# -*- coding: utf-8 -*-
import simplejson
import openerp
from openerp.osv import osv
from openerp.osv import osv, orm
from openerp.addons.web import http
from openerp.addons.web.controllers import main
from openerp.addons.web.http import request
import urllib
import math
import traceback
import logging
logger = logging.getLogger(__name__)
def auth_method_public():
@@ -16,6 +23,15 @@ def auth_method_public():
http.auth_methods['public'] = auth_method_public
def urlplus(url, params):
if not params:
return url
url += "?"
for k,v in params.items():
url += "%s=%s&" % (k, urllib.quote_plus(str(v)))
return url
class website(osv.osv):
_name = "website" # Avoid website.website convention for conciseness (for new api). Got a special authorization from xmo and rco
_description = "Website"
@@ -30,23 +46,24 @@ class website(osv.osv):
def get_rendering_context(self, additional_values=None):
debug = 'debug' in request.params
is_logged = True
try:
request.session.check_security()
except: # TODO fme: check correct exception
is_logged = False
is_public_user = request.uid == self.get_public_user().id
values = {
'debug': debug,
'is_public_user': is_public_user,
'editable': not is_public_user,
'editable': is_logged and not is_public_user,
'request': request,
'registry': request.registry,
'cr': request.cr,
'uid': request.uid,
'host_url': request.httprequest.host_url,
'res_company': request.registry['res.company'].browse(request.cr, openerp.SUPERUSER_ID, 1),
'json': simplejson,
}
if values['editable']:
values.update({
'script': "\n".join(['<script type="text/javascript" src="%s"></script>' % i for i in main.manifest_list('js', db=request.db, debug=debug)]),
'css': "\n".join('<link rel="stylesheet" href="%s">' % i for i in main.manifest_list('css', db=request.db, debug=debug))
})
if additional_values:
values.update(additional_values)
return values
@@ -55,4 +72,71 @@ class website(osv.osv):
context = {
'inherit_branding': values.get('editable', False),
}
return request.registry.get("ir.ui.view").render(request.cr, request.uid, template, values, context=context)
try:
return request.registry.get("ir.ui.view").render(request.cr, request.uid, template, values, context=context)
except (osv.except_osv, orm.except_orm), err:
logger.error(err)
values['error'] = err[1]
return self.render('website.401', values)
except ValueError:
logger.error("Website Rendering Error.\n\n%s" % (traceback.format_exc()))
return self.render('website.404', values)
except Exception:
logger.error("Website Rendering Error.\n\n%s" % (traceback.format_exc()))
if values['editable']:
values['traceback'] = traceback.format_exc()
return self.render('website.500', values)
else:
return self.render('website.404', values)
def pager(self, url, total, page=1, step=30, scope=5, url_args=None):
# Compute Pager
d = {}
d["page_count"] = int(math.ceil(float(total) / step))
page = max(1, min(int(page), d["page_count"]))
d["offset"] = (page-1) * step
scope -= 1
pmin = max(page - int(math.floor(scope/2)), 1)
pmax = min(pmin + scope, d["page_count"])
if pmax - pmin < scope:
pmin = pmax - scope > 0 and pmax - scope or 1
def get_url(page):
_url = "%spage/%s/" % (url, page)
if url_args:
_url = "%s?%s" % (_url, urllib.urlencode(url_args))
return _url
d["page"] = {'url': get_url(page), 'num': page}
d["page_start"] = {'url': get_url(pmin), 'num': pmin}
d["page_end"] = {'url': get_url(min(pmax, page+1)), 'num': min(pmax, page+1)}
d["pages"] = []
for page in range(pmin, pmax+1):
d["pages"].append({'url': get_url(page), 'num': page})
return d
class res_partner(osv.osv):
_inherit = "res.partner"
def google_map_img(self, cr, uid, ids, zoom=8, width=298, height=298, context=None):
partner = self.browse(cr, uid, ids[0], context=context)
params = {
'center': '%s, %s %s, %s' % (partner.street, partner.city, partner.zip, partner.country_id and partner.country_id.name_get()[0][1] or ''),
'size': "%sx%s" % (height, width),
'zoom': zoom,
'sensor': 'false',
}
return urlplus('http://maps.googleapis.com/maps/api/staticmap' , params)
def google_map_link(self, cr, uid, ids, zoom=8, context=None):
partner = self.browse(cr, uid, ids[0], context=context)
params = {
'q': '%s, %s %s, %s' % (partner.street, partner.city, partner.zip, partner.country_id and partner.country_id.name_get()[0][1] or ''),
}
return urlplus('https://maps.google.be/maps' , params)
+21 -13
View File
@@ -16,20 +16,28 @@
<field name="users" eval="[(4, ref('public_user'))]"/>
</record>
<record id="action_gotowebsite" model="ir.actions.client">
<field name="name">Website</field>
<field name="tag">website.gotowebsite</field>
<field name="res_model">website</field>
<record id="action_module_website" model="ir.actions.act_window">
<field name="name">Website Apps</field>
<field name="res_model">ir.module.module</field>
<field name="view_type">form</field>
<field name="view_mode">kanban,form</field>
<field name="context" eval="'{\'search_default_category_id\':'+str(ref('base.module_category_website'))+'}'"/>
<field name="help" type="html">
<p><b>No website module found!</b></p>
<p>You should try others search criteria.</p>
</field>
</record>
<menuitem id="website.menu" name="Website" sequence="501"/>
<menuitem id="website.submenu" name="Website" parent="website.menu" sequence="10"/>
<record id="mail_inboxfeeds" model="ir.ui.menu">
<field name="name">Go to Website</field>
<field name="sequence" eval="10"/>
<field name="action" ref="website.action_gotowebsite"/>
<field name="parent_id" ref="website.submenu"/>
<record id="action_website" model="ir.actions.act_url">
<field name="name">Website</field>
<field name="url">/</field>
<field name="target">self</field>
</record>
<record id="menu_website" model="ir.ui.menu">
<field name="name">Website</field>
<field name="sequence" eval="510"/>
<field name="action" ref="action_website"/>
</record>
</data>
</openerp>
</openerp>
+3 -3
View File
@@ -1,6 +1,7 @@
{
'name': 'Website Contact Form',
'category': 'CRM',
'name': 'Contact Form',
'category': 'Website',
'summary': 'Generate Leads From Contact Form',
'version': '1.0',
'description': """
OpenERP Contact Form
@@ -15,5 +16,4 @@ OpenERP Contact Form
'js': ['static/src/js/ecommerce.js'],
'css': ['static/src/css/ecommerce.css'],
'installable': True,
'auto_install': True,
}
@@ -0,0 +1,91 @@
<section class="oe_container">
<div class="oe_row oe_spaced">
<div class="oe_span12">
<h2 class="oe_slogan">Your Contact Form</h2>
<h3 class="oe_slogan">Integrate contact forms with your leads</h3>
</div>
<div class="oe_span6">
<div class="oe_demo oe_picture oe_screenshot">
<a href="https://www.openerp.com/saas_master/demo?lang=en_US&module=website">
<img src="">
</a>
<div class="oe_demo_footer oe_centeralign">Online Demo</div>
</div>
</div>
<div class="oe_span6">
<p class='oe_mt32'>
This simple application integrates a contact form in your
"Contact us" page. Forms submissions create leads automatically
in OpenERP CRM.
</p>
<div class="oe_centeralign oe_websiteonly">
<a href="http://www.openerp.com/start?app=website" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> website</a>
</div>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row">
<h2 class="oe_slogan">Easy Contact Page</h2>
<h3 class="oe_slogan">A contact form is better than an email</h3>
<div class="oe_span6">
<p class='oe_mt32'>
Get your leads filled up automatically with your contact form
integration. This application allows a better qualification of
the lead which is perfect to link them to marketing campaigns.
</p>
</div>
<div class="oe_span6">
<div class="oe_bg_img oe_centered">
<img class="oe_picture" src="">
</div>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row">
<h2 class="oe_slogan">Fully Integrated With Others Apps</h2>
<h3 class="oe_slogan">Get hundreds of open source apps for free</h3>
<div class="oe_span4">
<a href="/apps/website_sale">
<h3>eCommerce</h3>
<div class="oe_row_img oe_centered">
<img class="oe_picture oe_screenshot" src="">
</div>
</a>
<p>
Promote products, sell online, optimize visitors' shopping experiences.
</p>
</div>
<div class="oe_span4">
<a href="/apps/website_mail">
<h3>Blogs</h3>
<div class="oe_row_img oe_centered">
<img class="oe_picture oe_screenshot" src="">
</div>
</a>
<p>
Write news, attract new visitors, build customer loyalty.
</p>
</div>
<div class="oe_span4">
<a href="/apps/website">
<h3>CMS</h3>
<div class="oe_row_img oe_centered">
<img class="oe_picture oe_screenshot" src="">
</div>
</a>
<p>
Easily create awesome websites with no technical knowledge required.
</p>
</div>
<div class="oe_span12 oe_centered oe_muted">
<a href="/apps">
and hundreds more applications...
</a>
</div>
</div>
</section>
+60 -25
View File
@@ -1,33 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="contactus" model="ir.ui.view">
<field name="name">contactus</field>
<field name="type">qweb</field>
<field name="inherit_id" ref="website.contactus"/>
<field name="arch" type="xml">
<xpath expr="//div[@name='mail_button']" position="replace">
<form action="/crm/contactus" method="post" class="navbar-form pull-left">
<input class="span4" type="text" name="contact_name" required="True" placeholder="Name..."/><br/>
<input class="span4" type="text" name="phone" required="True" placeholder="Phone number..."/><br/>
<input class="span4" type="text" name="email_from" required="True" placeholder="Email..."/>
<input class="span8" style="margin-top: 15px;" type="text" name="name" required="True" placeholder="Subject..."/><br/>
<textarea class="span8" style="margin-top:5px; height: 140px;" name="description" placeholder="Enter your comment..."> </textarea><br/>
<button class="btn">Send message</button>
</form>
</xpath>
</field>
</record>
<template id="thanks">
<t t-call="website.layout">
<t t-set="title">Thank You!</t>
<div class="container">
<div class="oe_row">
<h2 class="oe_slogan">Thanks for your message.</h2>
<template id="contactus_form" name="Contact Form" inherit_id="website.contactus" inherit_option_id="website.contactus">
<xpath expr="//div[@name='mail_button']" position="replace">
<form action="/crm/contactus" method="post" class="form-horizontal">
<div class="control-group">
<label class="control-label" for="contact_name">Name</label>
<div class="controls">
<input type="text" name="contact_name" required="True"/>
</div>
</div>
</t>
<div class="control-group">
<label class="control-label" for="phone">Phone number</label>
<div class="controls">
<input type="text" name="phone" required="True" placeholder="e.g. (+32).81.81.37.00"/>
</div>
</div>
<div class="control-group">
<label class="control-label" for="email_from">Email</label>
<div class="controls">
<input type="text" name="email_from" required="True"/>
</div>
</div>
<div class="control-group">
<label class="control-label" for="name">Subject</label>
<div class="controls">
<input type="text" name="name" required="True"/>
</div>
</div>
<div class="control-group">
<label class="control-label" for="description">Your Question</label>
<div class="controls">
<textarea name="description"/>
</div>
</div>
<div class="control-group">
<div class="controls">
<button class="btn">Send</button>
</div>
</div>
</form>
</xpath>
</template>
<template id="thanks">
<t t-call="website.layout">
<t t-set="title">Message Sent</t>
<div class="container">
<div class="alert mt32">
Your message has been sent successfully.
<button type="button" class="close" data-dismiss="alert">&amp;times;</button>
</div>
<h2>Thanks!</h2>
<p>
We will get back to you shortly.
</p><p class="mt64">
If you have an emergency, do not hesitate to contact us by phone:
</p>
<ul class='unstyled'>
<li><i class="icon-phone"></i> : <span t-field="res_company.phone"/></li>
<li><i class="icon-envelope"></i> : <span t-field="res_company.email"></span></li>
</ul>
</div>
</t>
</template>
</data>
</openerp>
+3 -3
View File
@@ -1,6 +1,7 @@
{
'name': 'Website Event',
'category': 'mail',
'name': 'Online Events',
'category': 'Website',
'summary': 'Schedule, Promote and Sell Events Online',
'version': '1.0',
'description': """
OpenERP Blog
@@ -16,5 +17,4 @@ OpenERP Blog
],
'qweb': ['static/src/xml/*.xml'],
'installable': True,
'auto_install': True,
}
+45 -17
View File
@@ -14,8 +14,8 @@ import werkzeug
class website_event(http.Controller):
@http.route(['/event'], type='http', auth="public")
def events(self, **searches):
@http.route(['/event/', '/event/page/<int:page>/'], type='http', auth="public")
def events(self, page=1, **searches):
website = request.registry['website']
event_obj = request.registry['event.event']
@@ -80,13 +80,17 @@ class website_event(http.Controller):
countries = event_obj.read_group(request.cr, request.uid, domain, ["id", "country_id"], groupby="country_id", orderby="country_id")
countries.insert(0, {'country_id_count': event_obj.search(request.cr, request.uid, domain, count=True), 'country_id': ("all", _("All Countries"))})
step = 5
event_count = event_obj.search(request.cr, request.uid, dom_without("none"), count=True)
pager = website.pager(url="/event/", total=event_count, page=page, step=step, scope=5)
obj_ids = event_obj.search(request.cr, request.uid, dom_without("none"), limit=step, offset=pager['offset'], order="date_begin DESC")
obj_ids = event_obj.search(request.cr, request.uid, dom_without("none"), order="date_begin DESC")
values = website.get_rendering_context({
'event_ids': event_obj.browse(request.cr, request.uid, obj_ids),
'dates': dates,
'types': types,
'countries': countries,
'pager': pager,
'searches': searches,
'search_path': "?%s" % urllib.urlencode(searches),
})
@@ -99,24 +103,48 @@ class website_event(http.Controller):
event = request.registry['event.event'].browse(request.cr, request.uid, event_id, {'show_address': 1})
values = website.get_rendering_context({
'event_id': event,
'google_map_url': "http://maps.googleapis.com/maps/api/staticmap?center=%s&sensor=false&zoom=12&size=298x298" % urllib.quote_plus('%s, %s %s, %s' % (event.street, event.city, event.zip, event.country_id and event.country_id.name_get()[0][1] or ''))
})
return website.render("website_event.detail", values)
@http.route(['/event/<int:event_id>/add_cart'], type='http', auth="public")
def add_cart(self, event_id=None, **post):
if not post:
order_line_obj = request.registry.get('sale.order.line')
ticket_obj = request.registry.get('event.event.ticket')
order = request.registry['website'].get_rendering_context()['order']
partner_id = request.registry.get('res.users').browse(request.cr, SUPERUSER_ID, request.uid).partner_id.id
context = {}
fields = [k for k, v in order_line_obj._columns.items()]
values = order_line_obj.default_get(request.cr, SUPERUSER_ID, fields, context=context)
_values = None
for key, value in post.items():
quantity = int(value)
ticket_id = key.split("-")[0] == 'ticket' and int(key.split("-")[1]) or None
if not ticket_id or not quantity:
continue
ticket = ticket_obj.browse(request.cr, request.uid, ticket_id)
values['product_id'] = ticket.product_id.id
values['event_id'] = ticket.event_id.id
values['event_ticket_id'] = ticket.id
values['product_uom_qty'] = quantity
values['price_unit'] = ticket.price
values['order_id'] = order.id
values['name'] = "%s: %s" % (ticket.event_id.name, ticket.name)
ticket.check_registration_limits_before(quantity)
# change and record value
pricelist_id = order.pricelist_id and order.pricelist_id.id or False
_values = order_line_obj.product_id_change(request.cr, SUPERUSER_ID, [], pricelist_id, ticket.product_id.id, partner_id=partner_id, context=context)['value']
_values.update(values)
order_line_id = order_line_obj.create(request.cr, SUPERUSER_ID, _values, context=context)
order.write({'order_line': [(4, order_line_id)]}, context=context)
if not _values:
return werkzeug.utils.redirect("/event/%s/" % event_id)
return werkzeug.utils.redirect("/shop/checkout")
@http.route(['/event/publish'], type='http', auth="public")
def publish(self, **post):
obj_id = int(post['id'])
data_obj = request.registry['event.event']
obj = data_obj.browse(request.cr, request.uid, obj_id)
data_obj.write(request.cr, request.uid, [obj_id], {'website_published': not obj.website_published})
obj = data_obj.browse(request.cr, request.uid, obj_id)
return obj.website_published and "1" or "0"
+17 -28
View File
@@ -1,36 +1,25 @@
# -*- coding: utf-8 -*-
from openerp.osv import osv, fields
from openerp import SUPERUSER_ID
class event(osv.osv):
_inherit = 'event.event'
_columns = {
'website_published': fields.boolean('Available in the website'),
'description_website': fields.html('Description for the website'),
'event_product_ids': fields.one2many('event.event.product', "event_id", "Event"),
'organizer_id': fields.many2one('res.partner', "Orgonizer"),
'phone': fields.related('orgonizer_id', 'phone', type='char', string='Phone'),
'email': fields.related('orgonizer_id', 'email', type='char', string='Email'),
}
class event_product(osv.osv):
_name = 'event.event.product'
_columns = {
'deadline': fields.date("Sales End"),
'event_id': fields.many2one('event.event', "Event"),
'product_id': fields.many2one('product.product', 'Product', domain=[("event_type_id", "!=", False)]),
'price': fields.float('Price'),
'qty': fields.integer('Current Registrations', readonly=True),
'max_qty': fields.integer('Maximum Registrations'),
}
def onchange_product_id(self, cr, uid, ids, product_id=False, context=None):
return {'value': {'price': self.pool.get("product.product").browse(cr, uid, product_id).list_price or 0}}
# defined for access rules
class product(osv.osv):
_inherit = 'product.product'
_columns = {
'event_product_ids': fields.one2many('event.event.product', 'product_id', 'Linked event product'),
'event_ticket_ids': fields.one2many('event.event.ticket', 'product_id', 'Event Tickets'),
}
class event_event(osv.osv):
_inherit = "event.event"
def google_map_img(self, cr, uid, ids, zoom=8, width=298, height=298, context=None):
partner = self.browse(cr, uid, ids[0], context=context)
if partner.address_id:
return self.browse(cr, SUPERUSER_ID, ids[0], context=context).address_id.google_map_img()
def google_map_link(self, cr, uid, ids, zoom=8, context=None):
partner = self.browse(cr, uid, ids[0], context=context)
if partner.address_id:
return self.browse(cr, SUPERUSER_ID, ids[0], context=context).address_id.google_map_link()
@@ -1,4 +1,4 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_event_event_public,event.event.public,event.model_event_event,base.group_public,1,0,0,0
access_event_event_product_public,event.event.product.public,website_event.model_event_event_product,base.group_public,1,0,0,0
access_event_event_ticket_public,event.event.ticket.public,event_sale.model_event_event_ticket,base.group_public,1,0,0,0
access_event_product_product_public,event.product.product.public,product.model_product_product,base.group_public,1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_event_event_public event.event.public event.model_event_event base.group_public 1 0 0 0
3 access_event_event_product_public access_event_event_ticket_public event.event.product.public event.event.ticket.public website_event.model_event_event_product event_sale.model_event_event_ticket base.group_public 1 0 0 0
4 access_event_product_product_public event.product.product.public product.model_product_product base.group_public 1 0 0 0
@@ -11,9 +11,9 @@
<field name="perm_create" eval="False"/>
<field name="perm_unlink" eval="False"/>
</record>
<record id="event_event_product_public" model="ir.rule">
<field name="name">event product: Public</field>
<field name="model_id" ref="website_event.model_event_event_product"/>
<record id="event_event_ticket_public" model="ir.rule">
<field name="name">event ticket: Public</field>
<field name="model_id" ref="event_sale.model_event_event_ticket"/>
<field name="domain_force">[('event_id.website_published', '=', True)]</field>
<field name="groups" eval="[(4, ref('base.group_public'))]"/>
<field name="perm_read" eval="True"/>
@@ -24,7 +24,7 @@
<record id="event_product_product_public" model="ir.rule">
<field name="name">Product linked to event: Public</field>
<field name="model_id" ref="product.model_product_product"/>
<field name="domain_force">[("event_type_id", "!=", False), ('event_product_ids.event_id.website_published', '=', True)]</field>
<field name="domain_force">[("event_type_id", "!=", False), ('event_ticket_ids.event_id.website_published', '=', True)]</field>
<field name="groups" eval="[(4, ref('base.group_public'))]"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="False"/>
@@ -0,0 +1,261 @@
<section class="oe_container">
<div class="oe_row oe_spaced">
<div class="oe_span12">
<h2 class="oe_slogan">Organize Events, Trainings &amp; Webinars</h2>
<h3 class="oe_slogan">Schedule, Promote, Sell, Organize</h3>
</div>
<div class="oe_span6">
<div class="oe_demo oe_picture oe_screenshot">
<a href="https://www.openerp.com/saas_master/demo?lang=en_US&module=website_event">
<img src="">
</a>
<div class="oe_demo_footer oe_centeralign">Online Demo</div>
</div>
</div>
<div class="oe_span6">
<p class='oe_mt32'>
Schedule, promote, sell and organize your events online with no
effort. Whether you organize meetings, conferences, trainings
or webinars, OpenERP gives you all the features you need to
manage all aspects of your event.
</p>
<div class="oe_centeralign oe_websiteonly">
<a href="http://www.openerp.com/start?app=website_event" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> online store</a>
</div>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row">
<h2 class="oe_slogan">Create Awesome Event Pages</h2>
<h3 class="oe_slogan">Get rid of old WYSIWYG editors</h3>
<div class="oe_span6">
<p class='oe_mt32'>
Drag &amp; Drop well designed <em>'Building Blocks'</em> to
create beautifull event pages that your customer will love.
Use pre-defined building blocks like; speakers, schedules,
social icons, etc.
</p><p>
OpenERP's unique <em>'edit inline'</em> approach makes website
creation surprisingly easy. "Want to introduce a speaker? to
change the price of a ticket? to update a banner? promote sponsors?"
just click and change. What you see is what you get. Really.
</p>
</div>
<div class="oe_span6">
<div class="oe_bg_img oe_centered">
<img class="oe_picture" src="">
</div>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row">
<h2 class="oe_slogan">Sell Tickets Online</h2>
<h3 class="oe_slogan">Mass Mailing &amp; Social Media Icons</h3>
<div class="oe_span6">
<img class="oe_picture oe_screenshot" src="">
</div>
<div class="oe_span6">
<p class='oe_mt32'>
Use the multi-ticketing feature to sell registrations to your
event. Events can be free or for a fee. Attendees can pay online
with a credit card or on invoice, based on your configuration.
</p><p>
Boost your sales with early-bird prices, special conditions for
members, or extra services with multiple tickets.
</p>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row">
<h2 class="oe_slogan">Promote Events Efficiently</h2>
<h3 class="oe_slogan">Mass Mailing &amp; Social Media Icons</h3>
<div class="oe_span6">
<img class="oe_picture oe_screenshot" src="">
</div>
<div class="oe_span6">
<p class='oe_mt32'>
Use the segmentation, the social network integration and mass
mailing features to promote your events to the right audience.
Setup automated emails to attendees to send them last minute
details.
</p>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row">
<h2 class="oe_slogan">A Clean Google Analytics Integration</h2>
<h3 class="oe_slogan">Control your sales funnel with Google Analytics</h3>
<div class="oe_span6">
<p class='oe_mt32'>
Get a clear visibility of your sales funnel. OpenERP's Google
Analytics trackers are configured by default to track all kind of
events related to shopping carts, call-to-actions, etc.
</p><p>
As OpenERP marketing tools (mass mailing, campaigns, etc) are also
linked with Google Analytics, you get a 360° view of your business.
</p>
</div>
<div class="oe_span6">
<img class="oe_picture oe_screenshot" src="">
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row">
<h2 class="oe_slogan">Designer-Friendly Themes</h2>
<h3 class="oe_slogan">Designers love working on OpenERP</h3>
<div class="oe_span6">
<p class='oe_mt32'>
Themes are awesome and easy to design. You don't need to develop
to create new pages, themes or building blocks. We use a clean
HTML structure, a <a href="http://getbootstrap.com/">bootstrap</a>
CSS and our modularity allows to distribute your themes easily.
</p><p>
The building block approach allows the website to stay clean
after the end-users start creating new contents.
</p>
</div>
<div class="oe_span6">
<div class="oe_row_img oe_centered">
<img class="oe_picture" src="">
</div>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row">
<h2 class="oe_slogan">Make Your Event More Visible</h2>
<h3 class="oe_slogan">SEO tools at your finger tips</h3>
<div class="oe_span6">
<div class="oe_bg_img">
<img class="oe_picture oe_screenshot" src="">
</div>
</div>
<div class="oe_span6">
<p class='oe_mt32'>
SEO tools are ready to use, with no configuration required.
OpenERP suggests keywords according to Google most searched
terms, Google Analytics tracks your shopping cart events,
sitemap are created automatically.
</p><p>
We even do structured content automatically to promote your
events and products efficiently in Google.
</p>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row">
<h2 class="oe_slogan">Leverage Social Media</h2>
<h3 class="oe_slogan">Optimize: from Ads to Conversions</h3>
<div class="oe_span6">
<p class='oe_mt32'>
Create new landing pages easily with the OpenERP inline edition
feature. Send visitors of your different marketing campaigns to
event landing pages to optimize conversions.
</p>
</div>
<div class="oe_span6">
<div class="oe_bg_img">
<img class="oe_picture oe_screenshot" src="">
</div>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row">
<h2 class="oe_slogan">And Much More...</h2>
<div class="oe_span4">
<h3 class="oe_slogan">Schedule</h3>
<ul>
<li>Calendar of Events</li>
<li>Publish related documents</li>
<li>Ressources allocation</li>
<li>Automate purchases (cathering...)</li>
<li>Multiple locations and organizers</li>
<li>Mobile Interface</li>
</ul>
</div>
<div class="oe_span4">
<h3 class="oe_slogan">Sell</h3>
<ul>
<li>Online or offline sales</li>
<li>Automated invoicing</li>
<li>Cancellation policies</li>
<li>Specific prices for members</li>
<li>Dashboards and reporting</li>
</ul>
</div>
<div class="oe_span4">
<h3 class="oe_slogan">Organize</h3>
<ul>
<li>Advanced Planification</li>
<li>Print Badges</li>
<li>Automate Follow-up Emails</li>
<li>Min/Max capacities</li>
<li>Manage classes and ressources</li>
<li>Create group of attendees</li>
<li>Automate statisfaction surveys</li>
</ul>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row">
<h2 class="oe_slogan">Fully Integrated With Others Apps</h2>
<h3 class="oe_slogan">Get hundreds of open source apps for free</h3>
<div class="oe_span4">
<a href="/apps/website_sale">
<h3>eCommerce</h3>
<div class="oe_row_img oe_centered">
<img class="oe_picture oe_screenshot" src="">
</div>
</a>
<p>
Promote products, sell online, optimize visitors' shopping experiences.
</p>
</div>
<div class="oe_span4">
<a href="/apps/website_mail">
<h3>Blogs</h3>
<div class="oe_row_img oe_centered">
<img class="oe_picture oe_screenshot" src="">
</div>
</a>
<p>
Write news, attract new visitors, build customer loyalty.
</p>
</div>
<div class="oe_span4">
<a href="/apps/website_hr">
<h3>Our Team</h3>
<div class="oe_row_img oe_centered">
<img class="oe_picture oe_screenshot" src="">
</div>
</a>
<p>
Create a great "About us" page by presenting your team
efficiently.
</p>
</div>
<div class="oe_span12 oe_centered oe_muted">
<a href="/apps">
and hundreds more applications...
</a>
</div>
</div>
</section>
@@ -1,18 +0,0 @@
$(document).ready(function () {
$(document).on('click', '.js_publish, .js_unpublish', function (e) {
e.preventDefault();
var $link = $(this).parent();
$link.find('.js_publish, .js_unpublish').addClass("hidden");
var $unp = $link.find(".js_unpublish");
var $p = $link.find(".js_publish");
$.post('/event/publish', {'id': $link.data('id')}, function (result) {
if (+result) {
$p.addClass("hidden");
$unp.removeClass("hidden");
} else {
$p.removeClass("hidden");
$unp.addClass("hidden");
}
});
});
});
+90 -105
View File
@@ -2,68 +2,29 @@
<openerp>
<data>
<record id="view_event_form" model="ir.ui.view">
<field name="name">view_event_form</field>
<field name="model">event.event</field>
<field name="inherit_id" ref="event.view_event_form"/>
<field name="arch" type="xml">
<data>
<xpath expr="//notebook" position="inside">
<page string="Tarifs">
<field name="product_ids">
<tree string="Payments" editable="bottom">
<field name="product_id" on_change='onchange_product_id(product_id)'/>
<field name="deadline"/>
<field name="price"/>
<field name="max_qty"/>
</tree>
</field>
</page>
</xpath>
<field name="address_id" position="after">
<field name="organizer_id"/>
</field>
</data>
</field>
</record>
<!-- Layout add nav and footer -->
<record id="header_website_event" model="ir.ui.view">
<field name="name">header_website_event</field>
<field name="inherit_id" ref="website.header"/>
<field name="arch" type="xml">
<data>
<xpath expr="(//li)[last()]" position="after">
<li class="pull-right"><a href="/event">Events</a></li>
</xpath>
</data>
</field>
</record>
<record id="footer_website_event" model="ir.ui.view">
<field name="name">footer_website_event</field>
<field name="inherit_id" ref="website.footer"/>
<field name="arch" type="xml">
<data>
<xpath expr="//a[@href='/page/website.contactus']" position="after">
<li><a href="/event">Events</a></li>
</xpath>
</data>
</field>
</record>
<template id="footer_custom" inherit_id="website.layout" name="Custom Footer">
<xpath expr="//body/header//ul[@id='top_menu']/li[last()]" position="before">
<li><a href="/event">Events</a></li>
</xpath>
<xpath expr="//body/footer//a[@href='/page/website.contactus']" position="after">
<li><a href="/event">Events</a></li>
</xpath>
</template>
<!-- Page -->
<template id="index">
<template id="index" name="Events">
<t t-call="website.layout">
<t t-set="head">
<script type="text/javascript" src="/website_event/static/src/js/website_event.js"></script>
<t t-raw="head"/>
<script type="text/javascript" src="/website_hr/static/src/js/website_hr.js"></script>
<t t-raw="head or ''"/>
</t>
<t t-set="title">Events</t>
<div class="container mt48">
<div class="row">
<div class="span4 css_noprint">
<div class="span4 css_noprint" id="left_column">
<ul class="nav nav-list">
<li class="nav-header">Date</li>
<t t-foreach="dates" t-as="date">
@@ -72,30 +33,23 @@
</li>
</t>
</ul>
<ul class="nav nav-list">
<li class="nav-header">Category</li>
<t t-foreach="types">
<li t-if="type" t-att-class="searches.get('type') == str(type and type[0]) and 'active' or ''">
<a t-att-href="'/event/%%s&amp;type=%%s' %% (search_path, type[0])"><t t-esc="type[1]"/> <small>(<t t-esc="type_count"/>)</small></a>
</li>
</div>
<div class='span8 navbar navbar-inverse'>
<div class='navbar-inner'>
<t t-call="website.pager" >
<t t-set="classname">pull-left</t>
</t>
</ul>
<ul class="nav nav-list">
<li class="nav-header">Location</li>
<t t-foreach="countries">
<li t-if="country_id" t-att-class="searches.get('country') == str(country_id and country_id[0]) and 'active' or ''">
<a t-att-href="'/event/%%s&amp;country=%%s' %% (search_path, country_id[0])"><t t-esc="country_id[1]"/><small>(<t t-esc="country_id_count"/>)</small></a>
</li>
</t>
</ul>
</div>
</div>
<div class="span8">
<ul class="media-list mt32">
<ul class="media-list">
<li t-foreach="event_ids" t-as="event_id" class="media thumbnail">
<div class="media-body">
<t t-if="event_id.register_avail">
<span t-if="event_id.register_avail == 9999" class="label pull-right">No ticket available.</span>
<span t-if="event_id.register_avail != 9999" t-att-class="'label pull-right label-%%s' %% (event_id.register_avail &lt;= 10 and 'warning' or 'info')">
<span t-if="not event_id.event_ticket_ids" class="label pull-right">No tickets needed.</span>
<t t-if="event_id.event_ticket_ids">
<span t-if="event_id.register_avail == 9999" class="label pull-right label-info">Tickets availables.</span>
<span t-if="not event_id.register_avail" class="label pull-right">No ticket available.</span>
<span t-if="event_id.register_avail and event_id.register_avail != 9999" t-att-class="'label pull-right label-%%s' %% (event_id.register_avail &lt;= 10 and 'warning' or 'info')">
<t t-if="event_id.register_avail &lt;= 10">Only</t>
<t t-esc="event_id.register_avail"/>
<t t-if="event_id.register_avail &gt; 1">tickets </t>
@@ -104,10 +58,7 @@
</span>
</t>
<h4 class="media-heading"><a t-att-href="'/event/%%s/' %% event_id.id"><span t-field="event_id.name"> </span></a></h4>
<a t-if="editable" href="#" t-att-data-id="event_id.id" class="pull-right">
<span t-att-class="'label label-success js_unpublish %%s' %% (not event_id.website_published and 'hidden' or '')">Click to Unpublish</span>
<span t-att-class="'label label-important js_publish %%s' %% (event_id.website_published and 'hidden' or '')">Click to Publish</span>
</a>
<t t-call="website.publish"><t t-set="object" t-value="event_id"/></t>
<div>
<span t-field="event_id.type">: </span>
<t t-if="event_id.user_id">
@@ -124,23 +75,53 @@
</li>
</ul>
</div>
<div class="span8 offset4 text-center">
<t t-call="website.pager" />
</div>
</div>
</div>
</t>
</template>
<template id="event_category" inherit_id="website_event.index" inherit_option_id="website_event.index" name="Category">
<xpath expr="//div[@id='left_column']" position="inside">
<ul class="nav nav-list">
<li class="nav-header">Category</li>
<t t-foreach="types">
<li t-if="type" t-att-class="searches.get('type') == str(type and type[0]) and 'active' or ''">
<a t-att-href="'/event/%%s&amp;type=%%s' %% (search_path, type[0])"><t t-esc="type[1]"/> <small>(<t t-esc="type_count"/>)</small></a>
</li>
</t>
</ul>
</xpath>
</template>
<template id="event_location" inherit_id="website_event.index" inherit_option_id="website_event.index" name="Location">
<xpath expr="//div[@id='left_column']" position="inside">
<ul class="nav nav-list">
<li class="nav-header">Location</li>
<t t-foreach="countries">
<li t-if="country_id" t-att-class="searches.get('country') == str(country_id and country_id[0]) and 'active' or ''">
<a t-att-href="'/event/%%s&amp;country=%%s' %% (search_path, country_id[0])"><t t-esc="country_id[1]"/><small>(<t t-esc="country_id_count"/>)</small></a>
</li>
</t>
</ul>
</xpath>
</template>
<template id="detail">
<t t-call="website.layout">
<t t-set="head">
<script type="text/javascript" src="/website_event/static/src/js/website_event.js"></script>
<t t-raw="head"/>
<t t-raw="head or ''"/>
</t>
<t t-set="title">Events</t>
<div class="container mt48">
<div class="row">
<div class="span4 css_noprint">
<h4>When &amp; Where</h4>
<img t-att-src="google_map_url"/>
<a t-att-href="event_id.google_map_link()" target="_BLANK">
<img class="thumbnail" t-att-src="event_id.google_map_img()"/>
</a>
<address>
<pre t-field="event_id.address_id"/>
<i class="icon-time"></i> <span t-field="event_id.date_begin"> </span><br/>
@@ -153,9 +134,11 @@
</div>
<div class="span8">
<div class="media-body">
<t t-if="event_id.register_avail">
<span t-if="event_id.register_avail == 9999" class="label pull-right">No ticket available.</span>
<span t-if="event_id.register_avail != 9999" t-att-class="'label pull-right label-%%s' %% (event_id.register_avail &lt;= 10 and 'warning' or 'info')">
<span t-if="not event_id.event_ticket_ids" class="label pull-right">No tickets needed.</span>
<t t-if="event_id.event_ticket_ids">
<span t-if="event_id.register_avail == 9999" class="label pull-right">Tickets availables.</span>
<span t-if="not event_id.register_avail" class="label pull-right">No ticket available.</span>
<span t-if="event_id.register_avail and event_id.register_avail != 9999" t-att-class="'label pull-right label-%%s' %% (event_id.register_avail &lt;= 10 and 'warning' or 'info')">
<t t-if="event_id.register_avail &lt;= 10">Only</t>
<t t-esc="event_id.register_avail"/>
<t t-if="event_id.register_avail &gt; 1">tickets </t>
@@ -164,38 +147,40 @@
</span>
</t>
<h4 class="media-heading"><a t-att-href="'/event/%%s/' %% event_id.id"><span t-field="event_id.name"> </span></a></h4>
<t t-call="website.publish"><t t-set="object" t-value="event_id"/></t>
<h5 class="media-heading">
<span t-field="event_id.address_id"/><br/>
<i class="icon-time"></i> <span t-field="event_id.date_begin"/><br/>
<i class="icon-time"></i> <span t-field="event_id.date_end"/>
</h5>
<a t-if="editable" href="#" t-att-data-id="event_id.id" class="pull-right">
<span t-att-class="'label label-success js_unpublish %%s' %% (not event_id.website_published and 'hidden' or '')">Click to Unpublish</span>
<span t-att-class="'label label-important js_publish %%s' %% (event_id.website_published and 'hidden' or '')">Click to Publish</span>
</a>
<h4 t-if="event_id.event_product_ids">Ticket Information</h4>
<form t-att-action="'/event/%%s/add_cart' %% event_id.id" method="post" t-if="event_id.event_product_ids">
<h4 t-if="event_id.event_ticket_ids">Ticket Information</h4>
<form t-att-action="'/event/%%s/add_cart' %% event_id.id" method="post" t-if="event_id.event_ticket_ids">
<table class="table">
<tr>
<th>Ticket type</th>
<th>Sales End</th>
<th>Price</th>
<th>Seats</th>
<th>Quantity</th>
</tr>
<tr t-foreach="event_id.event_product_ids" t-as="prod">
<td t-field="prod.product_id"/>
<td t-field="prod.deadline"/>
<td t-field="prod.price"/>
<td><span t-if="prod.max_qty"><t t-esc="prod.qty"/>/<t t-field="prod.max_qty"/></span></td>
<td>
<select t-att-name="'product[%%s]' %% prod.id">
<t t-foreach="range(0,10)" t-as="nb"><option t-esc="nb"/></t>
</select>
</td>
</tr>
<thead>
<tr>
<th>Ticket type</th>
<th>Sales End</th>
<th>Price</th>
<th>Seats</th>
<th>Quantity</th>
</tr>
</thead>
<tbody>
<tr t-foreach="event_id.event_ticket_ids" t-as="ticket">
<td t-field="ticket.product_id"/>
<td t-field="ticket.deadline"/>
<td t-field="ticket.price"/>
<td><span t-if="ticket.register_max"><t t-esc="ticket.register_current"/>/<t t-field="ticket.register_max"/></span></td>
<td>
<select t-if="ticket.register_avail" t-att-name="'ticket-%%s' %% ticket.id">
<t t-foreach="range(0, ticket.register_avail > 9 and 10 or ticket.register_avail+1 )" t-as="nb"><option t-esc="nb"/></t>
</select>
<span t-if="not ticket.register_avail">Not ticket available</span>
</td>
</tr>
</tbody>
</table>
<button type="submit" class="btn btn-primary">Order Now</button>
<button type="submit" class="btn btn-primary" t-if="event_id.register_avail">Order Now</button>
</form>
<h4>Event Details</h4>
<div t-field="event_id.description_website"></div>
@@ -206,4 +191,4 @@
</t>
</template>
</data>
</openerp>
</openerp>
+3 -3
View File
@@ -1,6 +1,7 @@
{
'name': 'Website Team',
'category': 'mail',
'name': 'Team Page',
'category': 'Website',
'summary': 'Publish Your Team, Employees',
'version': '1.0',
'description': """
OpenERP Blog
@@ -16,5 +17,4 @@ OpenERP Blog
],
'qweb': ['static/src/xml/*.xml'],
'installable': True,
'auto_install': True,
}
+2 -24
View File
@@ -5,7 +5,7 @@ from openerp.addons.web.http import request
class website_hr(http.Controller):
@http.route(['/hr'], type='http', auth="public")
@http.route(['/page/website.aboutus'], type='http', auth="public")
def blog(self, **post):
website = request.registry['website']
hr_obj = request.registry['hr.employee']
@@ -13,26 +13,4 @@ class website_hr(http.Controller):
values = website.get_rendering_context({
'employee_ids': hr_obj.browse(request.cr, request.uid, employee_ids)
})
return website.render("website_hr.index", values)
@http.route(['/hr/publish'], type='http', auth="public")
def publish(self, **post):
obj_id = int(post['id'])
data_obj = request.registry['hr.employee']
obj = data_obj.browse(request.cr, request.uid, obj_id)
data_obj.write(request.cr, request.uid, [obj_id], {'website_published': not obj.website_published})
obj = data_obj.browse(request.cr, request.uid, obj_id)
return obj.website_published and "1" or "0"
@http.route(['/hr/publish_contact'], type='http', auth="public")
def publish_contact(self, **post):
obj_id = int(post['id'])
data_obj = request.registry['hr.employee']
obj = data_obj.browse(request.cr, request.uid, obj_id)
data_obj.write(request.cr, request.uid, [obj_id], {'website_published_on_contact_form': not obj.website_published_on_contact_form})
obj = data_obj.browse(request.cr, request.uid, obj_id)
return obj.website_published_on_contact_form and "1" or "0"
return website.render("website.aboutus", values)
+2
View File
@@ -9,3 +9,5 @@ class hr(osv.osv):
'website_published': fields.boolean('Available in the website'),
}
def img(self, cr, uid, ids, field='image_small', context=None):
return "/website/image?model=%s&field=%s&id=%s" % (self._name, field, ids[0])
@@ -0,0 +1,183 @@
<section class="oe_container">
<div class="oe_row oe_spaced">
<div class="oe_span12">
<h2 class="oe_slogan">Open Source Job Board</h2>
<h3 class="oe_slogan">Organize your job postings and applications</h3>
</div>
<div class="oe_span6">
<div class="oe_demo oe_picture oe_screenshot">
<a href="https://www.openerp.com/saas_master/demo?lang=en_US&module=website_hr">
<img src="">
</a>
<div class="oe_demo_footer oe_centeralign">Online Demo</div>
</div>
</div>
<div class="oe_span6">
<p class='oe_mt32'>
Organize your job board, promote your job announces and keep
track of application submissions easily. Follow every applicant
and build up a database of skills and profiles.
</p>
<div class="oe_centeralign oe_websiteonly">
<a href="http://www.openerp.com/start?app=website_hr" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> online store</a>
</div>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row">
<h2 class="oe_slogan">Create Awsome Job Description Pages</h2>
<h3 class="oe_slogan">Get rid of old WYSIWYG editors</h3>
<div class="oe_span6">
<p class='oe_mt32'>
Get a clean and professional look for your job annouces.
OpenERP's unique <em>'edit inline'</em> approach makes website
and job descriptions creation surprisingly easy.
</p><p>
Drag &amp; Drop well designed <em>'Building Blocks'</em> to
create beautifull job descriptions and announces that
emphasizes the quality of your company.
</p>
</div>
<div class="oe_span6">
<div class="oe_bg_img oe_centered">
<img class="oe_picture" src="">
</div>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row">
<h2 class="oe_slogan">Post Your Jobs on Best Job Boards</h2>
<h3 class="oe_slogan">LinkedIn, Monster, Kraigslist, Careerbuilder,...</h3>
<div class="oe_span6">
<img class="oe_picture oe_screenshot" src="">
</div>
<div class="oe_span6">
<p class='oe_mt32'>
Connect automatically to most famous job board websites;
linkedIn, Monster, Kraigslist, ... Every job position has a new
email address automatically assigned to route applications
automatically to the right job position.
</p><p>
Whether applicants contact you by email or using an online
form, you get all the data indexed automatically (resumes,
motivation letter) and you can answer in just a click, reusing
templates of answers.
</p>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row">
<h2 class="oe_slogan">Customize Your Recruitment Process</h2>
<h3 class="oe_slogan">Define your own stages and interviewers</h3>
<div class="oe_span6">
<p class='oe_mt32'>
Use the kanban view and customize the steps of your recruitments
process; pre-qualification, first interview, second interview,
negociaiton, ...
</p><p>
Get accurate statistics on your recruitment pipeline. Get reports
to compare the performance of your different investments on
external job boards.
</p>
</div>
<div class="oe_span6">
<img class="oe_picture oe_screenshot" src="">
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row">
<h2 class="oe_slogan">Streamline Your Recruitment Process</h2>
<h3 class="oe_slogan">Index resumes, track applicants, search profiles</h3>
<div class="oe_span6">
<img class="oe_picture oe_screenshot" src="hr_recruitment.png">
</div>
<div class="oe_span6">
<p class='oe_mt32'>
Follow applicants in your recruitment process with the smart
kanban view. Save time by automating some communications with
email templates.
</p><p>
Documents like resumes and motivation letters are indexed
automatically, allowing you to easily find for specific skills
and build up a database of profiles.
</p>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row">
<h2 class="oe_slogan">Integrated Surveys</h2>
<h3 class="oe_slogan">Define your own online or offline surveys</h3>
<div class="oe_span6">
<div class="oe_bg_img">
<img class="oe_picture" src="">
</div>
</div>
<div class="oe_span6">
<p class='oe_mt32'>
Create your own interview canvas based on our best practices.
Use the survey designer to adapt questions to your own process.
Ask the applicant to fill in the survey online, or the
interviewer to use it during real interviews.
</p>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row">
<h2 class="oe_slogan">Fully Integrated With Others Apps</h2>
<h3 class="oe_slogan">Get hundreds of open source apps for free</h3>
<div class="oe_span4">
<a href="/apps/website">
<h3>CMS</h3>
<div class="oe_row_img oe_centered">
<img class="oe_picture oe_screenshot" src="">
</div>
</a>
<p>
Easily create awesome websites with no technical knowledge required.
</p>
</div>
<div class="oe_span4">
<a href="/apps/website_mail">
<h3>Blogs</h3>
<div class="oe_row_img oe_centered">
<img class="oe_picture oe_screenshot" src="">
</div>
</a>
<p>
Write news, attract new visitors, build customer loyalty.
</p>
</div>
<div class="oe_span4">
<a href="/apps/website_event">
<h3>Online Events</h3>
<div class="oe_row_img oe_centered">
<img class="oe_picture oe_screenshot" src="">
</div>
</a>
<p>
Schedule, organize, promote or sell events online; conferences,
webinars, trainings, etc.
</p>
</div>
<div class="oe_span12 oe_centered oe_muted">
<a href="/apps">
and hundreds more applications...
</a>
</div>
</div>
</section>
-18
View File
@@ -1,18 +0,0 @@
$(document).ready(function () {
$(document).on('click', '.js_publish, .js_unpublish', function (e) {
e.preventDefault();
var $link = $(this).parent();
$link.find('.js_publish, .js_unpublish').addClass("hidden");
var $unp = $link.find(".js_unpublish");
var $p = $link.find(".js_publish");
$.post('/hr/publish', {'id': $link.data('id')}, function (result) {
if (+result) {
$p.addClass("hidden");
$unp.removeClass("hidden");
} else {
$p.removeClass("hidden");
$unp.addClass("hidden");
}
});
});
});
+36 -39
View File
@@ -2,56 +2,53 @@
<openerp>
<data>
<!-- Mail group for the company's jobs -->
<record id="website_mail_job" model="mail.group">
<field name="name">Job</field>
<field name="public">public</field>
<field name="description">Job offer displayed on your website</field>
</record>
<!-- Layout add nav and footer -->
<record id="footer_website_hr" model="ir.ui.view">
<field name="name">footer_website_hr</field>
<field name="inherit_id" ref="website.footer"/>
<field name="arch" type="xml">
<data>
<xpath expr="//a[@href='/page/website.contactus']" position="after">
<li><a href="/hr">Team</a></li>
</xpath>
</data>
</field>
</record>
<template id="footer_custom" inherit_id="website.layout" name="Custom Footer">
<xpath expr="//body/footer//a[@href='/page/website.aboutus']" position="after">
<li><a href="/blog/%(website_hr.website_mail_job)d/">Jobs</a></li>
</xpath>
</template>
<!-- Page -->
<template id="index">
<t t-call="website.layout">
<template id="aboutus" inherit_id="website.aboutus">
<xpath expr="//div[@class='span8']" position="inside">
<t t-set="head">
<script type="text/javascript" src="/website_hr/static/src/js/hr.js"></script>
<t t-raw="head"/>
<script type="text/javascript" src="/website_hr/static/src/js/website_hr.js"></script>
<t t-raw="head or ''"/>
</t>
<t t-set="title">Team</t>
<div class="container">
<div class="thumbnails">
<div t-foreach="employee_ids" t-as="employee_id" class="span4 mt16">
<div class="media thumbnail">
<a class="pull-left" href="#">
<img class="media-object" t-att-src="'data:image/png;base64,%%s' %% employee_id.image_small"/>
</a>
<div class="media-body">
<div t-if="editable" class="pull-right">
<a href="#" t-att-data-id="employee_id.id">
<span t-att-class="'label label-success js_unpublish %%s' %% (not employee_id.website_published and 'hidden' or '')">Click to Unpublish</span>
<span t-att-class="'label label-important js_publish %%s' %% (employee_id.website_published and 'hidden' or '')">Click to Publish</span>
</a>
</div>
<h5 class="media-heading" t-field="employee_id.name"/>
<div t-field="employee_id.department_id"/>
<div t-field="employee_id.job_id"/>
<div t-field="employee_id.work_location"/>
<div t-field="employee_id.work_phone"/>
<div t-field="employee_id.work_email"/>
<div t-field="employee_id.public_info"/>
</div>
<h3>Our team</h3>
<div class="thumbnails">
<div t-foreach="employee_ids" t-as="employee_id" class="span4 mt16">
<div class="media thumbnail">
<a class="pull-left" href="#">
<img class="media-object" t-att-src="employee_id.img('image_small')"/>
</a>
<div class="media-body">
<t t-call="website.publish"><t t-set="object" t-value="employee_id"/></t>
<h5 class="media-heading" t-field="employee_id.name"/>
<div t-field="employee_id.department_id"/>
<div t-field="employee_id.job_id"/>
<div t-field="employee_id.work_location"/>
<div t-field="employee_id.work_phone"/>
<div t-field="employee_id.work_email"/>
<div t-field="employee_id.public_info"/>
</div>
</div>
</div>
</div>
</t>
</xpath>
</template>
</data>
</openerp>
+3 -3
View File
@@ -1,6 +1,7 @@
{
'name': 'Website Blog',
'category': 'mail',
'name': 'Blogs',
'category': 'Website',
'summary': 'News, Blogs, Announces, Discussions',
'version': '1.0',
'description': """
OpenERP Blog
@@ -16,5 +17,4 @@ OpenERP Blog
],
'qweb': ['static/src/xml/*.xml'],
'installable': True,
'auto_install': True,
}
+11 -28
View File
@@ -13,8 +13,9 @@ _months = {1:_("January"), 2:_("February"), 3:_("March"), 4:_("April"), 5:_("May
class website_mail(http.Controller):
@http.route(['/blog', '/blog/<int:mail_group_id>/', '/blog/<int:mail_group_id>/<int:blog_id>/'], type='http', auth="public")
def blog(self, mail_group_id=None, blog_id=None, **post):
@http.route(['/blog/', '/blog/<int:mail_group_id>/', '/blog/<int:mail_group_id>/<int:blog_id>/',
'/blog/page/<int:page>/', '/blog/<int:mail_group_id>/page/<int:page>/', '/blog/<int:mail_group_id>/<int:blog_id>/page/<int:page>/'], type='http', auth="public")
def blog(self, mail_group_id=None, blog_id=None, page=0, **post):
website = request.registry['website']
group_obj = request.registry['mail.group']
message_obj = request.registry['mail.message']
@@ -24,8 +25,6 @@ class website_mail(http.Controller):
'blog_ids': None,
'blog_id': None,
'nav_list': dict(),
'prev_date': None,
'next_date': None,
'mail_group_id': mail_group_id,
'subscribe': post.get('subscribe'),
'website': website,
@@ -38,27 +37,22 @@ class website_mail(http.Controller):
domain = mail_group_id and [("res_id", "=", mail_group_id)] or []
for group in message_obj.read_group(request.cr, request.uid, domain + group_obj.get_public_blog(request.cr, request.uid), ['subject', 'date'], groupby="date", orderby="create_date asc"):
for group in message_obj.read_group(request.cr, request.uid, domain + group_obj.get_domain_public_blog(request.cr, request.uid), ['subject', 'date'], groupby="date", orderby="create_date asc"):
year = group['date'].split(" ")[1]
if not values['nav_list'].get(year):
values['nav_list'][year] = {'name': year, 'date_count': 0, 'months': []}
values['nav_list'][year]['date_count'] += group['date_count']
values['nav_list'][year]['months'].append(group)
if post.get('date'):
ids = group_obj.get_public_message_ids(request.cr, request.uid, domain=domain + [("date", ">", post.get('date'))], order="create_date asc", limit=10)
if ids:
values['prev_date'] = message_obj.browse(request.cr, request.uid, ids.pop()).date
domain += [("date", "<=", post.get('date'))]
message_ids = group_obj.get_public_message_ids(request.cr, request.uid, domain=domain, order="create_date desc", limit=11)
if message_ids:
values['blog_ids'] = message_obj.browse(request.cr, request.uid, message_ids)
if len(message_ids) > 10:
values['next_date'] = values['blog_ids'].pop().date
if blog_id:
values['blog_id'] = message_obj.browse(request.cr, request.uid, blog_id)
else:
step = 20
message_count = len(group_obj.get_public_message_ids(request.cr, request.uid, domain=domain, order="create_date desc"))
pager = website.pager(url="/blog/%s/" % mail_group_id, total=message_count, page=page, step=step, scope=7)
message_ids = group_obj.get_public_message_ids(request.cr, request.uid, domain=domain, order="create_date desc", limit=step, offset=pager['offset'])
values['pager'] = pager
values['blog_ids'] = message_obj.browse(request.cr, request.uid, message_ids)
return website.render("website_mail.index", values)
@@ -67,17 +61,6 @@ class website_mail(http.Controller):
comment_ids = request.registry['mail.group'].get_public_message_ids(request.cr, request.uid, domain=safe_eval(post.get('domain')), order="create_date asc", limit=None)
return simplejson.dumps(request.registry['mail.message'].read(request.cr, request.uid, comment_ids, ['website_published', 'subject', 'res_id']))
@http.route(['/blog/publish'], type='http', auth="public")
def publish(self, **post):
message_id = int(post['id'])
message_obj = request.registry['mail.message']
blog = message_obj.browse(request.cr, request.uid, message_id)
message_obj.write(request.cr, request.uid, [message_id], {'website_published': not blog.website_published})
blog = message_obj.browse(request.cr, request.uid, message_id)
return blog.website_published and "1" or "0"
@http.route(['/blog/<int:mail_group_id>/<int:blog_id>/post'], type='http', auth="public")
def blog_post(self, mail_group_id=None, blog_id=None, **post):
website = request.registry['website']
+3 -3
View File
@@ -32,12 +32,12 @@ class mail_message(osv.osv):
class mail_group(osv.Model):
_inherit = 'mail.group'
def get_public_blog(self, cr, uid, context=None):
def get_domain_public_blog(self, cr, uid, context=None):
mail_group_ids = self.search(cr, uid, [('public', '=', 'public')], context=context)
return [ ("type", "in", ['comment']),
("parent_id", "=", False),
("model", "=", 'mail.group'), ("res_id", "in", mail_group_ids)]
def get_public_message_ids(self, cr, uid, domain=[], order="create_date desc", limit=10, offset=0, context=None):
domain += self.get_public_blog(cr, uid, context=context)
def get_public_message_ids(self, cr, uid, domain=None, order="create_date desc", limit=None, offset=0, context=None):
domain += self.get_domain_public_blog(cr, uid, context=context)
return self.pool.get('mail.message').search(cr, uid, domain, order=order, limit=limit, offset=offset, context=context)
@@ -0,0 +1,266 @@
<section class="oe_container">
<div class="oe_row oe_spaced">
<div class="oe_span12">
<h2 class="oe_slogan">Awesome Open Source Blogging Systems</h2>
<h3 class="oe_slogan">Express yourself with beautiful blogs</h3>
</div>
<div class="oe_span6">
<div class="oe_demo oe_picture oe_screenshot">
<a href="https://www.openerp.com/saas_master/demo?lang=en_US&module=website_mail">
<img src="">
</a>
<div class="oe_demo_footer oe_centeralign">Online Demo</div>
</div>
</div>
<div class="oe_span6">
<p class='oe_mt32'>
</p>
<div class="oe_centeralign oe_websiteonly">
<a href="http://www.openerp.com/start?app=website_sale" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> online store</a>
</div>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row">
<h2 class="oe_slogan">Write Beautiful Blog Posts</h2>
<h3 class="oe_slogan">Get rid of old WYSIWYG editors</h3>
<div class="oe_span6">
<p class='oe_mt32'>
Drag &amp; Drop well designed <em>'Building Blocks'</em> to
create beautifull blog posts that perfectly integrates images,
videos, call-to-actions, quotes, banners, etc.
</p><p>
With our unique <em>'edit inline'</em> approach, you don't need
to be a designer to create awsome, good-looking, content. Each blog
post will look like it's designed by a professional designer.
</p>
</div>
<div class="oe_span6">
<div class="oe_bg_img oe_centered">
<img class="oe_picture" src="">
</div>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row">
<h2 class="oe_slogan">Automated Translation by Professionals</h2>
<h3 class="oe_slogan">Reach multi-languages audiences without Pain</h3>
<div class="oe_span6">
<div class="oe_bg_img">
<img class="oe_picture" src="">
</div>
</div>
<div class="oe_span6">
<p class='oe_mt32'>
Get your blog posts translated in multiple languages with no effort.
Our translation "on demand" feature allows you to benefit from
professional translators to translate all your changes
automatically. ($0.05 per word) Translated versions are updated
automatically once translated by professionals (around 32 hours).
</p>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row">
<h2 class="oe_slogan">Engage With Your Visitors</h2>
<h3 class="oe_slogan">Live chat with your visitors in one click</h3>
<div class="oe_span6">
<p class='oe_mt32'>
The integrated live chat features allows you to start chatting in
real time with your visitors to get feedback on your recent posts
or get ideas to write new posts.
</p><p>
Engaging with your visitors is also a great way to convert visitors
into customers.
</p>
</div>
<div class="oe_span6">
<div class="oe_bg_img">
<img class="oe_picture oe_screenshot" src="">
</div>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row">
<h2 class="oe_slogan">Build Visitors Loyalty</h2>
<h3 class="oe_slogan">Social Media Integration and Easy Following</h3>
<div class="oe_span6">
<img class="oe_picture oe_screenshot" src="">
</div>
<div class="oe_span6">
<p class='oe_mt32'>
The one click <em>follow</em> button will allow visitors
to receive your blog posts by email with no effort, without
having to register. Social media icons allows visitors to share
your best blog posts easily.
</p>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row">
<h2 class="oe_slogan">Google Analytics Integration</h2>
<h3 class="oe_slogan">Get visibility on the impact of each blog post</h3>
<div class="oe_span6">
<p class='oe_mt32'>
Get a clear visibility of your sales funnel. OpenERP's Google
Analytics trackers are configured by default to track all kind of
events related to shopping carts, call-to-actions, etc.
</p><p>
As OpenERP marketing tools (mass mailing, campaigns, etc) are also
linked with Google Analytics, you get a 360° view of your business.
</p>
</div>
<div class="oe_span6">
<img class="oe_picture oe_screenshot" src="">
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row">
<h2 class="oe_slogan">Designer-Friendly Themes</h2>
<h3 class="oe_slogan">Designers love working on OpenERP</h3>
<div class="oe_span6">
<p class='oe_mt32'>
Themes are awesome and easy to design. You don't need to develop
to create new pages, themes or building blocks. We use a clean
HTML structure, a <a href="http://getbootstrap.com/">bootstrap</a>
CSS and our modularity allows to distribute your themes easily.
</p><p>
The building block approach allows the website to remain clean
after the end-users start creating new contents.
</p>
</div>
<div class="oe_span6">
<div class="oe_row_img oe_centered">
<img class="oe_picture" src="">
</div>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row">
<h2 class="oe_slogan">SEO Optimized Blog Posts</h2>
<h3 class="oe_slogan">Attract new visitors with a good referencing</h3>
<div class="oe_span6">
<div class="oe_bg_img">
<img class="oe_picture oe_screenshot" src="">
</div>
</div>
<div class="oe_span6">
<p class='oe_mt32'>
SEO tools are ready to use, with no configuration required.
OpenERP suggests keywords for your titles according to Google
most searched terms, Google Analytics tracks interrests of your
visitors, sitemap are created automatically for Google
indexation, etc.
</p><p>
We even do structured content automatically to promote your
product and events efficiently in Google.
</p>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row">
<h2 class="oe_slogan">Easy Access Rights</h2>
<h3 class="oe_slogan">Adapt your publishing process to your own need</h3>
<div class="oe_span6">
<div class="oe_bg_img">
<img class="oe_picture oe_screenshot" src="">
</div>
</div>
<div class="oe_span6">
<p class='oe_mt32'>
Not everyone requires the same access to your website.
Designers manage the layout of the site, editors approves content and
authors write that content. This lets you organize your publishing
process according to your needs.
</p><p>
Others access rights related to business objects (products, people,
events, etc) directly follows OpenERP's standard access right allowing
you to not have to configure them twice.
</p>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row">
<h2 class="oe_slogan">Built-in Comments</h2>
<h3 class="oe_slogan">Engage with your readers</h3>
<div class="oe_span6">
<p class='oe_mt32'>
Your blog is your home, and comments provide a space for your
friends and followers to engage with your content. OpenERP's
comment tools give you everything you need to be a forum for
discussion and to moderate that discussion.
</p>
</div>
<div class="oe_span6">
<div class="oe_bg_img oe_centered">
<img class="oe_picture" src="">
</div>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row">
<h2 class="oe_slogan">Integrated With Others OpenERP Apps</h2>
<h3 class="oe_slogan">Get hundreds of open source apps for free</h3>
<div class="oe_span4">
<a href="/apps/website">
<h3>CMS</h3>
<div class="oe_row_img oe_centered">
<img class="oe_picture oe_screenshot" src="">
</div>
</a>
<p>
Easily create awesome websites with no technical knowledge required.
</p>
</div>
<div class="oe_span4">
<a href="/apps/website_sale">
<h3>eCommerce</h3>
<div class="oe_row_img oe_centered">
<img class="oe_picture oe_screenshot" src="">
</div>
</a>
<p>
Promote products, sell online, optimize visitors' shopping experiences.
</p>
</div>
<div class="oe_span4">
<a href="/apps/website_event">
<h3>Online Events</h3>
<div class="oe_row_img oe_centered">
<img class="oe_picture oe_screenshot" src="">
</div>
</a>
<p>
Schedule, organize, promote or sell events online; conferences,
webinars, trainings, etc.
</p>
</div>
<div class="oe_span12 oe_centered oe_muted">
<a href="/apps">
and hundreds more applications...
</a>
</div>
</div>
</section>
-17
View File
@@ -1,21 +1,4 @@
$(document).ready(function () {
$('.js_website_mail').on('click', '.js_publish, .js_unpublish', function (e) {
e.preventDefault();
var $link = $(this).parent();
$link.find('.js_publish, .js_unpublish').addClass("hidden");
var $unp = $link.find(".js_unpublish");
var $p = $link.find(".js_publish");
$.post('/blog/publish', {'id': $link.data('id')}, function (result) {
if (+result) {
$p.addClass("hidden");
$unp.removeClass("hidden");
} else {
$p.removeClass("hidden");
$unp.addClass("hidden");
}
});
});
$form = $('.js_nav_year a:first').on('click', function (e) {
e.preventDefault();
$(this).next("ul").toggle();
+44 -61
View File
@@ -12,57 +12,33 @@
<!-- Layout add nav and footer -->
<record id="header_website_mail" model="ir.ui.view">
<field name="name">header_website_mail</field>
<field name="inherit_id" ref="website.header"/>
<field name="arch" type="xml">
<data>
<xpath expr="//li[last()]" position="after">
<li class="pull-right"><a href="/blog/%(website_mail.website_mail_blog)d/">News</a></li>
</xpath>
</data>
</field>
</record>
<record id="footer_website_mail" model="ir.ui.view">
<field name="name">footer_website_mail</field>
<field name="inherit_id" ref="website.footer"/>
<field name="arch" type="xml">
<data>
<xpath expr="//a[@href='/page/website.news']" position="replace">
<a href="/blog/%(website_mail.website_mail_blog)d/">News</a>
</xpath>
</data>
</field>
</record>
<template id="footer_custom" inherit_id="website.layout" name="Custom Footer">
<xpath expr="//body/header//ul[@id='top_menu']/li[last()]" position="before">
<li><a href="/blog/%(website_mail.website_mail_blog)d/">News</a></li>
</xpath>
<xpath expr="//body/footer//h5[@name='info_title']" position="after">
<ul class='unstyled'>
<li><a href="/blog/%(website_mail.website_mail_blog)d/">News</a></li>
</ul>
</xpath>
</template>
<!-- Page -->
<template id="index">
<template id="index" name="Blogs">
<t t-call="website.layout">
<t t-set="head">
<script type="text/javascript" src="/website_mail/static/src/js/blog.js"></script>
<link rel='stylesheet' href='/website_mail/static/src/css/blog.css'/>
<t t-raw="head"/>
<t t-raw="head or ''"/>
</t>
<t t-set="title">Blog</t>
<div class="container mt48 js_website_mail">
<div class="row">
<div class="span4">
<ul class="nav nav-list">
<a t-if="mail_group_id and editable" t-att-href="'/blog/%%s/new' %% mail_group_id" class="btn">Add a new Blog</a>
<li class="nav-header"><a t-att-href="'/blog/%%s/' %% mail_group_id">BLOG ARCHIVE</a></li>
<!-- TODO: check qweb iteration -->
<li t-foreach="nav_list" t-as="year" class="js_nav_year">
<t t-set="year" t-value="nav_list[year]"/>
<a href="#"><t t-esc="year['name']"/> <small>(<t t-esc="year['date_count']"/>)</small></a>
<ul class="nav nav-list css_nav_month">
<t t-foreach="year['months']">
<li class="js_nav_month"><a href="#" t-att-data-domain="__domain"><t t-esc="date"/> <small>(<t t-esc="date_count"/>)</small></a>
<ul class="nav nav-list"/>
</li>
</t>
</ul>
</li>
<div class="span4" id="left_column">
<a t-if="mail_group_id and editable" t-att-href="'/blog/%%s/new' %% mail_group_id" class="btn">Add a new Blog</a>
<div id="blog_subscribe">
<form action="./subscribe" method="POST" class="form-inline" t-if="not subscribe">
<input placeholder="Email Address" type="email" name="email" class="input-medium" t-if="is_public_user"/>
<button type="submit" class="btn btn-primary" name="subscribe">Subscribe</button>
@@ -71,15 +47,12 @@
<input type="hidden" name="email" t-att-value="subscribe"/>
<button type="submit" class="btn" name="unsubscribe">Unsubscribe</button>
</form>
</ul>
</div>
</div>
<div class="span8" t-if="blog_id">
<div class="media">
<div class="media-body well">
<a href="#" t-att-data-id="blog_id.id" class="pull-right" t-if="editable">
<span t-att-class="'label label-success js_unpublish %%s' %% (not blog_id.website_published and 'hidden' or '')">Click to Unpublish</span>
<span t-att-class="'label label-important js_publish %%s' %% (blog_id.website_published and 'hidden' or '')">Click to Publish</span>
</a>
<t t-call="website.publish"><t t-set="object" t-value="blog_id"/></t>
<h3 t-field="blog_id.subject"/>
<div t-field="blog_id.body"/>
<small class="pull-right muted text-right">
@@ -90,10 +63,7 @@
<ul class="media-list" id="comment">
<li t-foreach="blog_id.child_ids" t-as="comment" class="media">
<div class="media-body">
<a href="#" t-att-data-id="blog_id.id" class="pull-right" t-if="editable">
<span t-att-class="'label label-success js_unpublish %%s' %% (not comment.website_published and 'hidden' or '')">Click to Unpublish</span>
<span t-att-class="'label label-important js_publish %%s' %% (comment.website_published and 'hidden' or '')">Click to Publish</span>
</a>
<t t-call="website.publish"><t t-set="object" t-value="comment"/></t>
<t t-raw="comment.body"/>
<small class="pull-right muted text-right">
<div t-field="comment.author_id"/>
@@ -108,14 +78,12 @@
</ul>
</div>
</div>
<div class="span8" t-if="not blog_id and blog_ids">
<ul class="media-list">
<li t-foreach="blog_ids" t-as="blog" class="media well">
<div t-att-class="'media-body %%s' %% (blog.website_published and 'css_published' or '')">
<a href="#" t-att-data-id="blog.id" class="pull-right" t-if="editable">
<span t-att-class="'label label-success js_unpublish %%s' %% (not blog.website_published and 'hidden' or '')">Click to Unpublish</span>
<span t-att-class="'label label-important js_publish %%s' %% (blog.website_published and 'hidden' or '')">Click to Publish</span>
</a>
<t t-call="website.publish"><t t-set="object" t-value="blog"/></t>
<h4 class="media-heading" ><a t-att-href="'/blog/%%s/%%s#comment' %% (blog.res_id, blog.id)" t-field="blog.subject"></a></h4>
<div class="media">
<div t-field="blog.body"/>
@@ -131,18 +99,33 @@
</div>
</li>
</ul>
<ul class="pager">
<li t-if="next_date" class="previous">
<a t-att-href="'?date=%%s' %% (next_date)">&amp;larr; Older</a>
</li>
<li t-if="prev_date" class="next">
<a t-att-href="'?date=%%s' %% (prev_date)">Newer &amp;rarr;</a>
</li>
</ul>
<div class="text-center">
<t t-call="website.pager" />
</div>
</div>
</div>
</div>
</t>
</template>
<template id="blog_history" inherit_id="website_mail.index" inherit_option_id="website_mail.index" name="History">
<xpath expr="//div[@id='left_column']" position="inside">
<ul class="nav nav-list">
<li class="nav-header"><a t-att-href="'/blog/%%s/' %% mail_group_id">BLOG ARCHIVE</a></li>
<!-- TODO: check qweb iteration -->
<li t-foreach="nav_list" t-as="year" class="js_nav_year">
<t t-set="year" t-value="nav_list[year]"/>
<a href="#"><t t-esc="year['name']"/> <small>(<t t-esc="year['date_count']"/>)</small></a>
<ul class="nav nav-list css_nav_month">
<t t-foreach="year['months']">
<li class="js_nav_month"><a href="#" t-att-data-domain="__domain"><t t-esc="date"/> <small>(<t t-esc="date_count"/>)</small></a>
<ul class="nav nav-list"/>
</li>
</t>
</ul>
</li>
</ul>
</xpath>
</template>
</data>
</openerp>
+1 -2
View File
@@ -1,3 +1,2 @@
import controllers
import pricelist
import product
import website_sale
+4 -5
View File
@@ -1,6 +1,7 @@
{
'name': 'E-Commerce',
'category': 'Sale',
'category': 'Website',
'summary': 'Sell Your Products Online',
'version': '1.0',
'description': """
OpenERP E-Commerce
@@ -10,12 +11,10 @@ OpenERP E-Commerce
'author': 'OpenERP SA',
'depends': ['website', 'sale', 'point_of_sale'],
'data': [
'views/ecommerce.xml',
'views/pricelist.xml',
'views/website_sale.xml',
'security/ir.model.access.csv',
'security/ecommerce.xml',
'security/website_sale.xml',
],
'qweb': ['static/src/xml/*.xml'],
'installable': True,
'auto_install': True,
}
+127 -191
View File
@@ -1,44 +1,40 @@
# -*- coding: utf-8 -*-
import math
import openerp
import simplejson
from openerp import SUPERUSER_ID
from openerp.osv import osv
from openerp.addons.web import http
from openerp.addons.web.http import request
import werkzeug
def get_order(order_id=None):
order_obj = request.registry.get('sale.order')
# check if order allready exists
if order_id:
try:
order_obj.browse(request.cr, openerp.SUPERUSER_ID, order_id).pricelist_id
order = order_obj.browse(request.cr, SUPERUSER_ID, order_id)
order.pricelist_id
except:
order_id = None
if not order_id:
fields = [k for k, v in order_obj._columns.items()]
order_value = order_obj.default_get(request.cr, openerp.SUPERUSER_ID, fields)
order_value['partner_id'] = request.registry.get('res.users').browse(request.cr, openerp.SUPERUSER_ID, request.uid).partner_id.id
order_value.update(order_obj.onchange_partner_id(request.cr, openerp.SUPERUSER_ID, [], request.uid, context={})['value'])
order_id = order_obj.create(request.cr, openerp.SUPERUSER_ID, order_value)
return order_obj.browse(request.cr, openerp.SUPERUSER_ID, order_id)
order_value = order_obj.default_get(request.cr, SUPERUSER_ID, fields)
order_value['partner_id'] = request.registry.get('res.users').browse(request.cr, SUPERUSER_ID, request.uid).partner_id.id
order_value.update(order_obj.onchange_partner_id(request.cr, SUPERUSER_ID, [], request.uid, context={})['value'])
order_id = order_obj.create(request.cr, SUPERUSER_ID, order_value)
order = order_obj.browse(request.cr, SUPERUSER_ID, order_id)
return order
def get_current_order():
order = get_order(request.httprequest.session.get('ecommerce_order_id'))
if order.state != 'draft':
order = get_order()
request.httprequest.session['ecommerce_order_id'] = order.id
return order
def get_categories():
category_obj = request.registry.get('pos.category')
category_ids = category_obj.search(request.cr, openerp.SUPERUSER_ID, [('parent_id', '=', False)])
return category_obj.browse(request.cr, openerp.SUPERUSER_ID, category_ids)
class website(osv.osv):
_inherit = "website"
def get_rendering_context(self, additional_values=None):
values = {
'website_sale_get_categories': get_categories,
'order': get_current_order(),
# 'website_sale_get_current_order': get_current_order, # TODO: replace 'order' key in templates
}
@@ -50,115 +46,46 @@ class Ecommerce(http.Controller):
def get_categories(self):
category_obj = request.registry.get('pos.category')
category_ids = category_obj.search(request.cr, openerp.SUPERUSER_ID, [('parent_id', '=', False)])
categories = category_obj.browse(request.cr, openerp.SUPERUSER_ID, category_ids)
print categories
category_ids = category_obj.search(request.cr, SUPERUSER_ID, [('parent_id', '=', False)])
categories = category_obj.browse(request.cr, SUPERUSER_ID, category_ids)
return categories
def get_current_order(self):
order = self.get_order(request.httprequest.session.get('ecommerce_order_id'))
request.httprequest.session['ecommerce_order_id'] = order.id
return order
def get_order(self, order_id=None):
order_obj = request.registry.get('sale.order')
# check if order allready exists
if order_id:
try:
order_obj.browse(request.cr, openerp.SUPERUSER_ID, order_id).pricelist_id
except:
order_id = None
if not order_id:
fields = [k for k, v in order_obj._columns.items()]
order_value = order_obj.default_get(request.cr, openerp.SUPERUSER_ID, fields)
order_value['partner_id'] = request.registry.get('res.users').browse(request.cr, openerp.SUPERUSER_ID, request.uid).partner_id.id
order_value.update(order_obj.onchange_partner_id(request.cr, openerp.SUPERUSER_ID, [], request.uid, context={})['value'])
order_id = order_obj.create(request.cr, openerp.SUPERUSER_ID, order_value)
return order_obj.browse(request.cr, openerp.SUPERUSER_ID, order_id)
def render(self, template, values={}):
_values = {
'order': self.get_current_order(),
'categories': self.get_categories(),
}
_values.update(values)
return website.render(template, _values)
def recommended_product(self, my_pids):
if not my_pids:
return []
product_obj = request.registry.get('product.product')
my_pids = str(my_pids)[1:-1]
product_ids = []
query = """
SELECT sol.product_id
FROM sale_order_line as my
LEFT JOIN sale_order_line as sol
ON sol.order_id = my.order_id
WHERE my.product_id in (%s)
AND sol.product_id not in (%s)
GROUP BY sol.product_id
ORDER BY COUNT(sol.order_id) DESC
LIMIT 8
""" % (my_pids, my_pids)
request.cr.execute(query)
for p in request.cr.fetchall():
product_ids.append(p[0])
# search to apply access rules
product_ids = product_obj.search(request.cr, request.uid, [("id", "in", product_ids)])
return product_obj.browse(request.cr, request.uid, product_ids)
@http.route(['/shop', '/shop/category/<cat_id>', '/shop/category/<cat_id>/page/<page>', '/shop/page/<page>'], type='http', auth="public")
@http.route(['/shop/', '/shop/category/<cat_id>/', '/shop/category/<cat_id>/page/<int:page>/', '/shop/page/<int:page>/'], type='http', auth="public")
def category(self, cat_id=0, page=0, **post):
website = request.registry['website']
product_obj = request.registry.get('product.product')
domain = [("sale_ok", "=", True)]
if openerp.SUPERUSER_ID != request.uid:
if SUPERUSER_ID != request.uid:
domain += [('website_published', '=', True)]
if post.get("search"):
domain += ['|', '|', '|',
('name', 'ilike', "%%%s%%" % post.get("search")),
('description', 'ilike', "%%%s%%" % post.get("search")),
('description_website', 'ilike', "%%%s%%" % post.get("search")),
('pos_categ_id.name', 'ilike', "%%%s%%" % post.get("search"))]
if cat_id:
cat_id = int(cat_id)
domain = [('pos_categ_id.id', 'child_of', cat_id)] + domain
domain += [('pos_categ_id.id', 'child_of', cat_id)] + domain
step = 20
product_count = len(product_obj.search(request.cr, request.uid, domain))
page_count = int(math.ceil(product_count / 20.0))
pager = website.pager(url="/shop/category/%s/" % cat_id, total=product_count, page=page, step=step, scope=7, url_args=post)
#if post.get("search"):
# domain += ['|', '|', ('name', 'ilike', "%%%s%%" % post.get("search")), ('description', 'ilike', "%%%s%%" % post.get("search")), ('pos_categ_id.name', 'ilike', "%%%s%%" % post.get("search"))]
page = max(1,min(int(page),page_count))
offset = (page-1) * 20
if page_count <= 5 or page <= 3:
pmin = 1
pmax = min(page_count,5)
elif page >= page_count - 2:
pmin = page_count - 4
pmax = page_count
else:
pmin = page - 2
pmax = page + 2
pages = range(pmin, pmax+1)
product_ids = product_obj.search(request.cr, request.uid, domain, limit=20, offset=offset)
product_ids = product_obj.search(request.cr, request.uid, domain, limit=step, offset=pager['offset'])
values = website.get_rendering_context({
'categories': self.get_categories(),
'current_category': cat_id,
'products': product_obj.browse(request.cr, request.uid, product_ids),
'search': post.get("search"),
'page_count': page_count,
'pages': pages,
'page': page,
'pager': pager,
})
return website.render("website_sale.products", values)
@http.route(['/shop/product/<product_id>'], type='http', auth="public")
@http.route(['/shop/product/<product_id>/'], type='http', auth="public")
def product(self, cat_id=0, product_id=0):
website = request.registry['website']
order = get_current_order()
@@ -167,37 +94,30 @@ class Ecommerce(http.Controller):
product_obj = request.registry.get('product.product')
line = [line for line in order.order_line if line.product_id.id == product_id]
quantity = line and int(line[0].product_uom_qty) or 0
values = website.get_rendering_context({
'categories': self.get_categories(),
'product': product_obj.browse(request.cr, request.uid, product_id),
'quantity': quantity,
'recommended_products': self.recommended_product([product_id]),
})
return website.render("website_sale.product", values)
@http.route(['/shop/mycart'], type='http', auth="public")
@http.route(['/shop/mycart/'], type='http', auth="public")
def mycart(self, **post):
website = request.registry['website']
order = get_current_order()
website = request.registry['website']
if post.get('code'):
pricelist_obj = request.registry.get('product.pricelist')
pricelist_ids = pricelist_obj.search(request.cr, openerp.SUPERUSER_ID, [('code', '=', post.get('code'))])
pricelist_ids = pricelist_obj.search(request.cr, SUPERUSER_ID, [('code', '=', post.get('code'))])
if pricelist_ids:
order.write({'pricelist_id': pricelist_ids[0]})
my_pids = [line.product_id.id for line in order.order_line]
values = website.get_rendering_context({
"recommended_products": self.recommended_product(my_pids)
'categories': self.get_categories(),
})
return website.render("website_sale.mycart", values)
@http.route(['/shop/add_cart'], type='http', auth="public")
def add_cart(self, product_id=0, remove=False):
website = request.registry['website']
values = website.get_rendering_context()
def add_product_to_cart(self, product_id=0, number=1, set_number=-1):
context = {}
order_line_obj = request.registry.get('sale.order.line')
@@ -209,15 +129,19 @@ class Ecommerce(http.Controller):
quantity = 0
# values initialisation
order_line_ids = order_line_obj.search(request.cr, openerp.SUPERUSER_ID, [('order_id', '=', order.id), ('product_id', '=', product_id)], context=context)
values = {}
order_line_ids = order_line_obj.search(request.cr, SUPERUSER_ID, [('order_id', '=', order.id), ('product_id', '=', product_id)], context=context)
if order_line_ids:
order_line = order_line_obj.read(request.cr, openerp.SUPERUSER_ID, order_line_ids, [], context=context)[0]
quantity = order_line['product_uom_qty'] + (remove and -1 or 1)
order_line = order_line_obj.read(request.cr, SUPERUSER_ID, order_line_ids, [], context=context)[0]
if set_number >= 0:
quantity = set_number
else:
quantity = order_line['product_uom_qty'] + number
if quantity <= 0:
order_line_obj.unlink(request.cr, openerp.SUPERUSER_ID, order_line_ids, context=context)
order_line_obj.unlink(request.cr, SUPERUSER_ID, order_line_ids, context=context)
else:
fields = [k for k, v in order_line_obj._columns.items()]
values = order_line_obj.default_get(request.cr, openerp.SUPERUSER_ID, fields, context=context)
values = order_line_obj.default_get(request.cr, SUPERUSER_ID, fields, context=context)
quantity = 1
values['product_uom_qty'] = quantity
values['product_id'] = product_id
@@ -226,92 +150,111 @@ class Ecommerce(http.Controller):
# change and record value
if quantity:
pricelist_id = order.pricelist_id and order.pricelist_id.id or False
values.update(order_line_obj.product_id_change(request.cr, openerp.SUPERUSER_ID, [], pricelist_id, product_id,
partner_id=user_obj.browse(request.cr, openerp.SUPERUSER_ID, request.uid).partner_id.id,
values.update(order_line_obj.product_id_change(request.cr, SUPERUSER_ID, [], pricelist_id, product_id,
partner_id=user_obj.browse(request.cr, SUPERUSER_ID, request.uid).partner_id.id,
context=context)['value'])
if order_line_ids:
order_line_obj.write(request.cr, openerp.SUPERUSER_ID, order_line_ids, values, context=context)
order_line_obj.write(request.cr, SUPERUSER_ID, order_line_ids, values, context=context)
else:
order_line_id = order_line_obj.create(request.cr, openerp.SUPERUSER_ID, values, context=context)
order_line_id = order_line_obj.create(request.cr, SUPERUSER_ID, values, context=context)
order.write({'order_line': [(4, order_line_id)]}, context=context)
html = website.render("website_sale.total", values)
return simplejson.dumps({"quantity": quantity, "totalHTML": html})
return quantity
@http.route(['/shop/remove_cart'], type='http', auth="public")
def remove_cart(self, product_id=0):
return self.add_cart(product_id=product_id, remove=True)
@http.route(['/shop/add_cart/<product_id>/', '/shop/<path:path>/add_cart/<product_id>/'], type='http', auth="public")
def add_cart(self, path=None, product_id=0, remove=None):
self.add_product_to_cart(product_id, number=(remove and -1 or 1))
if path:
return werkzeug.utils.redirect("/shop/%s/" % path)
else:
return werkzeug.utils.redirect("/shop/")
@http.route(['/shop/checkout'], type='http', auth="public")
@http.route(['/shop/remove_cart/<product_id>/', '/shop/<path:path>/remove_cart/<product_id>/'], type='http', auth="public")
def remove_cart(self, path=None, product_id=0):
return self.add_cart(product_id=product_id, path=path, remove=True)
@http.route(['/shop/set_cart/<product_id>/<set_number>/', '/shop/<path:path>/set_cart/<product_id>/<set_number>/'], type='http', auth="public")
def set_cart(self, path=None, product_id=0, set_number=0):
self.add_product_to_cart(product_id, set_number=set_number)
if path:
return werkzeug.utils.redirect("/shop/%s/" % path)
else:
return werkzeug.utils.redirect("/shop/")
@http.route(['/shop/checkout/'], type='http', auth="public")
def checkout(self, **post):
website = request.registry['website']
values = website.get_rendering_context({
'partner': False
})
order = get_current_order()
if order.state != 'draft':
return self.confirmed(**post)
if not order.order_line:
if order.state != 'draft' or not order.order_line:
return self.mycart(**post)
partner_obj = request.registry.get('res.partner')
user_obj = request.registry.get('res.users')
country_obj = request.registry.get('res.country')
country_state_obj = request.registry.get('res.country.state')
payment_obj = request.registry.get('portal.payment.acquirer')
values = website.get_rendering_context({
'shipping': post.get("shipping"),
'error': post.get("error") and dict.fromkeys(post.get("error").split(","), 'error') or {}
})
checkout = {}
if request.uid != website.get_public_user().id:
values['partner'] = user_obj.browse(request.cr, request.uid, request.uid).partner_id
shipping_ids = partner_obj.search(request.cr, request.uid, [("parent_id", "=", values['partner'].id), ('type', "=", 'delivery')])
values['shipping'] = None
partner = user_obj.browse(request.cr, request.uid, request.uid).partner_id
partner_id = partner.id
checkout = user_obj.read(request.cr, SUPERUSER_ID, [partner_id], [])[0]
checkout['company'] = partner.parent_id and partner.parent_id.name or ''
shipping_ids = partner_obj.search(request.cr, request.uid, [("parent_id", "=", partner_id), ('type', "=", 'delivery')])
if shipping_ids:
values['shipping'] = partner_obj.browse(request.cr, request.uid, shipping_ids[0])
for k,v in partner_obj.read(request.cr, request.uid, shipping_ids[0]).items():
checkout['shipping_'+k] = v or ''
values['countries'] = country_obj.browse(request.cr, openerp.SUPERUSER_ID, country_obj.search(request.cr, openerp.SUPERUSER_ID, [(1, "=", 1)]))
values['states'] = country_state_obj.browse(request.cr, openerp.SUPERUSER_ID, country_state_obj.search(request.cr, openerp.SUPERUSER_ID, [(1, "=", 1)]))
checkout.update(request.session.setdefault('checkout', {}))
for k,v in checkout.items():
checkout[k] = v or ''
values['checkout'] = checkout
payment_ids = payment_obj.search(request.cr, openerp.SUPERUSER_ID, [('visible', '=', True)])
values['payments'] = payment_obj.browse(request.cr, openerp.SUPERUSER_ID, payment_ids)
for payment in values['payments']:
content = payment_obj.render(request.cr, openerp.SUPERUSER_ID, payment.id, order, order.name, order.pricelist_id.currency_id, order.amount_total)
payment._content = content
values['countries'] = country_obj.browse(request.cr, SUPERUSER_ID, country_obj.search(request.cr, SUPERUSER_ID, [(1, "=", 1)]))
values['states'] = country_state_obj.browse(request.cr, SUPERUSER_ID, country_state_obj.search(request.cr, SUPERUSER_ID, [(1, "=", 1)]))
return website.render("website_sale.checkout", values)
@http.route(['/shop/confirm_order'], type='http', auth="public")
@http.route(['/shop/confirm_order/'], type='http', auth="public")
def confirm_order(self, **post):
website = request.registry['website']
order = get_current_order()
json = {'error': [], 'validation': False}
error = []
partner_obj = request.registry.get('res.partner')
user_obj = request.registry.get('res.users')
if order.state != 'draft':
json['validation'] = True
return json
return werkzeug.utils.redirect("/shop/checkout/")
if not order.order_line:
json['error'].append("empty_cart")
return json
error.append("empty_cart")
return werkzeug.utils.redirect("/shop/checkout/")
# check values
request.session['checkout'] = post
required_field = ['phone', 'zip', 'email', 'street', 'city', 'name', 'country_id']
for key in required_field:
if not post.get(key):
json['error'].append(key)
if 'shipping_name' in post and key != 'email' and not post.get("shipping_%s" % key):
json['error'].append("shipping_%s" % key)
if json['error']:
return simplejson.dumps(json)
error.append(key)
if post.get('shipping_different') and key != 'email' and not post.get("shipping_%s" % key):
error.append("shipping_%s" % key)
if error:
return werkzeug.utils.redirect("/shop/checkout/?error=%s&shipping=%s" % (",".join(error), post.get('shipping_different') and 'on' or ''))
# search or create company
company_id = None
if post['company']:
company_ids = partner_obj.search(request.cr, openerp.SUPERUSER_ID, [("name", "ilike", post['company']), ('is_company', '=', True)])
company_ids = partner_obj.search(request.cr, SUPERUSER_ID, [("name", "ilike", post['company']), ('is_company', '=', True)])
company_id = company_ids and company_ids[0] or None
if not company_id:
company_id = partner_obj.create(request.cr, openerp.SUPERUSER_ID, {'name': post['company'], 'is_company': True})
company_id = partner_obj.create(request.cr, SUPERUSER_ID, {'name': post['company'], 'is_company': True})
partner_value = {
'fax': post['fax'],
@@ -329,7 +272,7 @@ class Ecommerce(http.Controller):
partner_id = user_obj.browse(request.cr, request.uid, request.uid).partner_id.id
partner_obj.write(request.cr, request.uid, [partner_id], partner_value)
else:
partner_id = partner_obj.create(request.cr, openerp.SUPERUSER_ID, partner_value)
partner_id = partner_obj.create(request.cr, SUPERUSER_ID, partner_value)
shipping_id = None
if 'shipping_name' in post:
@@ -347,12 +290,12 @@ class Ecommerce(http.Controller):
}
domain = [(key, '_id' in key and '=' or 'ilike', '_id' in key and int(value) or value)
for key, value in shipping_value.items() if key in required_field + ["type", "parent_id"]]
shipping_ids = partner_obj.search(request.cr, openerp.SUPERUSER_ID, domain)
shipping_ids = partner_obj.search(request.cr, SUPERUSER_ID, domain)
if shipping_ids:
shipping_id = shipping_ids[0]
partner_obj.write(request.cr, openerp.SUPERUSER_ID, [shipping_id], shipping_value)
partner_obj.write(request.cr, SUPERUSER_ID, [shipping_id], shipping_value)
else:
shipping_id = partner_obj.create(request.cr, openerp.SUPERUSER_ID, shipping_value)
shipping_id = partner_obj.create(request.cr, SUPERUSER_ID, shipping_value)
order_value = {
'state': 'progress',
@@ -360,41 +303,34 @@ class Ecommerce(http.Controller):
'partner_invoice_id': partner_id,
'partner_shipping_id': shipping_id or partner_id
}
order_value.update(request.registry.get('sale.order').onchange_partner_id(request.cr, openerp.SUPERUSER_ID, [], request.uid, context={})['value'])
order_value.update(request.registry.get('sale.order').onchange_partner_id(request.cr, SUPERUSER_ID, [], request.uid, context={})['value'])
order.write(order_value)
json['validation'] = True
return simplejson.dumps(json)
request.httprequest.session['ecommerce_order_id_old'] = order.id
request.httprequest.session['ecommerce_order_id'] = None
@http.route(['/shop/confirmed'], type='http', auth="public")
def confirmed(self, **post):
return werkzeug.utils.redirect("/shop/payment/")
@http.route(['/shop/payment/'], type='http', auth="public")
def payment(self, **post):
website = request.registry['website']
order = get_order(request.httprequest.session.get('ecommerce_order_id_old'))
if request.httprequest.session.get('ecommerce_order_id'):
order = get_current_order()
if order.state != 'draft':
request.httprequest.session['ecommerce_order_id_old'] = order.id
request.httprequest.session['ecommerce_order_id'] = None
order_old = get_order(request.httprequest.session.get('ecommerce_order_id_old'))
if not order_old.order_line:
if order.state != 'progress':
return self.mycart(**post)
values = website.get_rendering_context({
'temp': 0,
'order': order_old,
'partner': False,
'order': order
})
return website.render("website_sale.confirmed", values)
@http.route(['/shop/publish'], type='http', auth="public")
def publish(self, **post):
product_id = int(post['id'])
product_obj = request.registry['product.product']
payment_obj = request.registry.get('portal.payment.acquirer')
payment_ids = payment_obj.search(request.cr, SUPERUSER_ID, [('visible', '=', True)])
values['payments'] = payment_obj.browse(request.cr, SUPERUSER_ID, payment_ids)
for payment in values['payments']:
content = payment_obj.render(request.cr, SUPERUSER_ID, payment.id, order, order.name, order.pricelist_id.currency_id, order.amount_total)
payment._content = content
product = product_obj.browse(request.cr, request.uid, product_id)
product_obj.write(request.cr, request.uid, [product_id], {'website_published': not product.website_published})
product = product_obj.browse(request.cr, request.uid, product_id)
return product.website_published and "1" or "0"
return website.render("website_sale.payment", values)
# vim:expandtab:tabstop=4:softtabstop=4:shiftwidth=4:
-29
View File
@@ -1,29 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# 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.osv import osv, fields
class product_pricelist(osv.osv):
_inherit = "product.pricelist"
_columns = {
'code': fields.char('Promotionnal Code', size=64, required=True, translate=True),
}
-11
View File
@@ -1,11 +0,0 @@
# -*- coding: utf-8 -*-
from openerp.osv import osv, fields
class product_pricelist(osv.osv):
_inherit = "product.product"
_columns = {
'website_published': fields.boolean('Available in the website'),
'description_website': fields.html('Description for the website'),
}
@@ -0,0 +1,319 @@
<section class="oe_container">
<div class="oe_row oe_spaced">
<div class="oe_span12">
<h2 class="oe_slogan">Open Source eCommerce</h2>
<h3 class="oe_slogan">Optimize sales with an awesome online store.</h3>
</div>
<div class="oe_span6">
<div class="oe_demo oe_picture oe_screenshot">
<a href="https://www.openerp.com/saas_master/demo?lang=en_US&module=website_sale">
<img src="">
</a>
<div class="oe_demo_footer oe_centeralign">Online Demo</div>
</div>
</div>
<div class="oe_span6">
<p class='oe_mt32'>
OpenERP eCommerce is unlike anything you have ever seen before.
It's at the same time full-featured, integrated with your
management software, fully customizable and super easy.
</p>
<div class="oe_centeralign oe_websiteonly">
<a href="http://www.openerp.com/start?app=website_sale" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> online store</a>
</div>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row">
<h2 class="oe_slogan">Create Awsome Product Pages</h2>
<h3 class="oe_slogan">Get rid of old WYSIWYG editors</h3>
<div class="oe_span6">
<p class='oe_mt32'>
OpenERP's unique <em>'edit inline'</em> approach makes website
and product pages creation surprisingly easy. "Want to change
the price of a product? or put it in bold? Want to add a banner
for a specific product?" just click and change. What you see is
what you get. Really.
</p><p>
Drag &amp; Drop well designed <em>'Building Blocks'</em> to
create beautifull product pages that your customer will love.
</p>
</div>
<div class="oe_span6">
<div class="oe_bg_img oe_centered">
<img class="oe_picture" src="">
</div>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row">
<h2 class="oe_slogan">Increase Your Revenue Per Order</h2>
<h3 class="oe_slogan">Do you want fries with that?</h3>
<div class="oe_span6">
<img class="oe_picture oe_screenshot" src="">
</div>
<div class="oe_span6">
<p class='oe_mt32'>
Use the built-in cross-selling feature helps you offer extra
products related to what the shopper put in his cart. (e.g.
accessories)
</p><p>
OpenERP's upselling algorythm allows you to show visitors
similar but more expensive products than the one in view, with
incentives like customer ratings. (social validation)
</p><p>
The inline editing feature allows you to easily change a price,
launch a promotion or fine tune the description of a product,
in a just a click.
</p>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row">
<h2 class="oe_slogan">A Clean Google Analytics Integration</h2>
<h3 class="oe_slogan">Control your sales funnel with Google Analytics</h3>
<div class="oe_span6">
<p class='oe_mt32'>
Get a clear visibility of your sales funnel. OpenERP's Google
Analytics trackers are configured by default to track all kind of
events related to shopping carts, call-to-actions, etc.
</p><p>
As OpenERP marketing tools (mass mailing, campaigns, etc) are also
linked with Google Analytics, you get a 360° view of your business.
</p>
</div>
<div class="oe_span6">
<img class="oe_picture oe_screenshot" src="">
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row">
<h2 class="oe_slogan">Target New Markets</h2>
<h3 class="oe_slogan">Multi-languages Without Pain</h3>
<div class="oe_span6">
<div class="oe_bg_img">
<img class="oe_picture" src="">
</div>
</div>
<div class="oe_span6">
<p class='oe_mt32'>
Get your website translated in multiple languages with no effort.
OpenERP proposes and propagates translations automatically
across pages.
</p>
Our translation "on demand" features allows you to benefit from
professional translators to translate all your changes
automatically. Just change any part of your website (a new blog
post, a page modification, product descriptions, ...) and the translated
versions are updated automatically in around 32 hours.
</p>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row">
<h2 class="oe_slogan">Designer-Friendly Themes</h2>
<h3 class="oe_slogan">Designers love working on OpenERP</h3>
<div class="oe_span6">
<p class='oe_mt32'>
Themes are awesome and easy to design. You don't need to develop
to create new pages, themes or building blocks. We use a clean
HTML structure, a <a href="http://getbootstrap.com/">bootstrap</a>
CSS and our modularity allows to distribute your themes easily.
</p><p>
The building block approach allows the website to remain clean
after the end-users start creating new contents.
</p>
</div>
<div class="oe_span6">
<div class="oe_row_img oe_centered">
<img class="oe_picture" src="">
</div>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row">
<h2 class="oe_slogan">Acquire New Customers</h2>
<h3 class="oe_slogan">SEO tools at your finger tips</h3>
<div class="oe_span6">
<div class="oe_bg_img">
<img class="oe_picture oe_screenshot" src="">
</div>
</div>
<div class="oe_span6">
<p class='oe_mt32'>
SEO tools are ready to use, with no configuration required.
OpenERP suggests keywords according to Google most searched
terms, Google Analytics tracks your shopping cart events,
sitemap are created automatically for Google indexation, etc.
</p><p>
We even do structured content automatically to promote your
product and events efficiently in Google.
</p>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row">
<h2 class="oe_slogan">Leverage Social Media</h2>
<h3 class="oe_slogan">Optimize: from Ads to Conversions</h3>
<div class="oe_span6">
<p class='oe_mt32'>
Create new landing pages easily with the OpenERP inline edition
feature. Send visitors of your different marketing campaigns to
specific landing pages to optimize conversions.
</p>
</div>
<div class="oe_span6">
<div class="oe_bg_img">
<img class="oe_picture oe_screenshot" src="">
</div>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row">
<h2 class="oe_slogan">Manage a Resellers Network</h2>
<h3 class="oe_slogan">Referencing, Lead Forward, Pricelists</h3>
<div class="oe_span6">
<div class="oe_bg_img">
<img class="oe_picture oe_screenshot" src="">
</div>
</div>
<div class="oe_span6">
<p class='oe_mt32'>
Manage a reseller network to target new market, have local
presences or broaden your distribution. Give them access to your
reseller portal for an efficient collaboration.
</p>
Promote your resellers online, forward leads to resellers (with
built-in geolocalisation feature), define specific pricelists,
launch a loyalty program (offer specific discounts to your best
customers or resellers), etc.
</p>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row">
<h2 class="oe_slogan"></h2>
<h3 class="oe_slogan">Integrated vs Interfaced</h3>
<div class="oe_span6">
<p class='oe_mt32'>
Benefit from the power of OpenERP, in your online store: a
powerfull tax engine, flexible pricing structures, a real
inventory management solution, a reseller interface, support
for products with different behaviours; physical goods, events,
services, variants and options, etc.
</p><p>
You don't need to interface with your warehouse, sales or
accounting software. Everything is integrated with OpenERP. No
pain, real time.
</p>
</div>
<div class="oe_span6">
<div class="oe_bg_img oe_centered">
<img class="oe_picture" src="">
</div>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row">
<h2 class="oe_slogan">And much more...</h2>
<div class="oe_span4">
<h3 class="oe_slogan">Online Sales</h3>
<ul>
<li>Mobile Interface</li>
<li>Sell products, events or services</li>
<li>Flexible pricelists</li>
<li>Product multi-variants</li>
<li>Multiple stores</li>
</ul>
</div>
<div class="oe_span4">
<h3 class="oe_slogan">Customer Service</h3>
<ul>
<li>Customer Portal to track orders</li>
<li>Assisted shopping with live chats</li>
<li>Returns management</li>
<li>Advanced shipping rules</li>
<li>Coupons or gift certificates</li>
</ul>
</div>
<div class="oe_span4">
<h3 class="oe_slogan">Order Management</h3>
<ul>
<li>Advanced warehouse management features</li>
<li>Invoicing and accounting integration</li>
<li>Mass mailing and customer segmentations</li>
<li>Lead automation and marketing campaigns</li>
<li>Persistent shopping cart</li>
</ul>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row">
<h2 class="oe_slogan">Fully Integrated With Others Apps</h2>
<h3 class="oe_slogan">Get hundreds of open source apps for free</h3>
<div class="oe_span4">
<a href="/apps/website">
<h3>CMS</h3>
<div class="oe_row_img oe_centered">
<img class="oe_picture oe_screenshot" src="">
</div>
</a>
<p>
Easily create awesome websites with no technical knowledge required.
</p>
</div>
<div class="oe_span4">
<a href="/apps/website_mail">
<h3>Blogs</h3>
<div class="oe_row_img oe_centered">
<img class="oe_picture oe_screenshot" src="">
</div>
</a>
<p>
Write news, attract new visitors, build customer loyalty.
</p>
</div>
<div class="oe_span4">
<a href="/apps/website_event">
<h3>Online Events</h3>
<div class="oe_row_img oe_centered">
<img class="oe_picture oe_screenshot" src="">
</div>
</a>
<p>
Schedule, organize, promote or sell events online; conferences,
webinars, trainings, etc.
</p>
</div>
<div class="oe_span12 oe_centered oe_muted">
<a href="/apps">
and hundreds more applications...
</a>
</div>
</div>
</section>
@@ -1,68 +0,0 @@
$(document).ready(function () {
$('.oe_ecommerce').on('click', '.js_publish, .js_unpublish', function (e) {
e.preventDefault();
var $link = $(this).parent();
$link.find('.js_publish, .js_unpublish').addClass("hidden");
var $unp = $link.find(".js_unpublish");
var $p = $link.find(".js_publish");
$.post('/shop/publish', {'id': $link.data('id')}, function (result) {
if (+result) {
$p.addClass("hidden");
$unp.removeClass("hidden");
} else {
$p.removeClass("hidden");
$unp.addClass("hidden");
}
});
});
$('.oe_ecommerce').on('click', '.oe_product .btn, .oe_product_detail .btn', function (e) {
var $button = $(e.currentTarget);
var $product = $button.parents('.oe_product:first, .oe_product_detail:first');
var link = $button.hasClass('btn-inverse') ? '/shop/remove_cart' : '/shop/add_cart';
var $add = $product.find('.btn-success,.btn-primary');
var $remove = $product.find('.btn-inverse');
$.get(link, {'product_id': $button.data('id')}, function (result) {
var result = JSON.parse(result);
var quantity = parseInt(result.quantity);
$add.find('.oe_quantity')
.html(quantity);
$add.toggleClass('btn-primary', !quantity)
.toggleClass('btn-success', !!quantity);
$remove.toggleClass('hidden', !quantity);
if ($('.oe_mycart').size() && !quantity) {
$product.remove()
}
$('.oe_ecommerce .oe_total').replaceWith(''+result.totalHTML);
});
});
var $checkout = $(".oe_ecommerce .oe_checkout");
$(".oe_ecommerce input[name='shipping_different']").change(function() {
$(".oe_ecommerce .js_shipping").toggle();
});
$(".oe_ecommerce .js_error_payment").click(function(e) {
var values = {};
$checkout.find(".js_inputs:not(:hidden) input:not(:checkbox), .js_inputs:not(:hidden) select, .js_signin_modal input").each(function() {
values[$(this).attr("name")] = $(this).val();
});
$checkout.find("input").css("border", "");
$.post('/shop/confirm_order', values, function (result) {
var result = JSON.parse(result);
console.log(result);
if (result.error.length) {
$inputs = $checkout.find("input[name='" + result.error.join("'], input[name='") + "']");
$inputs.css("border", "1px solid #dd0000");
$inputs.first().focus();
}
if (result.validation) {
var $form = $(e.currentTarget).parent().find("input[name='submit']").click();
setTimeout(function() {
window.location.href = "/shop/confirmed";
}, 0);
}
});
});
});
@@ -0,0 +1,13 @@
$(document).ready(function () {
$(".oe_website_sale input[name='shipping_different']").change(function() {
$(".oe_website_sale .js_shipping").toggle();
});
$(".oe_website_sale .oe_mycart input").change(function() {
var value = parseInt($(this).val());
if (!isNaN(value)) {
window.location.href = window.location.origin + window.location.pathname + 'set_cart/' + $(this).data('id') + '/' + value + '/';
}
});
});
-363
View File
@@ -1,363 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- Layout add nav and footer -->
<record id="header_ecommerce" model="ir.ui.view">
<field name="name">header_ecommerce</field>
<field name="inherit_id" ref="website.header"/>
<field name="arch" type="xml">
<data>
<xpath expr="(//li)[last()]" position="after">
<li class="pull-right"><a href="/shop/mycart"><i class="icon-shopping-cart icon-large" style="position: absolute;"></i>&amp;nbsp; &amp;nbsp; &amp;nbsp; My cart</a></li>
<li class="pull-right"><a href="/shop">Shop</a></li>
</xpath>
</data>
</field>
</record>
<record id="header_ecommerce" model="ir.ui.view">
<field name="name">header_ecommerce</field>
<field name="inherit_id" ref="website.header"/>
<field name="arch" type="xml">
<data>
<xpath expr="(//li)[last()]" position="after">
<li class="pull-right"><a href="/shop/mycart"><i class="icon-shopping-cart icon-large" style="position: absolute;"></i>&amp;nbsp; &amp;nbsp; &amp;nbsp; My cart</a></li>
<li class="pull-right"><a href="/shop">Shop</a></li>
</xpath>
</data>
</field>
</record>
<record id="product_normal_form_view" model="ir.ui.view">
<field name="name">product.normal.form.inherit</field>
<field name="model">product.product</field>
<field name="inherit_id" ref="stock.view_normal_procurement_locations_form"/>
<field name="arch" type="xml">
<group name="sale" position="before">
<group name="pos" string="Website">
<field name="website_published"/>
</group>
</group>
</field>
</record>
<!-- Page Shop -->
<template id="page">
<t t-call="website.layout">
<t t-set="head">
<script type="text/javascript" src="/website_sale/static/src/js/ecommerce.js"></script>
<link rel='stylesheet' href='/website_sale/static/src/css/ecommerce.css'/>
<t t-raw="head"/>
</t>
<t t-set="title">Shop - <t t-raw="title">Categories</t></t>
<div class="container mt48 oe_ecommerce">
<div class="row">
<t t-call='website_sale.categories' />
<t t-raw="shop_content" />
</div>
</div>
</t>
</template>
<!-- List of categories -->
<template id="categories">
<div class="span4">
<ul class="nav nav-list">
<li t-att-class=" '' if current_category else 'active' " class='active'><a href='/shop/'>All Products</a></li>
<t t-foreach="website_sale_get_categories()" t-as="category">
<t t-call="website_sale.categories_recursive"/>
</t>
</ul>
</div>
</template>
<template id="categories_recursive">
<li t-att-class="category.id == current_category and 'active' or ''">
<a t-att-href="'/shop/category/%%s' %% category.id" t-field="category.name"></a>
<ul t-if="category.child_id" class="nav nav-list">
<t t-foreach="category.child_id" t-as="category">
<t t-call="website_sale.categories_recursive"/>
</t>
</ul>
</li>
</template>
<!-- Product list -->
<template id="product_pager">
<t t-set="classname" t-value="classname or ''" />
<div t-if="page_count != 1" t-att-class="classname + ' pagination'">
<ul>
<li t-att-class=" 'disabled' if page == 1 else '' " ><a t-att-href=" '#' if page == 1 else ('/shop/category/%%s/page/%%s' %% (current_category, max(0,page-1))) ">Prev</a></li>
<t t-foreach="pages" t-as="p">
<li t-att-class=" 'active' if p == page else '' " ><a t-att-href=" '/shop/category/%%s/page/%%s' %% (current_category, p)" t-raw='p'></a></li>
</t>
<li t-att-class=" 'disabled' if page == page_count else '' "><a t-att-href=" '#' if page == page_count else ('/shop/category/%%s/page/%%s' %% (current_category, min(page_count,page+1))) ">Next</a></li>
</ul>
</div>
</template>
<template id="products">
<t t-call="website_sale.page">
<t t-set="title">Product</t>
<t t-set="shop_content">
<div class='span8 navbar navbar-inverse'>
<div class='navbar-inner'>
<t t-call="website_sale.product_pager" >
<t t-set="classname">pull-left</t>
</t>
<form action="/shop" method="get" class="navbar-search pull-right">
<input type="text" name="search" class="search-query span2" placeholder="Search" t-att-value="search or '' or ''"/>
</form>
</div>
</div>
<div class="span8">
<div class='row grid grid-align-top'>
<t t-foreach="products" t-as="product">
<t t-set="quantity" t-value="([int(line.product_uom_qty) for line in (order.order_line or []) if line.product_id.id == product.id] + [0])[0]"/>
<t t-call="website_sale.product_card"/>
</t>
</div>
</div>
<div class="span8 offset4 text-center">
<t t-call="website_sale.product_pager" />
</div>
</t>
</t>
</template>
<template id="product_card">
<div class="oe_product span2 mb16 thumbnail text-center">
<a t-att-href="'/shop/product/%%s' %% product.id">
<h5 t-field="product.name"> </h5>
</a>
<a t-att-href="'/shop/product/%%s' %% product.id">
<img class="img-rounded" t-att-src="'data:image/png;base64,' + product.image"/>
</a>
<div>
<div t-field="product.description_sale"></div>
<div><span t-field="product.list_price"></span>€</div>
<div class="mb8 mt8">
<button t-att-class="'btn mb8 btn-small btn-inverse %%s' %% (not quantity and 'hidden' or '')" t-att-data-id="product.id">Remove one</button>
<button t-att-class="'btn btn-small %%s' %% (quantity and 'btn-success' or 'btn-primary')" t-att-data-id="product.id">
Add to cart <t t-if="quantity">(<t t-esc="quantity"/>)</t>
</button>
</div>
</div>
</div>
</template>
<template id="product_recommended">
<div class="well mt32" t-if="recommended_products">
<h4>Customers who have bought this item also bought</h4>
<div class='row mt16'>
<t t-foreach="recommended_products or []" t-as="product">
<div class='span2 thumbnail'>
<a t-att-href="'/shop/product/%%s' %% product.id">
<div class='mt16 text-center'>
<img t-att-src="'data:image/png;base64,' + product.image"/>
<h5 t-field='product.name'></h5>
</div>
</a>
</div>
</t>
</div>
</div>
</template>
<!-- product -->
<template id="product">
<t t-call="website_sale.page">
<t t-set="title">Product</t>
<t t-set="shop_content">
<div class="oe_product_detail span8">
<a href="#" t-att-data-id="product.id" class="pull-right" t-if="editable">
<span t-att-class="'label label-success js_unpublish %%s' %% (not product.website_published and 'hidden' or '')">Click to Unpublish</span>
<span t-att-class="'label label-important js_publish %%s' %% (product.website_published and 'hidden' or '')">Click to Publish</span>
</a>
<h2 t-field="product.name"></h2>
<div class="oe_button_cart">
<button t-att-class="'btn btn-small btn-inverse %%s' %% (not quantity and 'oe_hidden' or '')" t-att-data-id="product.id">Remove one</button>
<button t-att-class="'btn btn-small %%s' %% (quantity and 'btn-success' or 'btn-primary')" t-att-data-id="product.id">
Add to cart <t t-if="quantity" >(<t t-esc="quantity"/>)</t>
</button>
</div>
<img class="media-object" t-att-src="'data:image/png;base64,' + product.image"/>
<div t-field="product.description_website"></div>
<div class="oe_ecommerce_price"><t t-field="product.list_price" />€</div>
<t t-call="website_sale.product_recommended"/>
</div>
</t>
</t>
</template>
<!-- Page Shop my cart -->
<template id="mycart">
<t t-call="website_sale.page">
<t t-set="title">My cart</t>
<t t-set="shop_content">
<div class="span8 oe_mycart">
<h2>My Shopping Cart</h2>
<h3 t-if="not order.order_line">Your cart is empty</h3>
<div class='row mt32 grid grid-align-top'>
<t t-foreach="order.order_line or []" t-as="line">
<t t-set="product" t-value="line.product_id"/>
<t t-set="quantity" t-value="int(line.product_uom_qty)"/>
<t t-call="website_sale.product_card"/>
</t>
</div>
<t t-call="website_sale.total"/>
<form t-if="order.order_line" class="well form-search" action="/shop/mycart" >
<input name="code" class='input' type="text" placeholder="Reduction Code..."/>
<button class="btn">Apply Code</button>
</form>
<a t-if="order.order_line" href="/shop/checkout"><button class="btn btn-success">Proceed To Payment</button></a>
<t t-call="website_sale.product_recommended"/>
</div>
</t>
</t>
</template>
<!-- Total Shop my cart -->
<template id="total">
<div class="row oe_total">
<div class="span4">
<div class="well">
<table class='table-equalized' t-if="order.order_line">
<tr> <td>Subtotal </td> <td><t t-esc="order.amount_untaxed"/> €</td></tr>
<tr> <td>Taxes </td> <td><t t-esc="order.amount_tax"/> €</td></tr>
<tr> <td><h4>Total</h4></td> <td><h4><t t-esc="order.amounttotal"/> €</h4></td></tr>
</table>
</div>
</div>
</div>
</template>
<!-- Page confirm my cart -->
<template id="checkout">
<t t-call="website.layout">
<t t-set="head">
<script type="text/javascript" src="/website_sale/static/src/js/ecommerce.js"></script>
<link rel='stylesheet' href='/website_sale/static/src/css/ecommerce.css'/>
<t t-raw="head"/>
</t>
<t t-set="title">Shop - Checkout</t>
<div class="container mt48 oe_ecommerce">
<div class="row">
<div class="span4 oe_total">
<table class="table table-condensed" t-if="order.order_line">
<thead>
<tr><th>Product</th><th>Qty.</th><th>Price</th></tr>
</thead>
<tbody>
<t t-foreach="order.order_line or []" t-as="line">
<tr>
<td><t t-esc="line.product_id.name"/></td>
<td><t t-esc="int(line.product_uom_qty)"/></td>
<td class="css_alignright"><t t-esc="line.product_id.list_price"/> €</td>
</tr>
</t>
<tr><td colspan="3" style="visibility: hidden; border: 0">-</td></tr>
<tr><th>Untaxed Amount</th><td></td><td><t t-esc="order.amount_untaxed"/> €</td></tr>
<tr><th>Taxes</th><td></td><td><t t-esc="order.amount_tax"/> €</td></tr>
<tr><th>Total</th><td></td><td><t t-esc="order.amount_total"/> €</td></tr>
</tbody>
</table>
</div>
<div class="span8 oe_checkout">
<div class="js_inputs row">
<a t-if="not partner" t-att-href="'/admin#action=redirect&amp;url=%%s/shop/checkout' %% host_url" class="btn btn-primary">Log me, I have an account</a>
<h3 class="span8">Billing Information</h3>
<label class="span8 css_required">Name and firstname<input class="span7" type="text" name="name" placeholder="Name and firstname" t-att-value="partner.name or ''"/></label>
<label class="span4 css_required">Telephone<input type="tel" name="phone" placeholder="Telephone" t-att-value="partner.phone or ''"/></label>
<label class="span4">Fax<input type="tel" name="fax" placeholder="Fax" t-att-value="partner.fax or ''"/></label>
<label class="span4">Company<input type="text" name="company" placeholder="Company" t-att-value="partner.parent_id and partner.parent_id.name or ''"/></label>
<label class="span4 css_required">Email address<input type="email" name="email" placeholder="Email address" t-att-value="partner.email or ''"/></label>
<label class="span8 css_required">Street<input class="span7" type="text" name="street" placeholder="Street address" t-att-value="partner.street or ''"/></label>
<label class="span4 css_required">City<input type="text" name="city" placeholder="City" t-att-value="partner.city or ''"/></label>
<label class="span4">State / Province <select name="state_id">
<option value="">State / Province...</option>
<t t-foreach="states or []" t-as="state">
<option t-att-value="state.id" t-att-selected="partner and partner.state_id and state.id == partner.state_id.id or None"><t t-esc="state.name"/></option>
</t>
</select></label>
<label class="span4 css_required">Zip / Postal Code<input type="text" name="zip" placeholder="Zip/Postal Code" t-att-value="partner.zip or ''"/></label>
<label class="span4 css_required">Country <select name="country_id">
<option value="">Country...</option>
<t t-foreach="countries or []" t-as="country">
<option t-att-value="country.id" t-att-selected="partner and partner.country_id and country.id == partner.country_id.id or None"><t t-esc="country.name"/></option>
</t>
</select></label>
<label class="span8 checkbox">Ship to different address<input type="checkbox" name="shipping_different"/></label>
</div>
<div class="js_inputs js_shipping row" style="display:none">
<h3 class="span8 oe_shipping" style="display:none">Shipping Information</h3>
<label class="span8 css_required">Name and firstname<input class="span7" type="text" name="shipping_name" placeholder="Name and firstname" t-att-value="shipping.name or ''"/></label>
<label class="span4 css_required">Telephone<input type="tel" name="shipping_phone" placeholder="Telephone" t-att-value="shipping.phone or ''"/></label>
<label class="span4">Fax<input type="tel" name="shipping_fax" placeholder="Fax" t-att-value="shipping.fax or ''"/></label>
<label class="span8 css_required">Street<input class="span7" type="text" name="shipping_street" placeholder="Street address" t-att-value="shipping.street or ''"/></label>
<label class="span4 css_required">City<input type="text" name="shipping_city" placeholder="City" t-att-value="shipping.city or ''"/></label>
<label class="span4">State / Province <select name="shipping_state_id">
<option value="">State / Province...</option>
<t t-foreach="states or []" t-as="state">
<option t-att-value="state.id" t-att-selected="shipping and shipping.state_id and state.id == shipping.state_id.id or None"><t t-esc="state.name"/></option>
</t>
</select></label>
<label class="span4 css_required">Zip / Postal Code<input type="text" name="shipping_zip" placeholder="Zip/Postal Code" t-att-value="shipping.zip or ''"/></label>
<label class="span4 css_required">Country <select name="shipping_country_id">
<option value="">Country...</option>
<t t-foreach="countries or []" t-as="country">
<option t-att-value="country.id" t-att-selected="shipping and shipping.country_id and country.id == shipping.country_id.id or None"><t t-esc="country.name"/></option>
</t>
</select></label>
</div>
<div class="js_payments css_payments row">
<h3 class="span8">Click on your payment method</h3>
<t t-foreach="payments or []" t-as="payment">
<div class="css_payment" t-att-title="payment.name">
<div class="js_error_payment css_error_payment"> </div>
<t t-raw="payment._content"/>
</div>
</t>
</div>
</div>
</div>
</div>
</t>
</template>
<template id="confirmed">
<t t-call="website_sale.page">
<t t-set="title">Order</t>
<t t-set="shop_content">
<table class="table table-condensed" t-if="order.order_line">
<thead>
<tr><th>Product</th><th>Qty.</th><th>Price</th></tr>
</thead>
<tbody>
<t t-foreach="order.order_line or []" t-as="line">
<tr>
<td><t t-esc="line.product_id.name"/></td>
<td><t t-esc="int(line.product_uom_qty)"/></td>
<td class="css_alignright"><t t-esc="line.product_id.list_price"/> €</td>
</tr>
</t>
<tr><td colspan="3" style="visibility: hidden; border: 0">-</td></tr>
<tr><th>Untaxed Amount</th><td></td><td><t t-esc="order.amount_untaxed"/> €</td></tr>
<tr><th>Taxes</th><td></td><td><t t-esc="order.amount_tax"/> €</td></tr>
<tr><th>Total</th><td></td><td><t t-esc="order.amount_total"/> €</td></tr>
</tbody>
</table>
</t>
</t>
</template>
</data>
</openerp>
-15
View File
@@ -1,15 +0,0 @@
<?xml version="1.0"?>
<openerp>
<data>
<record model="ir.ui.view" id="product_pricelist_view">
<field name="name">product.pricelist.website.form</field>
<field name="model">product.pricelist</field>
<field name="inherit_id" ref="product.product_pricelist_view"/>
<field name="arch" type="xml">
<field name="active" position="after">
<field name="code"/>
</field>
</field>
</record>
</data>
</openerp>
+462
View File
@@ -0,0 +1,462 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record model="ir.ui.view" id="product_pricelist_view">
<field name="name">product.pricelist.website.form</field>
<field name="model">product.pricelist</field>
<field name="inherit_id" ref="product.product_pricelist_view"/>
<field name="arch" type="xml">
<field name="active" position="after">
<field name="code"/>
</field>
</field>
</record>
<!-- Layout add nav and footer -->
<template id="footer_custom" inherit_id="website.layout" name="Custom Footer">
<xpath expr="//body/header//ul[@id='top_menu']/li" position="before">
<li><a href="/shop/">Shop</a></li>
<li>
<a href="/shop/mycart/">
<i class="icon-shopping-cart"></i>
My cart
<t t-if="order.get_total_quantity()">
<span class="badge badge-success" t-esc="order.get_total_quantity()"/>
</t>
</a>
</li>
</xpath>
</template>
<record id="product_normal_form_view" model="ir.ui.view">
<field name="name">product.normal.form.inherit</field>
<field name="model">product.product</field>
<field name="inherit_id" ref="stock.view_normal_procurement_locations_form"/>
<field name="arch" type="xml">
<group name="sale" position="before">
<group name="pos" string="Website">
<field name="website_published"/>
</group>
</group>
</field>
</record>
<!-- Page Shop -->
<template id="layout" name="Products Layout">
<t t-call="website.layout">
<t t-set="head">
<script type="text/javascript" src="/website_sale/static/src/js/website_sale.js"></script>
<t t-raw="head or ''"/>
</t>
<t t-set="title">Shop - <t t-raw="title">Categories</t></t>
<div class="container mt48 oe_website_sale">
<div class="row">
<div class="span12" id="shop_content">
<t t-raw="shop_content" />
</div>
</div>
</div>
</t>
</template>
<template id="products_categories" inherit_id="website_sale.layout" inherit_option_id="website_sale.layout" name="Products Left Categories">
<xpath expr="//div[@id='shop_content']" position="before">
<div class="span4">
<ul class="nav nav-list">
<li t-att-class=" '' if current_category else 'active' " class='active'><a href="/shop/">All Products</a></li>
<t t-foreach="categories" t-as="category">
<t t-call="website_sale.categories_recursive"/>
</t>
</ul>
</div>
</xpath>
<xpath expr="//div[@id='shop_content']" position="attributes">
<attribute name="class">span8</attribute>
</xpath>
</template>
<!-- List of categories -->
<template id="categories_recursive">
<li t-att-class="category.id == current_category and 'active' or ''">
<a t-attf-href="/shop/category/#{ category.id }/" t-field="category.name"></a>
<ul t-if="category.child_id" class="nav nav-list">
<t t-foreach="category.child_id" t-as="category">
<t t-call="website_sale.categories_recursive"/>
</t>
</ul>
</li>
</template>
<!-- Product list -->
<template id="products">
<t t-call="website_sale.layout">
<t t-set="title">Product</t>
<t t-set="shop_content">
<div class='navbar navbar-inverse'>
<div class='navbar-inner'>
<t t-call="website.pager" >
<t t-set="classname">pull-left</t>
</t>
<form action="/shop/" method="get" class="navbar-search pull-right pagination">
<input type="text" name="search" class="search-query span2" placeholder="Search" t-att-value="search or '' or ''"/>
</form>
</div>
</div>
<div class='row grid grid-align-top'>
<div t-foreach="products" t-as="product" class="span2 mb16 thumbnail text-center">
<a t-attf-href="/shop/product/#{ product.id }/ ">
<h5 t-field="product.name"> </h5>
</a>
<a t-attf-href="/shop/product/#{ product.id }/">
<img class="img-rounded" t-att-src="product.img('image_small')"/>
</a>
<div>
<div t-field="product.description_sale"></div>
<div><span t-field="product.list_price"></span>€</div>
<div class="mb8 mt8">
<a t-attf-href="./add_cart/#{ product.id }/" class="btn btn-small btn-success">Add to cart</a>
</div>
</div>
</div>
</div>
<div class="text-center">
<t t-call="website.pager" />
</div>
</t>
</t>
</template>
<!-- product -->
<template id="product" name="Product">
<t t-call="website_sale.layout">
<t t-set="title">Product</t>
<t t-set="shop_content">
<div id="product_detail">
<t t-call="website.publish"><t t-set="object" t-value="product"/></t>
<h2 t-field="product.name"></h2>
<a t-attf-href="./add_cart/#{ product.id }/" class="btn btn-small btn-success pull-right">Add to cart</a>
<img class="media-object" t-att-src="product.img('image')"/>
<div t-field="product.description_website"></div>
<div><t t-field="product.list_price" />€</div>
</div>
</t>
</t>
</template>
<template id="recommended_products" inherit_id="website_sale.product" inherit_option_id="website_sale.product" name="Recommended Products">
<xpath expr="//div[@id='product_detail']" position="inside">
<div class="well mt32" t-if="product.recommended_products()">
<h4>Customers who have bought this item also bought</h4>
<div class='row mt16'>
<t t-foreach="product.recommended_products()" t-as="product">
<div class='span2 thumbnail'>
<a t-attf-href="/shop/product/#{ product.id }/">
<div class='mt16 text-center'>
<img t-att-src="product.img('image_small')"/>
<h5 t-field='product.name'></h5>
</div>
</a>
</div>
</t>
</div>
</div>
</xpath>
</template>
<!-- Page Shop my cart -->
<template id="mycart">
<t t-call="website_sale.layout">
<t t-set="title">My cart</t>
<t t-set="shop_content">
<div class="span8 oe_mycart">
<h2>My Shopping Cart</h2>
<table class='table table-hover'>
<thead>
<tr>
<th width="80">Product</th>
<th></th>
<th width="80">Price</th>
<th width="150">Quantity</th>
</tr>
</thead>
<tbody t-if="not order.order_line">
<tr><td colspan="4"><h3>Your cart is empty</h3></td></tr>
</tbody>
<tbody t-if="order.order_line">
<t t-foreach="order.order_line" t-as="line">
<tr>
<td>
<a t-attf-href="/shop/product/#{ line.product_id.id }/"><img class="img-rounded" t-att-src="line.product_id.img('image_small')"/></a>
</td>
<td>
<a t-attf-href="/shop/product/#{ line.product_id.id }/"><span t-field="line.product_id.name"/></a><br/>
<small t-field="line.product_id.description_sale"/>
</td>
<td>
<span t-field="line.product_id.list_price"></span>€
</td>
<td>
<div class="mb8 mt8">
<input type="text" class="input-mini" t-att-data-id="line.product_id.id" t-att-value="line.product_uom_qty"/>
<a t-attf-href="./remove_cart/#{ line.product_id.id }/" class="btn mb8 btn-small btn-inverse">-</a>
<a t-attf-href="./add_cart/#{ line.product_id.id }/" class="btn mb8 btn-small btn-success">+</a>
</div>
</td>
</tr>
</t>
</tbody>
<tfoot>
<tr> <td colspan="3">Subtotal </td> <td><t t-esc="order.amount_untaxed"/> €</td></tr>
<tr> <td colspan="3">Taxes </td> <td><t t-esc="order.amount_tax"/> €</td></tr>
<tr> <td colspan="3"><h4>Total</h4></td> <td><h4><t t-esc="order.amount_total"/> €</h4></td></tr>
</tfoot>
</table>
<form t-if="order.order_line" class="well form-search" action="/shop/mycart/" method="post">
<input name="code" class='input' type="text" placeholder="Reduction Code..."/>
<button class="btn">Apply Code</button>
</form>
<a t-if="order.order_line" href="/shop/checkout/"><button class="btn btn-success">Proceed To Payment</button></a>
</div>
</t>
</t>
</template>
<!-- Page confirm my cart -->
<template id="checkout">
<t t-call="website.layout">
<t t-set="head">
<script type="text/javascript" src="/website_sale/static/src/js/website_sale.js"></script>
<t t-raw="head or ''"/>
</t>
<t t-set="title">Shop - Checkout</t>
<div class="container mt48 oe_website_sale">
<div class="row">
<div class="span4">
<table class="table table-condensed">
<thead>
<tr>
<th>Product</th>
<th>Price</th>
<th>Qty.</th>
</tr>
</thead>
<tbody t-if="order.order_line">
<t t-foreach="order.order_line" t-as="line">
<tr>
<td><t t-esc="line.name"/></td>
<td><t t-esc="line.product_uom_qty"/></td>
<td><t t-esc="line.product_id.list_price"/>€</td>
</tr>
</t>
</tbody>
<tfoot>
<tr><th>Untaxed Amount</th><td></td><td><t t-esc="order.amount_untaxed"/> €</td></tr>
<tr><th>Taxes</th><td></td><td><t t-esc="order.amount_tax"/> €</td></tr>
<tr><th>Total</th><td></td><td><t t-esc="order.amount_total"/> €</td></tr>
</tfoot>
</table>
</div>
<form class="span8 form-horizontal" action="/shop/confirm_order/" method="post">
<div class=" row">
<a t-if="not partner" t-att-href="'/admin#action=redirect&amp;url=%%s/shop/checkout/' %% host_url" class="btn btn-primary">Log me, I have an account</a>
<h3 class="span8">Billing Information</h3>
<div t-attf-class="control-group #{error.get('name', '')}">
<label class="control-label" for="contact_name">Name and firstname</label>
<div class="controls">
<input type="text" name="name" t-att-value="checkout.get('name', '')"/>
</div>
</div>
<div t-attf-class="control-group #{error.get('phone', '')}">
<label class="control-label" for="contact_name">Telephone</label>
<div class="controls">
<input type="tel" name="phone" t-att-value="checkout.get('phone', '')"/>
</div>
</div>
<div t-attf-class="control-group #{error.get('fax', '')}">
<label class="control-label" for="contact_name">Fax</label>
<div class="controls">
<input type="tel" name="fax" t-att-value="checkout.get('fax', '')"/>
</div>
</div>
<div t-attf-class="control-group #{error.get('company', '')}">
<label class="control-label" for="contact_name">Company</label>
<div class="controls">
<input type="tel" name="company" t-att-value="checkout.get('company', '')"/>
</div>
</div>
<div t-attf-class="control-group #{error.get('email', '')}">
<label class="control-label" for="contact_name">Email address</label>
<div class="controls">
<input type="tel" name="email" t-att-value="checkout.get('email', '')"/>
</div>
</div>
<div t-attf-class="control-group #{error.get('street', '')}">
<label class="control-label" for="contact_name">Street</label>
<div class="controls">
<input type="tel" name="street" t-att-value="checkout.get('street', '')"/>
</div>
</div>
<div t-attf-class="control-group #{error.get('city', '')}">
<label class="control-label" for="contact_name">City</label>
<div class="controls">
<input type="tel" name="city" t-att-value="checkout.get('city', '')"/>
</div>
</div>
<div t-attf-class="control-group #{error.get('state_id', '')}">
<label class="control-label" for="contact_name">State / Province</label>
<div class="controls">
<select name="state_id">
<option value="">State / Province...</option>
<t t-foreach="states or []" t-as="state">
<option t-att-value="state.id" t-att-selected="state.id == checkout.get('state_id')"><t t-esc="state.name"/></option>
</t>
</select>
</div>
</div>
<div t-attf-class="control-group #{error.get('zip', '')}">
<label class="control-label" for="contact_name">Zip / Postal Code</label>
<div class="controls">
<input type="tel" name="zip" t-att-value="checkout.get('zip', '')"/>
</div>
</div>
<div t-attf-class="control-group #{error.get('country_id', '')}">
<label class="control-label" for="contact_name">Country</label>
<div class="controls">
<select name="country_id">
<option value="">Country...</option>
<t t-foreach="countries or []" t-as="country">
<option t-att-value="country.id" t-att-selected="country.id == checkout.get('country_id')"><t t-esc="country.name"/></option>
</t>
</select>
</div>
</div>
<div class="control-group checkbox">
<div class="controls">
<label class="checkbox">
<input t-if="not shipping" type="checkbox" name="shipping_different"/>
<input t-if="shipping" type="checkbox" name="shipping_different" checked="1"/>
Ship to different address
</label>
</div>
</div>
</div>
<div class="js_shipping row" t-att-style="not shipping and 'display:none' or ''">
<h3 class="span8 oe_shipping">Shipping Information</h3>
<div t-attf-class="control-group #{error.get('shipping_name', '')}">
<label class="control-label" for="contact_name">Name and firstname</label>
<div class="controls">
<input type="text" name="shipping_name" t-att-value="checkout.get('shipping_name', '')"/>
</div>
</div>
<div t-attf-class="control-group #{error.get('shipping_phone', '')}">
<label class="control-label" for="contact_name">Telephone</label>
<div class="controls">
<input type="tel" name="shipping_phone" t-att-value="checkout.get('shipping_phone', '')"/>
</div>
</div>
<div t-attf-class="control-group #{error.get('shipping_fax', '')}">
<label class="control-label" for="contact_name">Fax</label>
<div class="controls">
<input type="tel" name="shipping_fax" t-att-value="checkout.get('shipping_fax', '')"/>
</div>
</div>
<div t-attf-class="control-group #{error.get('shipping_street', '')}">
<label class="control-label" for="contact_name">Street</label>
<div class="controls">
<input type="tel" name="shipping_street" t-att-value="checkout.get('shipping_street', '')"/>
</div>
</div>
<div t-attf-class="control-group #{error.get('shipping_city', '')}">
<label class="control-label" for="contact_name">City</label>
<div class="controls">
<input type="tel" name="shipping_city" t-att-value="checkout.get('shipping_city', '')"/>
</div>
</div>
<div t-attf-class="control-group #{error.get('shipping_state_id', '')}">
<label class="control-label" for="contact_name">State / Province</label>
<div class="controls">
<select name="shipping_state_id">
<option value="">State / Province...</option>
<t t-foreach="states or []" t-as="state">
<option t-att-value="state.id" t-att-selected="state.id == checkout.get('shipping_state_id')"><t t-esc="state.name"/></option>
</t>
</select>
</div>
</div>
<div t-attf-class="control-group #{error.get('shipping_zip', '')}">
<label class="control-label" for="contact_name">Zip / Postal Code</label>
<div class="controls">
<input type="tel" name="shipping_zip" t-att-value="checkout.get('shipping_zip', '')"/>
</div>
</div>
<div t-attf-class="control-group #{error.get('shipping_country_id', '')}">
<label class="control-label" for="contact_name">Country</label>
<div class="controls">
<select name="shipping_country_id">
<option value="">Country...</option>
<t t-foreach="countries or []" t-as="country">
<option t-att-value="country.id" t-att-selected="country.id == checkout.get('shipping_country_id')"><t t-esc="country.name"/></option>
</t>
</select>
</div>
</div>
</div>
<button type="submit">Last stape</button>
</form>
</div>
</div>
</t>
</template>
<template id="payment">
<t t-call="website.layout">
<t t-set="title">Shop - Payment</t>
<div class="container mt48 oe_website_sale">
<div class="row">
<div class="span4">
<table class="table table-condensed">
<thead>
<tr>
<th>Product</th>
<th>Price</th>
<th>Qty.</th>
</tr>
</thead>
<tbody t-if="order.order_line">
<t t-foreach="order.order_line" t-as="line">
<tr>
<td><t t-esc="line.name"/></td>
<td><t t-esc="line.product_uom_qty"/></td>
<td><t t-esc="line.product_id.list_price"/>€</td>
</tr>
</t>
</tbody>
<tfoot>
<tr><th>Untaxed Amount</th><td></td><td><t t-esc="order.amount_untaxed"/> €</td></tr>
<tr><th>Taxes</th><td></td><td><t t-esc="order.amount_tax"/> €</td></tr>
<tr><th>Total</th><td></td><td><t t-esc="order.amount_total"/> €</td></tr>
</tfoot>
</table>
</div>
<div class="span8">
<div class="row">
<h3 class="span8">Click on your payment method</h3>
<t t-foreach="payments or []" t-as="payment">
<div t-att-title="payment.name">
<t t-raw="payment._content"/>
</div>
</t>
</div>
</div>
</div>
</div>
</t>
</template>
</data>
</openerp>
+69
View File
@@ -0,0 +1,69 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C)-2010 Tiny SPRL (<http://tiny.be>).
#
# 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 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.osv import osv, fields
class product_pricelist(osv.osv):
_inherit = "product.pricelist"
_columns = {
'code': fields.char('Promotionnal Code', size=64, required=True, translate=True),
}
class product_product(osv.osv):
_inherit = "product.product"
_columns = {
'website_published': fields.boolean('Available in the website'),
'description_website': fields.html('Description for the website'),
}
def recommended_products(self, cr, uid, ids, context=None):
id = ids[0]
product_ids = []
query = """
SELECT sol.product_id
FROM sale_order_line as my
LEFT JOIN sale_order_line as sol
ON sol.order_id = my.order_id
WHERE my.product_id in (%s)
AND sol.product_id not in (%s)
GROUP BY sol.product_id
ORDER BY COUNT(sol.order_id) DESC
LIMIT 8
"""
cr.execute(query, (id, id))
for p in cr.fetchall():
product_ids.append(p[0])
# search to apply access rules
product_ids = self.search(cr, uid, [("id", "in", product_ids)])
return self.browse(cr, uid, product_ids)
def img(self, cr, uid, ids, field='image_small', context=None):
return "/website/image?model=%s&field=%s&id=%s" % (self._name, field, ids[0])
class sale_order(osv.osv):
_inherit = "sale.order"
def get_total_quantity(self, cr, uid, ids, context=None):
order = self.browse(cr, uid, ids[0], context=context)
return sum(l.product_uom_qty for l in (order.order_line or []))