[MERGE]Merge lp:~openerp-dev/openobject-addons/trunk-website-al.
bzr revid: bth@tinyerp.com-20130816062420-4a04olf1ulf2v4vy
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import controllers
|
||||
import res_config
|
||||
from website import website
|
||||
|
||||
from website import website
|
||||
import view
|
||||
|
||||
@@ -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'],
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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,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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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());
|
||||
});
|
||||
});
|
||||
@@ -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">
|
||||
|
||||
@@ -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
@@ -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='#'>&#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">
|
||||
<!DOCTYPE html>
|
||||
<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">&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 &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">&lsaquo;</a>
|
||||
<a class="carousel-control right" href="#myCarousel" data-slide="next">&rsaquo;</a>
|
||||
<a class="carousel-control left" href="#myCarousel" data-slide="prev" t-ignore="1">&lsaquo;</a>
|
||||
<a class="carousel-control right" href="#myCarousel" data-slide="next" t-ignore="1">&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>&#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>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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">&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>
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
@@ -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 & 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 & 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 & 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 & 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");
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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&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&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 <= 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 <= 10 and 'warning' or 'info')">
|
||||
<t t-if="event_id.register_avail <= 10">Only</t>
|
||||
<t t-esc="event_id.register_avail"/>
|
||||
<t t-if="event_id.register_avail > 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&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&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 & 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 <= 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 <= 10 and 'warning' or 'info')">
|
||||
<t t-if="event_id.register_avail <= 10">Only</t>
|
||||
<t t-esc="event_id.register_avail"/>
|
||||
<t t-if="event_id.register_avail > 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>
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 & 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>
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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>
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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 & 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>
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)">&larr; Older</a>
|
||||
</li>
|
||||
<li t-if="prev_date" class="next">
|
||||
<a t-att-href="'?date=%%s' %% (prev_date)">Newer &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,3 +1,2 @@
|
||||
import controllers
|
||||
import pricelist
|
||||
import product
|
||||
import website_sale
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
@@ -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 & 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 + '/';
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -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>&nbsp; &nbsp; &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>&nbsp; &nbsp; &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&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>
|
||||
@@ -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>
|
||||
@@ -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&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>
|
||||
@@ -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 []))
|
||||
Reference in New Issue
Block a user