[MERGE]Merge lp:~openerp-dev/openobject-addons/trunk-website-al.
bzr revid: bth@tinyerp.com-20130925093523-xq6otgmj3xdwrunr
This commit is contained in:
commit
55410d9a4d
|
@ -51,7 +51,9 @@ Key Features
|
|||
'res_partner_view.xml',
|
||||
'email_template.xml',
|
||||
],
|
||||
'demo': ['event_demo.xml'],
|
||||
'demo': [
|
||||
'event_demo.xml',
|
||||
],
|
||||
'test': ['test/process/event_draft2done.yml'],
|
||||
'css': ['static/src/css/event.css'],
|
||||
'installable': True,
|
||||
|
|
|
@ -212,7 +212,10 @@ class event_event(osv.osv):
|
|||
'speaker_confirmed': fields.boolean('Speaker Confirmed', readonly=False, states={'done': [('readonly', True)]}),
|
||||
'country_id': fields.related('address_id', 'country_id',
|
||||
type='many2one', relation='res.country', string='Country', readonly=False, states={'done': [('readonly', True)]}, store=True),
|
||||
'note': fields.text('Description', readonly=False, states={'done': [('readonly', True)]}),
|
||||
'description': fields.html(
|
||||
'Description', readonly=False,
|
||||
states={'done': [('readonly', True)]},
|
||||
oldname='note'),
|
||||
'company_id': fields.many2one('res.company', 'Company', required=False, change_default=True, readonly=False, states={'done': [('readonly', True)]}),
|
||||
'is_subscribed' : fields.function(_subscribe_fnc, type="boolean", string='Subscribed'),
|
||||
'visibility': fields.selection(_visibility_selection, 'Privacy / Visibility',
|
||||
|
|
|
@ -27,31 +27,185 @@
|
|||
<field name="name">Training</field>
|
||||
</record>
|
||||
|
||||
<!-- Demo data for Event -->
|
||||
<!-- event.event -->
|
||||
<record id="event_0" model="event.event">
|
||||
<field name="name">Concert of Bon Jovi</field>
|
||||
<field eval="time.strftime('%Y-%m-01 19:05:15')" name="date_begin"/>
|
||||
<field eval="time.strftime('%Y-%m-01 23:05:15')" name="date_end"/>
|
||||
<field name="name">Open Days in Los Angeles</field>
|
||||
<field eval="(DateTime.now() + timedelta(days=1)).strftime('%Y-%m-%d 8:00:00')" name="date_begin"/>
|
||||
<field eval="(DateTime.now() + timedelta(days=5)).strftime('%Y-%m-%d 18:00:00')" name="date_end"/>
|
||||
<field name="register_max">500</field>
|
||||
<field name="address_id" ref="base.res_partner_6"/>
|
||||
<field name="type" ref="event_type_1"/>
|
||||
<field name="description"><![CDATA[
|
||||
<div class="oe_structure">
|
||||
<center><strong>Join us to our main event of the year: the Open Days</strong></center>
|
||||
<p> </p>
|
||||
<p>Every year we invite our community, partners and end-users to come and meet us! It's the ideal event to get together and present new features, roadmap of future versions, achievements of the software, workshops, training sessions, etc.... This event is also an opportunity to showcase our partners' case studies, methodology or developments. Be there and see directly from the source the features of the version 8!
|
||||
</p>
|
||||
<p>This event and all the conferences are in english!</p>
|
||||
<p> </p>
|
||||
<p><strong>What's new for this year?</strong></p>
|
||||
<ul>
|
||||
<li>The Open Days are preceded by 2 days of optional training sessions for experts! We propose 3 different training sessions, 2 days each.</li>
|
||||
<li>The whole event is open to all public! We ask a participation fee of 49.50€ for the costs for the 3 days (morning coffee, coffee breaks, drinks, sandwiches for lunch and the surprising beer party of Wednesday evening) but it's optional. For those who do not want to contribute, there is a free ticket, therefore, catering is not inclued.</li>
|
||||
<li>The plenary sessions in the morning will be shorter and we will give more time for thematical meetings, conferences, workshops and tutorial sessions in the afternoon.</li>
|
||||
</ul>
|
||||
<p> </p>
|
||||
<p><strong>Program:</strong></p>
|
||||
<p>Conferences, workshops and trainings will be organized in 6 rooms:</p>
|
||||
<ul>
|
||||
<li>2 technical rooms: one dedicated to advanced OpenERP developers, one for new developers.</li>
|
||||
<li>2 technical rooms: one dedicated to advanced OpenERP developers, one for new developers.</li>
|
||||
<li>1 business room: to discuss implementation methodologies, best sales practices, etc.</li>
|
||||
<li>1 workshop room: mainly for developers.</li>
|
||||
</ul>
|
||||
<p><em>If you wish to make a presentation, please send your topic proposal as soon as possible for approval to Mr. Famke Jenssens at ngh (a) yourcompany (dot) com. The presentations should be, for example, a presentation of a community module, a case study, methodology feedback, technical, etc. Each presentation must be in English.</em></p>
|
||||
<p> </p>
|
||||
<p><strong>Where to find us:</strong></p>
|
||||
<p>OpenElec Applications 23 Rockwell Lane, Los Angeles, CA 90001, United States</p>
|
||||
<p>For any additional information, please contact us at <a href="mailto:events@yourcompany.com">events@yourcompany.com</a>.</p>
|
||||
<p> </p>
|
||||
<p>Best regards,</p>
|
||||
<p>Luigi Roni, Senior Event Manager</p>
|
||||
<p> </p>
|
||||
<p align="RIGHT"><em>(OpenElec Applications reserves the right to cancel, re-name or re-locate<br/>the event or change the dates on which it is held.)</em></p>
|
||||
</div>
|
||||
]]></field>
|
||||
</record>
|
||||
|
||||
<record id="event_1" model="event.event">
|
||||
<field name="name">Opera of Verdi</field>
|
||||
<field eval="(DateTime.today()+ timedelta(days=1)).strftime('%Y-%m-%d 18:00:00')" name="date_begin"/>
|
||||
<field eval="(DateTime.today()+ timedelta(days=2)).strftime('%Y-%m-%d 21:00:00')" name="date_end"/>
|
||||
<field name="type" ref="event_type_1"/>
|
||||
<field name="register_min">50</field>
|
||||
<field name="name">Functional Webinar</field>
|
||||
<field eval="(DateTime.now() + timedelta(days=3)).strftime('%Y-%m-%d 7:00:00')" name="date_begin"/>
|
||||
<field eval="(DateTime.now() + timedelta(days=3)).strftime('%Y-%m-%d 11:00:00')" name="date_end"/>
|
||||
<field name="type" ref="event_type_0"/>
|
||||
<field name="address_id" ref="base.res_partner_5"/>
|
||||
<field name="register_max">350</field>
|
||||
<field name="description"><![CDATA[
|
||||
<div class="oe_structure">
|
||||
<center><strong>Functional Webinar</strong></center>
|
||||
<p> </p>
|
||||
<p>Webinars are online demonstrations where one of our team members explains the main features and benefits of our online offer through an online conference. We can therefore directly answer any questions you may have through a Q&A.</p>
|
||||
<p>Each session lasts approximately one hour and is free, we just ask you to register to receive access codes.</p>
|
||||
<p> </p>
|
||||
<p><strong>Objective:</strong></p>
|
||||
<p>These webinars allow companies interested in our software, to assess whether the solution meets their needs, and can adapt to the scope of their project.</p>
|
||||
<p>This webinar helps participants to:
|
||||
<ul>
|
||||
<li>Discover how to navigate in our software;</li>
|
||||
<li>View full flow: purchasing, sales, project management, accounting;</li>
|
||||
<li>Ask your questions to our expert;</li>
|
||||
<li>Assess whether your expectations are met;</li>
|
||||
</ul>
|
||||
<p> </p>
|
||||
<p>After registering, you will receive a link and password by email before the start of the session. If you have a problem to connect, please contact us at <a href="mailto:events@yourcompany.com">events@yourcompany.com</a>.</p>
|
||||
<p> </p>
|
||||
<p>We are looking forward to meeting you online,</p>
|
||||
<p>Best regards,</p>
|
||||
<p>Luigi Roni, Senior Event Manager</p>
|
||||
<p> </p>
|
||||
<p align="RIGHT"><em>(YourCompany reserves the right to cancel, re-name or re-locate<br/>the event or change the dates on which it is held.)</em></p>
|
||||
</div>
|
||||
]]></field>
|
||||
</record>
|
||||
|
||||
<record id="event_2" model="event.event">
|
||||
<field name="name">Conference on ERP Business</field>
|
||||
<field eval="(DateTime.today()+ timedelta(days=2)).strftime('%Y-%m-%d 14:00:00')" name="date_begin"/>
|
||||
<field eval="(DateTime.today()+ timedelta(days=2)).strftime('%Y-%m-%d 16:30:00')" name="date_end"/>
|
||||
<field name="name">Conference on Business Applications</field>
|
||||
<field eval="(DateTime.today()+ timedelta(days=5)).strftime('%Y-%m-%d 7:00:00')" name="date_begin"/>
|
||||
<field eval="(DateTime.today()+ timedelta(days=5)).strftime('%Y-%m-%d 16:30:00')" name="date_end"/>
|
||||
<field name="type" ref="event_type_2"/>
|
||||
<field name="address_id" ref="base.res_partner_14"/>
|
||||
<field name="register_max">200</field>
|
||||
<field name="description"><![CDATA[
|
||||
<div class="oe_structure">
|
||||
<center><strong>Conference on Business Applications</strong></center>
|
||||
<p> </p>
|
||||
<p> During this conference, our team will give a detailed overview of our business applications. You’ll know all the benefits of using it.</p>
|
||||
<p> </p>
|
||||
<p><strong>Objectives:</strong></p>
|
||||
<p>Having attended this conference, participants should be able to:</p>
|
||||
<ul>
|
||||
<li>Understand the various modules;</li>
|
||||
<li>Functional flow of the main applications;</li>
|
||||
</ul>
|
||||
<p> </p>
|
||||
<p><strong>Program:</strong></p>
|
||||
<ul>
|
||||
<li>Introduction, CRM, Sales Management</li>
|
||||
<li>Purchase, Sales & Purchase management, Financial accounting.</li>
|
||||
<li>Project management, Human resources, Contract management.</li>
|
||||
<li>Warehouse management, Manufacturing (MRP) & Sales, Import/Export.</li>
|
||||
<li>Point of Sale (POS), Introduction to report customization.</li>
|
||||
</ul>
|
||||
<p> </p>
|
||||
<p><strong>Where to find us:</strong></p>
|
||||
<p>Chamber Works 60, Rosewood Court Detroit, MI 48212 (United States)</p>
|
||||
<p>For any additional information, please contact us at <a href="mailto:events@openerp.com">events@openerp.com</a>.</p>
|
||||
<p> </p>
|
||||
<p>Best regards,</p>
|
||||
<p>Luigi Roni, Senior Event Manager</p>
|
||||
<p> </p>
|
||||
<p align="RIGHT"><em>(Chamber Works reserves the right to cancel, re-name or re-locate<br/>the event or change the dates on which it is held.)</em></p>
|
||||
</div>
|
||||
]]></field>
|
||||
</record>
|
||||
<function model="event.event" name="button_confirm" eval="[ref('event_2')]"/>
|
||||
|
||||
<record id="event_3" model="event.event">
|
||||
<field name="name">Technical Training</field>
|
||||
<field eval="(DateTime.now() + timedelta(15)).strftime('%Y-%m-%d 7:00:00')" name="date_begin"/>
|
||||
<field eval="(DateTime.now() + timedelta(20)).strftime('%Y-%m-%d 16:00:00')" name="date_end"/>
|
||||
<field name="type" ref="event_type_4"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="address_id" ref="base.res_partner_2"/>
|
||||
<field name="organizer_id" ref="base.res_partner_address_4"/>
|
||||
<field name="description"><![CDATA[
|
||||
<div class="oe_structure">
|
||||
<center><strong>5-days Technical Training</strong></center>
|
||||
<p> </p>
|
||||
<p><strong>Course summary:</strong></p>
|
||||
<p>This course is dedicated to partners, integrators and developers who need to grasp knowledge of the business applications development process. This course is for new developers or for IT professionals eager to learn more about technical aspects.</p>
|
||||
<p> </p>
|
||||
<p><strong>Objectives:</strong></p>
|
||||
<p>Having attended this course, participants should be able to:</p>
|
||||
<ul>
|
||||
<li>Understand the development concepts and architecture;</li>
|
||||
<li>Install and administer your own server;</li>
|
||||
<li>Develop a new module for a particular application.</li>
|
||||
</ul>
|
||||
<p> </p>
|
||||
<p><strong>Our prices include:</strong></p>
|
||||
<ul>
|
||||
<li>drinks and lunch;</li>
|
||||
<li>training material.</li>
|
||||
</ul>
|
||||
<p> </p>
|
||||
<p><strong>Requirements:</strong></p>
|
||||
<ul>
|
||||
<li>Bring your own laptop.</li>
|
||||
<li>Participants are expected to have some knowledge in programming. A basic knowledge of the Python programming is recommended.</li>
|
||||
<li>Participants preferably have a functional knowledge of our software (see Functional Training).</li>
|
||||
</ul>
|
||||
<p> </p>
|
||||
<p>For more information on the program, please explore <a href="http://www.openerp.com/services/technical-training">http://www.openerp.com/services/technical-training</a>.</p>
|
||||
<p>If you have a question<strong> concerning the content of the training</strong>, please contact <a href="mailto:events@yourcompany.com">events@yourcompany.com</a>.</p>
|
||||
<p> </p>
|
||||
<p><strong>Where to find us:</strong></p>
|
||||
<p>Chaussée de Namur 69, 1300 Wavre, Belgium</p>
|
||||
<p>More information about our Headquarter office (directions, transports, parking, hotels, ...), please have a look at <a href="http://bit.ly/VD8J67">http://bit.ly/VD8J67.</a></p>
|
||||
<p> </p>
|
||||
<p><strong>Cancellation Policy: </strong></p>
|
||||
<p>The organization of the training session has related costs. Due to these costs, cancellations made less than 2 weeks (14 calendar days) prior to the start of the training session is a subject to a fee. This fee can be up to a maximum of 1000€ per cancellation request.</p>
|
||||
<p>We strongly recommend to book your flight tickets and/or hotel reservations 2 weeks prior to the training. If the training is cancelled 2 weeks in advance, you'll be notified by email.</p>
|
||||
<div> </div>
|
||||
<p>For any additional information, please contact us at <a href="mailto:events@openerp.com">events@openerp.com</a>.</p>
|
||||
<p> </p>
|
||||
<p>Best regards,</p>
|
||||
<p>Luigi Roni, Senior Event Manager</p>
|
||||
<p> </p>
|
||||
<p align="RIGHT"><em>(YourCompany reserves the right to cancel, re-name or re-locate<br/>the event or change the dates on which it is held.)</em></p>
|
||||
</div>
|
||||
]]></field>
|
||||
</record>
|
||||
<function model="event.event" name="button_confirm" eval="[ref('event_0')]"/>
|
||||
<function model="event.event" name="button_confirm" eval="[ref('event_1')]"/>
|
||||
<function model="event.event" name="button_confirm" eval="[ref('event_2')]"/>
|
||||
|
||||
<!-- Demo data for Event Registration-->
|
||||
|
|
|
@ -91,14 +91,6 @@
|
|||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Event Details" groups="base.group_no_one">
|
||||
<group colspan="4">
|
||||
<field name="reply_to"/>
|
||||
<field name="email_registration_id"/>
|
||||
<field name="email_confirmation_id"/>
|
||||
</group>
|
||||
<field name="note" nolabel="1" placeholder="Event Description..."/>
|
||||
</page>
|
||||
<page string="Registrations">
|
||||
<group>
|
||||
<group>
|
||||
|
@ -149,6 +141,16 @@
|
|||
</form>
|
||||
</field>
|
||||
</page>
|
||||
<page string="Description">
|
||||
<field name="description" nolabel="1" placeholder="Event Description..."/>
|
||||
</page>
|
||||
<page string='Event Details' groups="base.group_no_one">
|
||||
<group colspan="4">
|
||||
<field name="reply_to"/>
|
||||
<field name="email_registration_id"/>
|
||||
<field name="email_confirmation_id"/>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -117,10 +117,8 @@ class event_event(osv.osv):
|
|||
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"),
|
||||
'organizer_id': fields.many2one('res.partner', "Organizer"),
|
||||
'phone': fields.related('organizer_id', 'phone', type='char', string='Phone'),
|
||||
'email': fields.related('organizer_id', 'email', type='char', string='Email'),
|
||||
'register_max': fields.function(_get_register_max,
|
||||
|
|
|
@ -245,7 +245,7 @@ FaceTime HD Camera, 1.2 MP Photos</field>
|
|||
<field name="name">Bose Mini Bluetooth Speaker</field>
|
||||
<field name="default_code">PC-DEM</field>
|
||||
<field name="categ_id" ref="product_category_4"/>
|
||||
<field name="public_categ_id" ref="services"/>
|
||||
<field name="public_categ_id" ref="Speakers"/>
|
||||
<field name="standard_price">600.0</field>
|
||||
<field name="list_price">900.0</field>
|
||||
<field name="type">consu</field>
|
||||
|
@ -311,7 +311,8 @@ FaceTime HD Camera, 1.2 MP Photos</field>
|
|||
<field name="uom_id" ref="product_uom_unit"/>
|
||||
<field name="uom_po_id" ref="product_uom_unit"/>
|
||||
</record>
|
||||
<record id="product_product_11" model="product.product">
|
||||
|
||||
<record id="product_product_11_temp" model="product.template">
|
||||
<field name="name">iPod</field>
|
||||
<field name="default_code">M-Las</field>
|
||||
<field name="categ_id" ref="product_category_8"/>
|
||||
|
@ -322,6 +323,24 @@ FaceTime HD Camera, 1.2 MP Photos</field>
|
|||
<field name="uom_id" ref="product_uom_unit"/>
|
||||
<field name="uom_po_id" ref="product_uom_unit"/>
|
||||
</record>
|
||||
<record id="product_product_11" model="product.product">
|
||||
<field name="name">iPod</field>
|
||||
<field name="default_code">M-Las</field>
|
||||
<field name="categ_id" ref="product_category_8"/>
|
||||
<field name="public_categ_id" ref="Keyboard_Mouse"/>
|
||||
<field name="standard_price">14</field>
|
||||
<field name="list_price">16.50</field>
|
||||
<field name="type">consu</field>
|
||||
<field name="uom_id" ref="product_uom_unit"/>
|
||||
<field name="uom_po_id" ref="product_uom_unit"/>
|
||||
<field name="product_tmpl_id" ref="product_product_11_temp"/>
|
||||
</record>
|
||||
<record id="product_product_11_b" model="product.product">
|
||||
<field name="variants">32 Gb</field>
|
||||
<field name="price_extra">12</field>
|
||||
<field name="product_tmpl_id" ref="product_product_11_temp"/>
|
||||
</record>
|
||||
|
||||
<record id="product_product_12" model="product.product">
|
||||
<field name="name">Mouse, Wireless</field>
|
||||
<field name="default_code">M-Wir</field>
|
||||
|
@ -1023,12 +1042,12 @@ QWERTY keyboard</field>
|
|||
<field name="min_qty">1</field>
|
||||
</record>
|
||||
|
||||
<record id="product_supplierinfo_38" model="product.supplierinfo">
|
||||
<!--record id="product_supplierinfo_38" model="product.supplierinfo">
|
||||
<field name="product_id" ref="product_product_48"/>
|
||||
<field name="name" ref="base.res_partner_8"/>
|
||||
<field name="delay">7</field>
|
||||
<field name="min_qty">1</field>
|
||||
</record>
|
||||
</record-->
|
||||
|
||||
<record id="product_supplierinfo_39" model="product.supplierinfo">
|
||||
<field name="product_id" ref="product_product_18"/>
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -220,12 +220,16 @@ class Website(openerp.addons.web.controllers.main.Home):
|
|||
hashed_session = hashlib.md5(request.session_id).hexdigest()
|
||||
retag = hashed_session
|
||||
try:
|
||||
ids = Model.read(request.cr, request.uid, [('id', '=', id)], request.context)
|
||||
if not ids:
|
||||
id = Model.read(request.cr, openerp.SUPERUSER_ID, [('id', '=', id), ('website_published', '=', True)], request.context)[0]
|
||||
|
||||
if etag:
|
||||
date = Model.read(request.cr, request.uid, [id], [last_update], request.context)[0].get(last_update)
|
||||
date = Model.read(request.cr, openerp.SUPERUSER_ID, [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]
|
||||
res = Model.read(request.cr, openerp.SUPERUSER_ID, [id], [last_update, field], request.context)[0]
|
||||
retag = hashlib.md5(res.get(last_update)).hexdigest()
|
||||
image_base64 = res.get(field)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -228,7 +229,7 @@ footer {
|
|||
}
|
||||
|
||||
.oe_structure.oe_empty:empty:before, [data-oe-type=html]:empty:before, .oe_structure.oe_empty > .oe_drop_zone.oe_insert:only-child:before, [data-oe-type=html] > .oe_drop_zone.oe_insert:only-child:before {
|
||||
content: "Drag Building Blocks Here";
|
||||
content: "Click Edit To Create Content";
|
||||
text-align: center;
|
||||
display: block;
|
||||
padding-top: 100px;
|
||||
|
@ -237,6 +238,10 @@ footer {
|
|||
font-size: 24px;
|
||||
}
|
||||
|
||||
.oe_structure.oe_editable.oe_empty:empty:before, .oe_editable[data-oe-type=html]:empty:before, .oe_structure.oe_editable.oe_empty > .oe_drop_zone.oe_insert:only-child:before, [data-oe-type=html] > .oe_drop_zone.oe_insert:only-child:before {
|
||||
content: "Drag Building Blocks Here";
|
||||
}
|
||||
|
||||
/* ---- HACK FOR COVERING UP CK EDITOR BOGUS P INSERTION --- */
|
||||
.navbar .nav > li > p {
|
||||
margin-bottom: 0px;
|
||||
|
@ -370,17 +375,21 @@ a[data-publish][data-publish='on']:hover .css_published {
|
|||
display: none;
|
||||
}
|
||||
|
||||
[data-publish='off']:not(a) > :not([data-publish]) {
|
||||
.unpublish {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
[data-publish='off']:not(a) > :not(.js_publish) {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
[data-publish]:not(a) {
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
/*&:hover > [data-publish] */
|
||||
/*&:hover .js_publish */
|
||||
/* display: block */
|
||||
}
|
||||
[data-publish]:not(a) > [data-publish] {
|
||||
[data-publish]:not(a) .js_publish {
|
||||
position: absolute;
|
||||
right: -6px;
|
||||
top: -10px;
|
||||
|
|
|
@ -155,7 +155,7 @@ footer
|
|||
position: static
|
||||
|
||||
.oe_structure.oe_empty:empty:before, [data-oe-type=html]:empty:before, .oe_structure.oe_empty > .oe_drop_zone.oe_insert:only-child:before, [data-oe-type=html] > .oe_drop_zone.oe_insert:only-child:before
|
||||
content: 'Drag Building Blocks Here'
|
||||
content: 'Click Edit To Create Content'
|
||||
text-align: center
|
||||
display: block
|
||||
padding-top: 100px
|
||||
|
@ -163,6 +163,9 @@ footer
|
|||
color: grey
|
||||
font-size: 24px
|
||||
|
||||
.oe_structure.oe_editable.oe_empty:empty:before, .oe_editable[data-oe-type=html]:empty:before, .oe_structure.oe_editable.oe_empty > .oe_drop_zone.oe_insert:only-child:before, [data-oe-type=html] > .oe_drop_zone.oe_insert:only-child:before
|
||||
content: 'Drag Building Blocks Here'
|
||||
|
||||
/* ---- HACK FOR COVERING UP CK EDITOR BOGUS P INSERTION --- */
|
||||
|
||||
.navbar .nav > li > p
|
||||
|
@ -282,16 +285,18 @@ a[data-publish]
|
|||
&:hover .css_published
|
||||
display: none
|
||||
|
||||
.unpublish
|
||||
opacity: 0.5
|
||||
[data-publish='off']:not(a)
|
||||
>:not([data-publish])
|
||||
>:not(.js_publish)
|
||||
opacity: 0.5
|
||||
[data-publish]:not(a)
|
||||
position: relative
|
||||
overflow: visible
|
||||
>[data-publish]
|
||||
.js_publish
|
||||
position: absolute
|
||||
right: -6px
|
||||
top: -10px
|
||||
display: none
|
||||
/*&:hover > [data-publish]*/
|
||||
/*&:hover .js_publish*/
|
||||
/* display: block*/
|
||||
|
|
|
@ -321,16 +321,16 @@
|
|||
var self = this;
|
||||
// create a single editor for the whole page
|
||||
var root = document.getElementById('wrapwrap');
|
||||
$(root).attr('data-cke-editable', 'true')
|
||||
.on('dragstart', 'img', function (e) {
|
||||
$(root).on('dragstart', 'img', function (e) {
|
||||
e.preventDefault();
|
||||
});
|
||||
this.editor = CKEDITOR.inline(root, self._config());
|
||||
this.editor.on('instanceReady', function () {
|
||||
var editor = this.editor = CKEDITOR.inline(root, self._config());
|
||||
editor.on('instanceReady', function () {
|
||||
editor.setReadOnly(false);
|
||||
// ckeditor set root to editable, disable it (only inner
|
||||
// sections are editable)
|
||||
// FIXME: are there cases where the whole editor is editable?
|
||||
root.contentEditable = false;
|
||||
editor.editable().setReadOnly(true);
|
||||
|
||||
self.setup_editables(root);
|
||||
|
||||
|
@ -496,11 +496,15 @@
|
|||
this.changed($target.find('.url-source'));
|
||||
},
|
||||
'click button.remove': 'remove_link',
|
||||
'change input#link-text': function (e) {
|
||||
this.text = $(e.target).val()
|
||||
},
|
||||
}),
|
||||
init: function (editor) {
|
||||
this._super(editor);
|
||||
// url -> name mapping for existing pages
|
||||
this.pages = Object.create(null);
|
||||
this.text = null;
|
||||
},
|
||||
start: function () {
|
||||
var element;
|
||||
|
@ -554,13 +558,15 @@
|
|||
if (this.element) {
|
||||
this.element.setAttributes(attributes);
|
||||
this.element.removeAttributes(to_remove);
|
||||
if (this.text) { this.element.setText(this.text); }
|
||||
} else {
|
||||
var selection = this.editor.getSelection();
|
||||
var range = selection.getRanges(true)[0];
|
||||
|
||||
if (range.collapsed) {
|
||||
//noinspection JSPotentiallyInvalidConstructorUsage
|
||||
var text = new CKEDITOR.dom.text(label || url);
|
||||
var text = new CKEDITOR.dom.text(
|
||||
this.text || label || url);
|
||||
range.insertNode(text);
|
||||
range.selectNodeContents(text);
|
||||
}
|
||||
|
@ -628,6 +634,7 @@
|
|||
|
||||
this.changed($control);
|
||||
|
||||
this.$('input#link-text').val(this.element.getText());
|
||||
this.$('input.window-new').prop(
|
||||
'checked', this.element.getAttribute('target') === '_blank');
|
||||
},
|
||||
|
|
|
@ -116,20 +116,18 @@
|
|||
|
||||
dom_ready.then(function () {
|
||||
/* ----- PUBLISHING STUFF ---- */
|
||||
$('[data-publish]:has([data-publish])').each(function () {
|
||||
var $pub = $("[data-publish]", this);
|
||||
if($pub.size())
|
||||
$(this).attr("data-publish", $pub.attr("data-publish"));
|
||||
else
|
||||
$(this).removeAttr("data-publish");
|
||||
$('[data-publish]:has(.js_publish)').each(function () {
|
||||
$(this).attr("data-publish", $(".js_publish li.active", this).size() ? "on" : 'off');
|
||||
});
|
||||
|
||||
$(document).on('click', '.js_publish', function (e) {
|
||||
e.preventDefault();
|
||||
var $data = $(":first", this).parents("[data-publish]");
|
||||
$data.attr("data-publish", $data.first().attr("data-publish") == 'off' ? 'on' : 'off');
|
||||
$.post('/website/publish', {'id': $(this).data('id'), 'object': $(this).data('object')}, function (result) {
|
||||
$data.attr("data-publish", +result ? 'on' : 'off');
|
||||
$(document).on('click', '.js_publish a.js_publish_btn', function (e) {
|
||||
var $li = $(this).parent("li");
|
||||
var $data = $li.parents(".js_publish:first");
|
||||
var publish = $li.hasClass("active");
|
||||
$li.toggleClass("active");
|
||||
$.post('/website/publish', {'id': $data.data('id'), 'object': $data.data('object')}, function (result) {
|
||||
$li.toggleClass("active", !!+result);
|
||||
$li.parents("[data-publish]").attr("data-publish", +result ? 'on' : 'off');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1027,7 +1027,6 @@
|
|||
this.set_options_background();
|
||||
this.set_options_style();
|
||||
}
|
||||
console.log(nb);
|
||||
if (nb <= 1) {
|
||||
this.$target.find('.carousel-control').addClass("hidden");
|
||||
}
|
||||
|
@ -1159,7 +1158,12 @@
|
|||
}
|
||||
});
|
||||
|
||||
website.snippet.selector.push([ _.map([1,2,3,4,5,6,7,8,9,10,11,12], function (v) {return '.row > .col-md-'+v;}).join(","), 'colmd']);
|
||||
/*
|
||||
* data-snippet-id automatically setted
|
||||
* Don't need to add data-snippet-id="..." into the views
|
||||
*/
|
||||
|
||||
website.snippet.selector.push([".row > div[class*='col-md-']", 'colmd']);
|
||||
website.snippet.selector.push(['hr', 'hr']);
|
||||
|
||||
})();
|
||||
|
|
|
@ -83,6 +83,17 @@
|
|||
id="link-email" placeholder="you@yourwebsite.com"/>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label for="link-text" class="col-sm-2 control-label">
|
||||
Link text
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control"
|
||||
id="link-text"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</t>
|
||||
</t>
|
||||
|
|
|
@ -336,12 +336,15 @@
|
|||
</template>
|
||||
|
||||
<template id="publish">
|
||||
<a href="#" t-att-data-id="object.id" t-att-data-object="object._name" t-att-data-publish="object.id and object.website_published and 'on' or 'off'" class="pull-right js_publish" t-if="editable" t-ignore="true">
|
||||
<span t-attf-class="label label-success css_publish">Publish</span>
|
||||
<span t-attf-class="label label-danger css_unpublish">Unpublish</span>
|
||||
<span t-attf-class="label label-success css_published">Published</span>
|
||||
<span t-attf-class="label label-danger css_unpublished">Unpublished</span>
|
||||
</a>
|
||||
<t t-if="editable" t-ignore="true">
|
||||
<div class="dropdown js_publish pull-right" t-att-data-id="object.id" t-att-data-object="object._name">
|
||||
<a class="btn btn-default" id="dopprod" role="button" data-toggle="dropdown"> Manage <span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" role="menu" aria-labelledby="dopprod">
|
||||
<li t-att-class="object.id and object.website_published and 'active' or ''"><a href="#" class="js_publish_btn">Publish</a></li>
|
||||
<li><a t-att-href="'/admin/#model=%s&id=%s' % (object._name, object.id)">Manage Products</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="kanban">
|
||||
|
|
|
@ -95,10 +95,10 @@ class website(osv.osv):
|
|||
|
||||
qweb_context = request.context.copy()
|
||||
|
||||
if values is None:
|
||||
values = {}
|
||||
if values:
|
||||
qweb_context.update(values)
|
||||
|
||||
values.update(
|
||||
qweb_context.update(
|
||||
request=request,
|
||||
registry=request.registry,
|
||||
json=simplejson,
|
||||
|
@ -107,7 +107,6 @@ class website(osv.osv):
|
|||
user_id=user.browse(cr, openerp.SUPERUSER_ID, uid),
|
||||
)
|
||||
|
||||
qweb_context.update(values)
|
||||
context = {
|
||||
'inherit_branding': qweb_context.setdefault('editable', False),
|
||||
}
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
sass:
|
||||
sass --compass --trace -t expanded website_blog.sass website_blog.css
|
||||
sass --trace -t expanded website_blog.sass:website_blog.css
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
@import url(compass/css3.css);
|
||||
.css_website_mail .has-error {
|
||||
border-color: red;
|
||||
}
|
||||
|
@ -7,3 +8,16 @@
|
|||
.css_website_mail .css_nav_month:first-of-type {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.blog_content a.oe_mail_expand:after {
|
||||
content: " →";
|
||||
}
|
||||
.blog_content a.oe_mail_expand {
|
||||
font-weight: bold;
|
||||
display: block;
|
||||
}
|
||||
|
||||
p.post-meta {
|
||||
position: relative;
|
||||
top: -5px;
|
||||
}
|
||||
|
|
|
@ -7,3 +7,15 @@
|
|||
display: none
|
||||
&:first-of-type
|
||||
display: block
|
||||
|
||||
.blog_content
|
||||
a.oe_mail_expand:after
|
||||
content: " →"
|
||||
a.oe_mail_expand
|
||||
font-weight: bold
|
||||
display: block
|
||||
|
||||
p.post-meta
|
||||
position: relative
|
||||
top: -5px
|
||||
|
||||
|
|
|
@ -14,38 +14,49 @@
|
|||
|
||||
<!-- Blog Post Summary -->
|
||||
<template id="view_blog_post_short" name="Blog Post Short">
|
||||
<div class="media-body">
|
||||
<t t-call="website_mail.follow"><t t-set="object" t-value="blog_post"/></t>
|
||||
<t t-call="website.publish"><t t-set="object" t-value="blog_post"/></t>
|
||||
<small class="text-muted">
|
||||
<t t-field="blog_post.create_uid"/> on <t t-field="blog_post.create_date"/>
|
||||
</small>
|
||||
<h4 class="media-heading" ><a t-attf-href="/blog/#{blog_post.category_id.id}/#{blog_post.id}#comment" t-field="blog_post.name"></a></h4>
|
||||
<div class="media">
|
||||
<div t-field="blog_post.shortened_content"/>
|
||||
<small class="pull-left muted text-right">
|
||||
<a t-if="len(blog_post.message_ids) <= 1" t-attf-href="/blog/#{blog_post.category_id.id}/#{blog_post.id}#comments"><t t-esc="len(blog_post.message_ids)"/> Comment</a>
|
||||
<a t-if="len(blog_post.message_ids) > 1" t-attf-href="/blog/#{blog_post.category_id.id}/#{blog_post.id}#comments"><t t-esc="len(blog_post.message_ids)"/> Comments</a>
|
||||
</small>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-center">
|
||||
<a t-attf-href="/blog/#{blog_post.category_id.id}/#{blog_post.id}#comment" t-field="blog_post.name"></a>
|
||||
</h2>
|
||||
<p class="post-meta text-muted text-center">
|
||||
<span class="icon-calendar"> <t t-field="blog_post.create_date"/></span> &nbsp;
|
||||
<span class="icon-user"> By <t t-field="blog_post.create_uid"/></span> &nbsp;
|
||||
<span t-if="len(blog_post.message_ids) > 0" class="icon-comment"> With
|
||||
<a t-if="len(blog_post.message_ids) <= 1" t-attf-href="/blog/#{blog_post.category_id.id}/#{blog_post.id}#comments"><t t-esc="len(blog_post.message_ids)"/> comment</a>
|
||||
<a t-if="len(blog_post.message_ids) > 1" t-attf-href="/blog/#{blog_post.category_id.id}/#{blog_post.id}#comments"><t t-esc="len(blog_post.message_ids)"/> comments</a>
|
||||
</span>
|
||||
</p>
|
||||
<div t-field="blog_post.shortened_content" class="blog_content"/>
|
||||
<hr/>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Blog Post Complete -->
|
||||
<template id="view_blog_post" name="Blog Post">
|
||||
<div class="media">
|
||||
<div class="media-body">
|
||||
<div>
|
||||
<t t-call="website_mail.follow"><t t-set="object" t-value="blog_post"/></t>
|
||||
<t t-call="website.publish"><t t-set="object" t-value="blog_post"/></t>
|
||||
<small class="text-muted">
|
||||
<t t-field="blog_post.create_uid"/> on <t t-field="blog_post.create_date"/>
|
||||
</small>
|
||||
<h3 t-field="blog_post.name"/>
|
||||
</div><div class="clearfix"/>
|
||||
|
||||
<h2 class="text-center" t-field="blog_post.name"/>
|
||||
<p class="post-meta text-muted text-center">
|
||||
<span class="icon-calendar"> <t t-field="blog_post.create_date"/></span> &nbsp;
|
||||
<span class="icon-user"> By <t t-field="blog_post.create_uid"/></span> &nbsp;
|
||||
<span t-if="len(blog_post.message_ids) > 0" class="icon-comment"> With
|
||||
<a t-if="len(blog_post.message_ids) <= 1" t-attf-href="#comments"><t t-esc="len(blog_post.message_ids)"/> comment</a>
|
||||
<a t-if="len(blog_post.message_ids) > 1" t-attf-href="#comments"><t t-esc="len(blog_post.message_ids)"/> comments</a>
|
||||
</span>
|
||||
</p>
|
||||
<p class="post-meta text-muted text-center" t-if="len(blog_post.tag_ids)">
|
||||
<span class="icon-tags"/>
|
||||
<t t-foreach="blog_post.tag_ids" t-as="tag">
|
||||
<a class="btn btn-sm btn-info" href="/blog/tag/#{tag.id}"><t t-esc="tag.name"/></a>
|
||||
<a href="/blog/tag/#{tag.id}" t-esc="tag.name"/> &nbsp;
|
||||
</t>
|
||||
<div t-field="blog_post.content"/>
|
||||
</div>
|
||||
</p>
|
||||
|
||||
<div t-field="blog_post.content" class="mt32"/>
|
||||
|
||||
<hr/>
|
||||
<div class="clearfix">
|
||||
<div class="pull-right text-right">
|
||||
|
@ -77,7 +88,6 @@
|
|||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Page -->
|
||||
|
@ -86,42 +96,29 @@
|
|||
<t t-set="head">
|
||||
<script type="text/javascript" src="/website_blog/static/src/js/website_blog.js"></script>
|
||||
<link rel='stylesheet' href='/website_blog/static/src/css/website_blog.css'/>
|
||||
<t t-raw="head or ''"/>
|
||||
</t>
|
||||
<t t-set="title">Blog</t>
|
||||
<div id="wrap">
|
||||
<div class="container mt48 js_website_blog">
|
||||
<div class="container mt16 js_website_blog">
|
||||
<div class="row">
|
||||
<div class="col-md-3" id="left_column">
|
||||
<h4>Categories</h4>
|
||||
<ul class="nav nav-pills nav-stacked">
|
||||
<t t-foreach="categories" t-as="nav_category">
|
||||
<li t-att-class="'active' if category and category.id == nav_category.id else ''">
|
||||
<a t-attf-href="/blog/#{nav_category.id}">
|
||||
<t t-field="nav_category.name"/>
|
||||
</a>
|
||||
</li>
|
||||
</t>
|
||||
</ul>
|
||||
<t t-if="category">
|
||||
<a t-if="editable" t-attf-href="/blog/#{category.id}/new" class="btn btn-default">New Blog Post</a>
|
||||
<t t-call="website_mail.follow"><t t-set="object" t-value="category"/></t>
|
||||
</t>
|
||||
</div>
|
||||
<div class="col-md-9" t-if="blog_post">
|
||||
<t t-call="website_blog.view_blog_post"><t t-set="blog_post" t-value="blog_post"/></t>
|
||||
<div class="col-sm-3 hidden-xs" id="left_column">
|
||||
</div>
|
||||
|
||||
<div class="col-md-9" t-if="not blog_post and blog_posts">
|
||||
<ul class="media-list">
|
||||
<li t-foreach="blog_posts" t-as="blog_post" data-publish="">
|
||||
<div class="col-lg-8 col-sm-9 col-lg-offset-1" t-if="not blog_post and blog_posts">
|
||||
<t t-if="category">
|
||||
<a t-if="editable" t-attf-href="/blog/#{category.id}/new" class="btn btn-default">New Blog Post</a>
|
||||
</t>
|
||||
<t t-foreach="blog_posts" t-as="blog_post" data-publish="">
|
||||
<t t-call="website_blog.view_blog_post_short"/>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="text-center">
|
||||
<t t-call="website.pager"/>
|
||||
</t>
|
||||
<div class="text-center" t-call="website.pager"/>
|
||||
</div>
|
||||
<div class="col-md-9 col-lg-8 col-lg-offset-1" t-if="blog_post">
|
||||
<t t-call="website_blog.view_blog_post">
|
||||
<t t-set="blog_post" t-value="blog_post"/>
|
||||
</t>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -147,5 +144,49 @@
|
|||
</ul>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="blog_aboutus" inherit_option_id="website_blog.index" name="About">
|
||||
<xpath expr="//div[@id='left_column']" position="inside">
|
||||
<h4>About us</h4>
|
||||
<p>
|
||||
Write here a small text for <b>new visitors</b> finding your website
|
||||
through your <b>blog entries</b>, referenced in Google.
|
||||
</p>
|
||||
<div>
|
||||
<button src="/contactus" class="btn btn-primary mb32">Contact us</button>
|
||||
</div>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="blog_followus" inherit_option_id="website_blog.index" name="Follow us">
|
||||
<xpath expr="//div[@id='left_column']" position="inside">
|
||||
<h4>Follow us</h4>
|
||||
<p class="text-muted">
|
||||
Why should visitor follow you?
|
||||
</p>
|
||||
<t t-call="website_mail.follow"><t t-set="object" t-value="category"/></t>
|
||||
<div class="mb16">
|
||||
<a href="http://facebook.com/openerp"><span class="icon-facebook"/></a>
|
||||
<a href="http://twitter.com/openerp"><span class="icon-twitter"/></a>
|
||||
<a href="http://www.linkedin.com/groups/OpenERP-165657"><span class="icon-linkedin"/></a>
|
||||
</div>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="blog_categories" inherit_option_id="website_blog.index" name="Blogs">
|
||||
<xpath expr="//div[@id='left_column']" position="inside">
|
||||
<h4>Blogs</h4>
|
||||
<ul class="nav nav-pills nav-stacked mb32">
|
||||
<t t-foreach="categories" t-as="nav_category">
|
||||
<li t-att-class="'active' if category and category.id == nav_category.id else ''">
|
||||
<a t-attf-href="/blog/#{nav_category.id}">
|
||||
<t t-field="nav_category.name"/>
|
||||
</a>
|
||||
</li>
|
||||
</t>
|
||||
</ul>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -107,6 +107,7 @@ class BlogPost(osv.Model):
|
|||
'website_published_datetime': fields.datetime(
|
||||
'Publish Date'
|
||||
),
|
||||
# TDE TODO FIXME: when website_mail/mail_thread.py inheritance work -> this field won't be necessary
|
||||
'website_message_ids': fields.one2many(
|
||||
'mail.message', 'res_id',
|
||||
domain=lambda self: [
|
||||
|
|
|
@ -1,2 +1,23 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2013-Today OpenERP SA (<http://www.openerp.com>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import controllers
|
||||
import event
|
|
@ -1,15 +1,17 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
{
|
||||
'name': 'Online Events',
|
||||
'category': 'Website',
|
||||
'summary': 'Schedule, Promote and Sell Events',
|
||||
'version': '1.0',
|
||||
'description': """
|
||||
OpenERP Blog
|
||||
============
|
||||
Online Events
|
||||
=============
|
||||
|
||||
""",
|
||||
'author': 'OpenERP SA',
|
||||
'depends': ['website', 'event_sale', 'website_sale'],
|
||||
'depends': ['website', 'website_mail', 'event_sale', 'website_sale'],
|
||||
'data': [
|
||||
'event_data.xml',
|
||||
'views/website_event.xml',
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import main
|
||||
|
|
|
@ -1,4 +1,23 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2013-Today OpenERP SA (<http://www.openerp.com>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp.addons.web import http
|
||||
|
@ -18,7 +37,10 @@ class website_event(http.Controller):
|
|||
|
||||
@website.route(['/event', '/event/page/<int:page>/'], type='http', auth="public")
|
||||
def events(self, page=1, **searches):
|
||||
cr, uid, context = request.cr, request.uid, request.context
|
||||
event_obj = request.registry['event.event']
|
||||
type_obj = request.registry['event.type']
|
||||
country_obj = request.registry['res.country']
|
||||
|
||||
searches.setdefault('date', 'all')
|
||||
searches.setdefault('type', 'all')
|
||||
|
@ -54,13 +76,19 @@ class website_event(http.Controller):
|
|||
]
|
||||
|
||||
# search domains
|
||||
current_date = dates[0][1]
|
||||
current_type = None
|
||||
current_country = None
|
||||
for date in dates:
|
||||
if searches.get("date") == date[0]:
|
||||
if searches["date"] == date[0]:
|
||||
domain_search["date"] = date[2]
|
||||
if searches.get("type", "all") != 'all':
|
||||
domain_search["type"] = [("type", "=", int(searches.get("type")))]
|
||||
if searches.get("country", "all") != 'all':
|
||||
domain_search["country"] = [("country_id", "=", int(searches.get("country")))]
|
||||
current_date = date[1]
|
||||
if searches["type"] != 'all':
|
||||
current_type = type_obj.browse(cr, uid, int(searches['type']), context=context)
|
||||
domain_search["type"] = [("type", "=", int(searches["type"]))]
|
||||
if searches["country"] != 'all':
|
||||
current_country = country_obj.browse(cr, uid, int(searches['country']), context=context)
|
||||
domain_search["country"] = [("country_id", "=", int(searches["country"]))]
|
||||
|
||||
def dom_without(without):
|
||||
domain = SUPERUSER_ID != request.uid and [('website_published', '=', True)] or [(1, "=", 1)]
|
||||
|
@ -109,6 +137,9 @@ class website_event(http.Controller):
|
|||
context=request.context)
|
||||
|
||||
values = {
|
||||
'current_date': current_date,
|
||||
'current_country': current_country,
|
||||
'current_type': current_type,
|
||||
'event_ids': events_ids,
|
||||
'dates': dates,
|
||||
'types': types,
|
||||
|
@ -126,11 +157,9 @@ class website_event(http.Controller):
|
|||
values = {
|
||||
'event_id': event_obj.browse(request.cr, request.uid, event_id,
|
||||
dict(request.context, show_address=1)),
|
||||
'message_ids': event_obj.browse(request.cr, request.uid, event_id, request.context).message_ids,
|
||||
'subscribe': post.get('subscribe'),
|
||||
'range': range
|
||||
}
|
||||
return request.website.render("website_event.detail", values)
|
||||
return request.website.render("website_event.event_description_full", values)
|
||||
|
||||
@website.route(['/event/<int:event_id>/add_cart'], type='http', auth="public")
|
||||
def add_cart(self, event_id=None, **post):
|
||||
|
@ -182,50 +211,3 @@ class website_event(http.Controller):
|
|||
if not _values:
|
||||
return werkzeug.utils.redirect("/event/%s/" % event_id)
|
||||
return werkzeug.utils.redirect("/shop/checkout")
|
||||
|
||||
@website.route(['/event/<int:event_id>/subscribe'], type='http', auth="public")
|
||||
def subscribe(self, event_id=None, **post):
|
||||
partner_obj = request.registry['res.partner']
|
||||
event_obj = request.registry['event.event']
|
||||
user_obj = request.registry['res.users']
|
||||
|
||||
if event_id and 'subscribe' in post and (post.get('email') or not request.context['is_public_user']):
|
||||
if request.context['is_public_user']:
|
||||
partner_ids = partner_obj.search(
|
||||
request.cr, SUPERUSER_ID, [("email", "=", post.get('email'))],
|
||||
context=request.context)
|
||||
if not partner_ids:
|
||||
partner_data = {
|
||||
"email": post.get('email'),
|
||||
"name": "Subscribe: %s" % post.get('email')
|
||||
}
|
||||
partner_ids = [partner_obj.create(
|
||||
request.cr, SUPERUSER_ID, partner_data, context=request.context)]
|
||||
else:
|
||||
partner_ids = [user_obj.browse(
|
||||
request.cr, request.uid, request.uid,
|
||||
context=request.context).partner_id.id]
|
||||
event_obj.check_access_rule(request.cr, request.uid, [event_id],
|
||||
'read', request.context)
|
||||
event_obj.message_subscribe(request.cr, SUPERUSER_ID, [event_id],
|
||||
partner_ids, request.context)
|
||||
|
||||
return self.event(event_id=event_id, subscribe=post.get('email'))
|
||||
|
||||
@website.route(['/event/<int:event_id>/unsubscribe'], type='http', auth="public")
|
||||
def unsubscribe(self, event_id=None, **post):
|
||||
partner_obj = request.registry['res.partner']
|
||||
event_obj = request.registry['event.event']
|
||||
user_obj = request.registry['res.users']
|
||||
|
||||
if event_id and 'unsubscribe' in post and (post.get('email') or not request.context['is_public_user']):
|
||||
if request.context['is_public_user']:
|
||||
partner_ids = partner_obj.search(
|
||||
request.cr, SUPERUSER_ID, [("email", "=", post.get('email'))],
|
||||
context=request.context)
|
||||
else:
|
||||
partner_ids = [user_obj.browse(request.cr, request.uid, request.uid, request.context).partner_id.id]
|
||||
event_obj.check_access_rule(request.cr, request.uid, [event_id], 'read', request.context)
|
||||
event_obj.message_unsubscribe(request.cr, SUPERUSER_ID, [event_id], partner_ids, request.context)
|
||||
|
||||
return self.event(event_id=event_id, subscribe=None)
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
.. _changelog:
|
||||
|
||||
Changelog
|
||||
=========
|
||||
|
||||
`trunk (saas-3)`
|
||||
----------------
|
||||
|
||||
- created ``website_event``
|
|
@ -0,0 +1,10 @@
|
|||
Website Event Module documentation topics
|
||||
'''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
Changelog
|
||||
'''''''''
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
changelog.rst
|
|
@ -1,8 +1,28 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2013-Today OpenERP SA (<http://www.openerp.com>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp.osv import osv, fields
|
||||
from openerp import SUPERUSER_ID
|
||||
|
||||
|
||||
# defined for access rules
|
||||
class product(osv.osv):
|
||||
_inherit = 'product.product'
|
||||
|
@ -15,7 +35,15 @@ class event(osv.osv):
|
|||
_inherit = 'event.event'
|
||||
_columns = {
|
||||
'website_published': fields.boolean('Available in the website'),
|
||||
'description_website': fields.html('Description for the website'),
|
||||
# TDE TODO FIXME: when website_mail/mail_thread.py inheritance work -> this field won't be necessary
|
||||
'website_message_ids': fields.one2many(
|
||||
'mail.message', 'res_id',
|
||||
domain=lambda self: [
|
||||
'&', ('model', '=', self._name), ('type', '=', 'comment')
|
||||
],
|
||||
string='Website Messages',
|
||||
help="Website communication history",
|
||||
),
|
||||
}
|
||||
|
||||
def google_map_img(self, cr, uid, ids, zoom=8, width=298, height=298, context=None):
|
||||
|
@ -28,6 +56,7 @@ class event(osv.osv):
|
|||
if partner.address_id:
|
||||
return self.browse(cr, SUPERUSER_ID, ids[0], context=context).address_id.google_map_link()
|
||||
|
||||
|
||||
class sale_order_line(osv.osv):
|
||||
_inherit = "sale.order.line"
|
||||
|
||||
|
|
|
@ -2,53 +2,20 @@
|
|||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="event_sale.event_technical_training" model="event.event">
|
||||
<record id="event.event_0" model="event.event">
|
||||
<field name="website_published">True</field>
|
||||
</record>
|
||||
|
||||
<record id="event.event_1" model="event.event">
|
||||
<field name="website_published">True</field>
|
||||
</record>
|
||||
|
||||
<record id="event.event_2" model="event.event">
|
||||
<field name="website_published">True</field>
|
||||
</record>
|
||||
|
||||
<record id="event.event_3" model="event.event">
|
||||
<field name="website_published">True</field>
|
||||
<field name="description_website"><![CDATA[
|
||||
<center><strong>OpenERP v.7 Technical Training in English (5 days)</strong></center>
|
||||
<p> </p>
|
||||
<p><strong>Course summary:</strong></p>
|
||||
<p>This course is dedicated to partners, integrators and developers who need to grasp knowledge of the OpenERP development process. This course is for new developers or for IT professionals eager to learn more about the OpenERP technical aspects.</p>
|
||||
<p> </p>
|
||||
<p><strong>Objectives:</strong></p>
|
||||
<p>Having attended this course, participants should be able to:</p>
|
||||
<ul>
|
||||
<li>Understand the development concepts and architecture;</li>
|
||||
<li>Install and administer OpenERP;</li>
|
||||
<li>Develop a new OpenERP module.</li>
|
||||
</ul>
|
||||
<p> </p>
|
||||
<p><strong>Our prices include:</strong></p>
|
||||
<ul>
|
||||
<li>drinks and lunch;</li>
|
||||
<li>training material.</li>
|
||||
</ul>
|
||||
<p> </p>
|
||||
<p><strong>Requirements:</strong></p>
|
||||
<ul>
|
||||
<li>Bring your own laptop.</li>
|
||||
<li>Participants are expected to have some knowledge in programming. A basic knowledge of the Python programming is recommended.</li>
|
||||
<li>Participants preferably have a functional knowledge of the OpenERP software (see Functional Training).</li>
|
||||
</ul>
|
||||
<p> </p>
|
||||
<p>For more information on the program, please explore <a href="http://www.openerp.com/services/technical-training">http://www.openerp.com/services/technical-training</a>.</p>
|
||||
<p>If you have a question<strong> concerning the content of the training</strong>, please contact <a href="mailto:training@openerp.com">training@openerp.com</a>.</p>
|
||||
<p> </p>
|
||||
<p><strong>Where to find us:</strong></p>
|
||||
<p>Chaussée de Namur 40, 1367 Ramillies (Belgium)</p>
|
||||
<p>More information about our Headquarter office (directions, transports, parking, hotels, ...), please have a look at <a href="http://bit.ly/VD8J67">http://bit.ly/VD8J67.</a></p>
|
||||
<p> </p>
|
||||
<p><strong>Cancellation Policy: </strong></p>
|
||||
<p>The organization of the training session has related costs. Due to these costs, cancellations made less than 2 weeks (14 calendar days) prior to the start of the training session is a subject to a fee. This fee can be up to a maximum of 1000€ per cancellation request.</p>
|
||||
<p>We strongly recommend to book your flight tickets and/or hotel reservations 2 weeks prior to the training. If the training is cancelled 2 weeks in advance, you'll be notified by email.</p>
|
||||
<div> </div>
|
||||
<p>For any additional information, please contact us at <a href="mailto:events@openerp.com">events@openerp.com</a>.</p>
|
||||
<p> </p>
|
||||
<p>Best regards,</p>
|
||||
<p>Miss Charline Louis, OpenERP Junior Event Manager</p>
|
||||
<p> </p>
|
||||
<p align="RIGHT"><em>(OpenERP reserves the right to cancel, re-name or re-locate<br/>the event or change the dates on which it is held.)</em></p>
|
||||
]]></field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Business Applications
|
||||
# Copyright (c) 20123TODAY OpenERP S.A. <http://www.openerp.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp.addons.website_blog.tests import test_controllers
|
||||
|
||||
checks = [
|
||||
test_controllers,
|
||||
]
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -0,0 +1,29 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2013-Today OpenERP SA (<http://www.openerp.com>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp.addons.mail.tests.test_mail_base import TestMailBase
|
||||
from openerp.tools import mute_logger, email_split
|
||||
|
||||
|
||||
class TestControllers(TestMailBase):
|
||||
|
||||
def test_00(self):
|
||||
cr, uid = self.cr, self.uid
|
|
@ -22,7 +22,6 @@
|
|||
</template>
|
||||
|
||||
<!-- Page -->
|
||||
|
||||
<template id="index" name="Events" page="True">
|
||||
<t t-call="website.layout">
|
||||
<t t-set="head">
|
||||
|
@ -30,9 +29,6 @@
|
|||
</t>
|
||||
<t t-set="title">Events</t>
|
||||
<div id="wrap">
|
||||
<div class="oe_structure">
|
||||
<h1 class="text-center">Our Events</h1>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-4 css_noprint" id="left_column">
|
||||
|
@ -51,6 +47,17 @@
|
|||
</t>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<div class="oe_structure">
|
||||
<h2>
|
||||
Events for <t t-esc="current_date"/>
|
||||
<t t-if="current_type">
|
||||
in <t t-esc="current_type.name"/>
|
||||
</t>
|
||||
<t t-if="current_country">
|
||||
in <t t-esc="current_country.name"/>
|
||||
</t>
|
||||
</h2>
|
||||
</div>
|
||||
<ul class="media-list">
|
||||
<li t-foreach="event_ids" t-as="event" class="media" data-publish="">
|
||||
<t t-call="website.publish"><t t-set="object" t-value="event"/></t>
|
||||
|
@ -119,7 +126,7 @@
|
|||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="detail">
|
||||
<template id="event_description_full">
|
||||
<t t-call="website.layout">
|
||||
<t t-set="head">
|
||||
<script type="text/javascript" src="/website_event/static/src/js/website_event.js"></script>
|
||||
|
@ -128,21 +135,10 @@
|
|||
<t t-set="title">Events</t>
|
||||
<div id="wrap">
|
||||
<div class="container">
|
||||
<t t-call="website.publish"><t t-set="object" t-value="event_id"/></t>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<form action="./subscribe" method="POST" class="form-inline" t-if="not subscribe">
|
||||
<div class="col-lg-7">
|
||||
<input placeholder="Email Address" type="email" name="email" class="form-control" t-if="is_public_user"/>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary" name="subscribe">Subscribe</button>
|
||||
</form>
|
||||
<form action="./unsubscribe" method="POST" class="form-inline" t-if="subscribe">
|
||||
<input type="hidden" name="email" t-att-value="subscribe"/>
|
||||
<button type="submit" class="btn btn-default" name="unsubscribe">Unsubscribe</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<t t-call="website.publish"><t t-set="object" t-value="event_id"/></t>
|
||||
<t t-call="website_mail.follow"><t t-set="object" t-value="event_id"/></t>
|
||||
<h1 class="text-center" t-field="event_id.name"></h1>
|
||||
<h4 class="text-center">
|
||||
<i class="icon-time"></i> <span t-field="event_id.date_begin"/> to
|
||||
|
@ -151,20 +147,19 @@
|
|||
<h5 class="text-center" t-field="event_id.address_id"/>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4 css_noprint">
|
||||
<div class="col-md-4 css_noprint pull-right">
|
||||
<h4>When & Where</h4>
|
||||
<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"/>
|
||||
|
||||
<address><pre t-field="event_id.address_id"/></address>
|
||||
<i class="icon-time"></i> <span t-field="event_id.date_begin"> </span><br/>
|
||||
<i class="icon-time"></i> <span t-field="event_id.date_end"> </span>
|
||||
<t t-if="event_id.organizer_id">
|
||||
<h6>Organized by:</h6>
|
||||
<pre><t t-field="event_id.organizer_id"/><t t-if="event_id.phone"><br/><span>&#x2706;</span> <span t-field="event_id.phone"></span></t><t t-if="event_id.email"><br/><i class="icon-envelope"></i> <span t-field="event_id.email"></span></t></pre>
|
||||
<address><strong t-field="event_id.organizer_id.display_name"/><t t-if="event_id.phone"><br/><span>&#x2706;</span> <span t-field="event_id.phone"></span></t><t t-if="event_id.email"><br/><i class="icon-envelope"></i> <span t-field="event_id.email"></span></t></address>
|
||||
</t>
|
||||
</address>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<t t-if="event_id.event_ticket_ids">
|
||||
|
@ -195,14 +190,14 @@
|
|||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<button type="submit" class="btn btn-primary" t-if="event_id.register_avail">Order Now</button>
|
||||
<button type="submit" class="btn btn-primary pull-right" t-if="event_id.register_avail">Order Now</button><br/>
|
||||
</form>
|
||||
</t>
|
||||
<hr/>
|
||||
<div t-field="event_id.description_website"></div>
|
||||
<div t-field="event_id.description"></div>
|
||||
<hr/>
|
||||
<ul class="media-list" id="comment">
|
||||
<li t-foreach="message_ids" t-as="comment" class="media">
|
||||
<li t-foreach="event_id.website_message_ids" t-as="comment" class="media">
|
||||
<div class="media-body">
|
||||
<t t-call="website.publish"><t t-set="object" t-value="comment"/></t>
|
||||
<t t-raw="comment.body"/>
|
||||
|
|
|
@ -21,3 +21,4 @@
|
|||
|
||||
import controllers
|
||||
import mail_message
|
||||
import mail_thread
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2013-Today OpenERP SA (<http://www.openerp.com>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp.osv import osv, fields
|
||||
|
||||
|
||||
class MailThread(osv.Model):
|
||||
_inherit = 'mail.thread'
|
||||
|
||||
_columns = {
|
||||
'website_message_ids': fields.one2many(
|
||||
'mail.message', 'res_id',
|
||||
domain=lambda self: [
|
||||
'&', ('model', '=', self._name), ('type', '=', 'comment')
|
||||
],
|
||||
string='Website Messages',
|
||||
help="Website communication history",
|
||||
),
|
||||
}
|
|
@ -1,15 +1,16 @@
|
|||
|
||||
{
|
||||
'name': 'Public Projects',
|
||||
'category': 'Website',
|
||||
'summary': 'Publish Your Public Projects',
|
||||
'version': '1.0',
|
||||
'description': """
|
||||
OpenERP Blog
|
||||
============
|
||||
OpenERP Projects
|
||||
================
|
||||
|
||||
""",
|
||||
'author': 'OpenERP SA',
|
||||
'depends': ['website', 'project'],
|
||||
'depends': ['website_mail', 'project'],
|
||||
'data': [
|
||||
'views/website_project.xml',
|
||||
],
|
||||
|
|
|
@ -1,13 +1,33 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2013-Today OpenERP SA (<http://www.openerp.com>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp.osv import osv
|
||||
from openerp.addons.web import http
|
||||
from openerp.addons.web.http import request
|
||||
from openerp.addons.website import website
|
||||
from openerp.osv import osv
|
||||
|
||||
|
||||
class Website(osv.osv):
|
||||
class Website(osv.Model):
|
||||
_inherit = "website"
|
||||
|
||||
def preprocess_request(self, cr, uid, ids, *args, **kwargs):
|
||||
project_obj = request.registry['project.project']
|
||||
project_ids = project_obj.search(cr, uid, [('privacy_visibility', "=", "public")], context=request.context)
|
||||
|
@ -20,7 +40,25 @@ class Website(osv.osv):
|
|||
class website_project(http.Controller):
|
||||
|
||||
@website.route(['/project/<int:project_id>/'], type='http', auth="public")
|
||||
def blog(self, project_id=None, **post):
|
||||
def project(self, project_id=None, **post):
|
||||
cr, uid, context = request.cr, request.uid, request.context
|
||||
project_obj = request.registry['project.project']
|
||||
|
||||
project = project_obj.browse(request.cr, request.uid, project_id, request.context)
|
||||
return request.website.render("website_project.index", {'project_id': project})
|
||||
|
||||
render_values = {
|
||||
'project': project
|
||||
}
|
||||
return request.website.render("website_project.index", render_values)
|
||||
|
||||
@website.route(['/project/task/<int:task_id>'], type='http', auth="public")
|
||||
def task(self, task_id=None, **post):
|
||||
cr, uid, context = request.cr, request.uid, request.context
|
||||
task_obj = request.registry['project.task']
|
||||
|
||||
task = task_obj.browse(cr, uid, task_id, context=context)
|
||||
|
||||
render_values = {
|
||||
'task': task
|
||||
}
|
||||
return request.website.render("website_project.task", render_values)
|
||||
|
|
|
@ -2,21 +2,29 @@
|
|||
<openerp>
|
||||
<data>
|
||||
|
||||
|
||||
<!-- Layout add nav and footer -->
|
||||
|
||||
<template id="footer_custom" inherit_id="website.layout" name="Custom Footer">
|
||||
<xpath expr="//footer//ul[@name='products']" position="inside">
|
||||
<li t-foreach="website_project_ids" t-as="project"><a t-attf-href="/project/#{ project.id }/"><t t-esc="project.name"/></a></li>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<!-- Page -->
|
||||
<!-- Task -->
|
||||
<template id="task" name="Task">
|
||||
<t t-call="website.layout">
|
||||
<t t-set="title">Task</t>
|
||||
<div id="wrap">
|
||||
<div class="container">
|
||||
<h4 t-field="task.name"/>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
|
||||
<template id="kanban_card" name="Project">
|
||||
<!-- Project -->
|
||||
<template id="task_kanban_card" name="TaskKanban">
|
||||
<div class="thumbnail">
|
||||
<a t-attf-href="/task/#{ object_id.id }/"><span t-field="object_id.name"/></a>
|
||||
<a t-attf-href="/project/task/#{object_id.id}/"><span t-field="object_id.name"/></a>
|
||||
<div>
|
||||
Assigned to <span t-field="object_id.user_id"/>
|
||||
</div>
|
||||
|
@ -31,24 +39,21 @@
|
|||
</small>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="index" name="Project">
|
||||
<t t-call="website.layout">
|
||||
<t t-set="title">Project</t>
|
||||
<div id="wrap">
|
||||
<div class="oe_structure"/>
|
||||
<div class="container">
|
||||
<h4 t-field="project_id.name"/>
|
||||
<h4 t-field="project.name"/>
|
||||
<t t-call="website.kanban">
|
||||
<t t-set="model">project.task</t>
|
||||
<t t-set="domain" t-value="[('project_id', '=', project_id.id)]"/>
|
||||
<t t-set="domain" t-value="[('project_id', '=', project.id)]"/>
|
||||
<t t-set="column">stage_id</t>
|
||||
<t t-set="template">website_project.kanban_card</t>
|
||||
<t t-set="template">website_project.task_kanban_card</t>
|
||||
<t t-set="step">10</t>
|
||||
<t t-set="scope">3</t>
|
||||
</t>
|
||||
</div>
|
||||
<div class="oe_structure"/>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
import controllers
|
||||
import product
|
||||
import website_sale
|
||||
|
|
|
@ -50,10 +50,23 @@ class Website(osv.osv):
|
|||
class Ecommerce(http.Controller):
|
||||
|
||||
def get_categories(self):
|
||||
domain = [('parent_id', '=', False)]
|
||||
|
||||
category_obj = request.registry.get('product.public.category')
|
||||
category_ids = category_obj.search(request.cr, SUPERUSER_ID, [('parent_id', '=', False)], context=request.context)
|
||||
category_ids = category_obj.search(request.cr, SUPERUSER_ID, domain, context=request.context)
|
||||
categories = category_obj.browse(request.cr, SUPERUSER_ID, category_ids, context=request.context)
|
||||
return categories
|
||||
|
||||
product_obj = request.registry.get('product.product')
|
||||
groups = product_obj.read_group(request.cr, SUPERUSER_ID, [("sale_ok", "=", True), ('website_published', '=', True)], ['public_categ_id'], 'public_categ_id', context=request.context)
|
||||
full_category_ids = [group['public_categ_id'][0] for group in groups if group['public_categ_id']]
|
||||
|
||||
for cat_id in category_obj.browse(request.cr, SUPERUSER_ID, full_category_ids, context=request.context):
|
||||
while cat_id.parent_id:
|
||||
cat_id = cat_id.parent_id
|
||||
full_category_ids.append(cat_id.id)
|
||||
full_category_ids.append(1)
|
||||
|
||||
return (categories, full_category_ids)
|
||||
|
||||
@website.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):
|
||||
|
@ -63,7 +76,7 @@ class Ecommerce(http.Controller):
|
|||
product_obj = request.registry.get('product.template')
|
||||
|
||||
domain = [("sale_ok", "=", True)]
|
||||
domain += [('website_published', '=', True)]
|
||||
#domain += [('website_published', '=', True)]
|
||||
|
||||
if post.get("search"):
|
||||
domain += ['|', '|', '|',
|
||||
|
@ -84,7 +97,7 @@ class Ecommerce(http.Controller):
|
|||
request.context['pricelist'] = self.get_pricelist()
|
||||
|
||||
values = {
|
||||
'categories': self.get_categories(),
|
||||
'get_categories': self.get_categories,
|
||||
'category_id': cat_id,
|
||||
'products': product_obj.browse(request.cr, SUPERUSER_ID, product_ids, context=request.context),
|
||||
'search': post.get("search"),
|
||||
|
@ -117,7 +130,7 @@ class Ecommerce(http.Controller):
|
|||
'category_id': post.get('category_id') and int(post.get('category_id')) or None,
|
||||
'category': category,
|
||||
'search': post.get("search"),
|
||||
'categories': self.get_categories(),
|
||||
'get_categories': self.get_categories,
|
||||
'category_list': category_list,
|
||||
'product': product,
|
||||
}
|
||||
|
@ -234,6 +247,7 @@ class Ecommerce(http.Controller):
|
|||
for line in order.order_line:
|
||||
suggested_ids += [p.id for p in line.product_id and line.product_id.suggested_product_ids or [] for line in order.order_line]
|
||||
suggested_ids = prod_obj.search(request.cr, request.uid, [('id', 'in', suggested_ids)], context=request.context)
|
||||
|
||||
# select 3 random products
|
||||
suggested_products = []
|
||||
while len(suggested_products) < 3 and suggested_ids:
|
||||
|
@ -241,7 +255,7 @@ class Ecommerce(http.Controller):
|
|||
suggested_products.append(suggested_ids.pop(index))
|
||||
|
||||
values = {
|
||||
'categories': self.get_categories(),
|
||||
'get_categories': self.get_categories,
|
||||
'suggested_products': prod_obj.browse(request.cr, request.uid, suggested_products, request.context),
|
||||
}
|
||||
return request.website.render("website_sale.mycart", values)
|
||||
|
@ -272,9 +286,12 @@ class Ecommerce(http.Controller):
|
|||
|
||||
@website.route(['/shop/checkout/'], type='http', auth="public")
|
||||
def checkout(self, **post):
|
||||
classic_fields = ["name", "phone", "fax", "email", "street", "city", "state_id", "zip"]
|
||||
rel_fields = ['country_id', 'state_id']
|
||||
|
||||
order = get_current_order()
|
||||
|
||||
if order.state != 'draft' or not order.order_line:
|
||||
if not order or order.state != 'draft' or not order.order_line:
|
||||
return self.mycart(**post)
|
||||
|
||||
partner_obj = request.registry.get('res.partner')
|
||||
|
@ -287,24 +304,20 @@ class Ecommerce(http.Controller):
|
|||
'error': post.get("error") and dict.fromkeys(post.get("error").split(","), 'error') or {}
|
||||
}
|
||||
|
||||
checkout = {}
|
||||
checkout = dict((field_name, '') for field_name in classic_fields + rel_fields)
|
||||
if not request.context['is_public_user']:
|
||||
partner = user_obj.browse(request.cr, request.uid, request.uid, request.context).partner_id
|
||||
partner_id = partner.id
|
||||
fields = ["name", "phone", "fax", "company", "email", "street", "city", "state_id", "zip", "country_id"]
|
||||
checkout = user_obj.read(request.cr, SUPERUSER_ID, [partner_id], fields, request.context)[0]
|
||||
checkout.update(dict((field_name, getattr(partner, field_name)) for field_name in classic_fields if getattr(partner, field_name)))
|
||||
checkout['state_id'] = partner.state_id and partner.state_id.id or ''
|
||||
checkout['country_id'] = partner.country_id and partner.country_id.id or ''
|
||||
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')], context=request.context)
|
||||
shipping_ids = partner_obj.search(request.cr, request.uid, [("parent_id", "=", partner.id), ('type', "=", 'delivery')], context=request.context)
|
||||
if shipping_ids:
|
||||
for k, v in partner_obj.read(request.cr, request.uid, shipping_ids[0], request.context).items():
|
||||
checkout['shipping_'+k] = v or ''
|
||||
|
||||
checkout.update(request.session.setdefault('checkout', {}))
|
||||
for k,v in checkout.items():
|
||||
checkout[k] = v or ''
|
||||
values['checkout'] = checkout
|
||||
|
||||
countries_ids = country_obj.search(request.cr, SUPERUSER_ID, [(1, "=", 1)], context=request.context)
|
||||
values['countries'] = country_obj.browse(request.cr, SUPERUSER_ID, countries_ids, request.context)
|
||||
states_ids = country_state_obj.search(request.cr, SUPERUSER_ID, [(1, "=", 1)], context=request.context)
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2013-Today OpenERP SA (<http://www.openerp.com>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp.osv import osv, fields
|
||||
|
||||
|
||||
class product_pricelist(osv.Model):
|
||||
_inherit = "product.pricelist"
|
||||
_columns = {
|
||||
'code': fields.char('Promotionnal Code', size=64, translate=True),
|
||||
}
|
||||
|
||||
|
||||
class product_template(osv.Model):
|
||||
_inherit = "product.template"
|
||||
_order = 'website_published,name'
|
||||
_columns = {
|
||||
'website_published': fields.boolean('Available in the website'),
|
||||
'website_description': fields.html('Description for the website'),
|
||||
'suggested_product_id': fields.many2one('product.template', 'Suggested For Product'),
|
||||
'suggested_product_ids': fields.one2many('product.template', 'suggested_product_id', 'Suggested Products'),
|
||||
'website_sizex': fields.selection(map(lambda x: (str(x+1),str(x+1)), range(12)), 'Size X'),
|
||||
'website_sizey': fields.selection(map(lambda x: (str(x+1),str(x+1)), range(6)), 'Size Y'),
|
||||
'website_product_class': fields.selection([('','Default'), ('oe_image_full','Image Full')], 'Size Y'),
|
||||
}
|
||||
_defaults = {
|
||||
'website_sizex': '3',
|
||||
'website_sizey': '2',
|
||||
'website_product_class': '',
|
||||
}
|
||||
|
||||
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 10
|
||||
"""
|
||||
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)], limit=3)
|
||||
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 product_product(osv.Model):
|
||||
_inherit = "product.product"
|
||||
|
||||
def _website_url(self, cr, uid, ids, field_name, arg, context=None):
|
||||
res = {}
|
||||
base_url = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url')
|
||||
for id in ids:
|
||||
res[id] = "%s/shop/product/%s/" % (base_url, id)
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'website_url': fields.function(_website_url, string="Website url"),
|
||||
}
|
||||
|
||||
def img(self, cr, uid, ids, field='image_small', context=None):
|
||||
temp_id = self.browse(cr, uid, ids[0], context=context).product_tmpl_id.id
|
||||
return "/website/image?model=product.template&field=%s&id=%s" % (field, temp_id)
|
|
@ -2,6 +2,20 @@
|
|||
/* ---- Default Styles Description ---- */
|
||||
.oe_product_image {
|
||||
position: absolute;
|
||||
}
|
||||
.oe_product_image img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
margin: auto;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.oe_product .oe_product_image {
|
||||
position: absolute;
|
||||
left: 15px;
|
||||
right: 15px;
|
||||
top: 15px;
|
||||
|
@ -71,18 +85,60 @@
|
|||
}
|
||||
|
||||
/* ---- Product Sizes ---- */
|
||||
.oe-height-1 {
|
||||
height: 170px;
|
||||
.col-md-12 .oe-height-1 {
|
||||
height: 125px;
|
||||
}
|
||||
.col-md-12 .oe-height-2 {
|
||||
height: 250px;
|
||||
}
|
||||
.col-md-12 .oe-height-3 {
|
||||
height: 375px;
|
||||
}
|
||||
.col-md-12 .oe-height-4 {
|
||||
height: 499.9px;
|
||||
}
|
||||
|
||||
.oe-height-2 {
|
||||
height: 255px;
|
||||
.col-md-9 .oe-height-1 {
|
||||
height: 95px;
|
||||
}
|
||||
.col-md-9 .oe-height-2 {
|
||||
height: 190px;
|
||||
}
|
||||
.col-md-9 .oe-height-3 {
|
||||
height: 285px;
|
||||
}
|
||||
.col-md-9 .oe-height-4 {
|
||||
height: 380px;
|
||||
}
|
||||
|
||||
.oe-height-3 {
|
||||
height: 340px;
|
||||
/* ---- Product list style ---- */
|
||||
.oe_list_products {
|
||||
border: 1px solid rgba(100, 100, 100, 0.2);
|
||||
max-width: 100%;
|
||||
max-height: 140px;
|
||||
}
|
||||
|
||||
.oe-height-4 {
|
||||
height: 510px;
|
||||
.oe_list_products .oe_product_image {
|
||||
position: absolute;
|
||||
left: 15px;
|
||||
right: 15px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 150px;
|
||||
}
|
||||
.oe_list_products .oe_product_image img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
margin: auto;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
.oe_list_products .oe_product_description {
|
||||
bottom: 0;
|
||||
position: absolute;
|
||||
left: 180px;
|
||||
right: 0;
|
||||
border-top: 1px solid #dddddd;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,19 @@
|
|||
|
||||
/* ---- Default Styles Description ---- */
|
||||
|
||||
.oe_product_image
|
||||
position: absolute
|
||||
img
|
||||
max-width: 100%
|
||||
max-height: 100%
|
||||
margin: auto
|
||||
position: absolute
|
||||
top: 0
|
||||
left: 0
|
||||
bottom: 0
|
||||
right: 0
|
||||
|
||||
.oe_product
|
||||
.oe_product_image
|
||||
position: absolute
|
||||
left: 15px
|
||||
|
@ -72,15 +85,50 @@
|
|||
|
||||
/* ---- Product Sizes ---- */
|
||||
|
||||
.col-md-12
|
||||
.oe-height-1
|
||||
height: 170px
|
||||
|
||||
height: 125px
|
||||
.oe-height-2
|
||||
height: 255px
|
||||
|
||||
height: 250px
|
||||
.oe-height-3
|
||||
height: 340px
|
||||
|
||||
height: 375px
|
||||
.oe-height-4
|
||||
height: 510px
|
||||
height: 499.9px
|
||||
.col-md-9
|
||||
.oe-height-1
|
||||
height: 95px
|
||||
.oe-height-2
|
||||
height: 190px
|
||||
.oe-height-3
|
||||
height: 285px
|
||||
.oe-height-4
|
||||
height: 380px
|
||||
|
||||
|
||||
/* ---- Product list style ---- */
|
||||
.oe_list_products
|
||||
border: 1px solid rgba(100, 100, 100, 0.2)
|
||||
max-width: 100%
|
||||
max-height: 140px
|
||||
.oe_product_image
|
||||
position: absolute
|
||||
left: 15px
|
||||
right: 15px
|
||||
top: 0
|
||||
bottom: 0
|
||||
width: 150px
|
||||
img
|
||||
max-width: 100%
|
||||
max-height: 100%
|
||||
margin: auto
|
||||
position: absolute
|
||||
top: 0
|
||||
left: 0
|
||||
bottom: 0
|
||||
right: 0
|
||||
.oe_product_description
|
||||
bottom: 0
|
||||
position: absolute
|
||||
left: 180px
|
||||
right: 0
|
||||
border-top: 1px solid #dddddd
|
||||
|
|
|
@ -68,11 +68,13 @@
|
|||
|
||||
<template id="categories_recursive">
|
||||
<li t-att-class="category.id == category_id and 'active' or ''">
|
||||
<a t-attf-href="/shop/category/#{ category.id }/" t-field="category.name"></a>
|
||||
<a t-att-class="category.id not in categ[1] and 'unpublish' or ''" t-attf-href="/shop/category/#{ category.id }/" t-field="category.name"></a>
|
||||
<ul t-if="category.child_id" class="nav nav-pills nav-stacked nav-hierarchy">
|
||||
<t t-foreach="category.child_id" t-as="category">
|
||||
<t t-if="category.id in categ[1] or editable">
|
||||
<t t-call="website_sale.categories_recursive"/>
|
||||
</t>
|
||||
</t>
|
||||
</ul>
|
||||
</li>
|
||||
</template>
|
||||
|
@ -111,7 +113,7 @@
|
|||
<div class='row style_default'>
|
||||
<div class="col-md-12" id="products_grid">
|
||||
<t t-foreach="products" t-as="product">
|
||||
<div t-attf-class="col-md-#{ product.website_sizex } oe_product oe-height-#{ product.website_sizey } #{ product.website_product_class}" t-att-data-publish="product.website_published" data-snippet-id="colmd">
|
||||
<div t-attf-class="col-md-#{ search and 3 or product.website_sizex } oe_product oe-height-#{ search and 2 or product.website_sizey } #{ product.website_product_class}" t-att-data-publish="product.website_published and 'on' or 'off'" data-name="products_layout">
|
||||
|
||||
<div class="oe_product_description">
|
||||
<a t-attf-href="/shop/product/#{ product.id }/?#{ search and ('search=%s' % search) or ''}#{ category_id and ('&category_id=%s' % category_id) or ''}">
|
||||
|
@ -119,9 +121,7 @@
|
|||
</a>
|
||||
<!-- This should be an option -->
|
||||
<div t-if="product.description_sale" class="text-muted oe_subdescription">
|
||||
|
||||
<!-- TODO: replace by a smart t-field on field.text: description_sale -->
|
||||
<small t-raw="product.description_sale.replace('\n','<br/>') "/>
|
||||
<div id="product_description" t-att-data-name="product.id"/>
|
||||
</div>
|
||||
<div>
|
||||
<b>
|
||||
|
@ -132,9 +132,7 @@
|
|||
</t>
|
||||
<t t-esc="product.product_variant_ids[0].price" /> €
|
||||
</b>
|
||||
<a t-attf-href="./add_cart/?product_id=#{ product.id }">
|
||||
<span class="icon-shopping-cart"/>
|
||||
</a>
|
||||
<span id="add_to_cart" t-att-data-name="product.id"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -157,6 +155,35 @@
|
|||
</t>
|
||||
</template>
|
||||
|
||||
<!-- Product Description-->
|
||||
|
||||
<template id="product_description" inherit_option_id="website_sale.products" name="Product Description">
|
||||
<xpath expr="//div[@id='product_description']" position="replace">
|
||||
<small>
|
||||
<t t-field="product.description_sale"/>
|
||||
</small>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<!-- Add to cart button-->
|
||||
|
||||
<template id="add_to_basket" inherit_option_id="website_sale.products" name="Add to Cart">
|
||||
<xpath expr="//span[@id='add_to_cart']" position="replace">
|
||||
<a t-attf-href="./add_cart/?product_id=#{ product.id }">
|
||||
<span class="icon-shopping-cart"/>
|
||||
</a>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<!-- List view of products -->
|
||||
|
||||
<template id="list_view" inherit_option_id="website_sale.products" name="List View">
|
||||
<xpath expr="//div[@data-name='products_layout']" position="attributes">
|
||||
<attribute name="class">col-md-12 oe_list_products oe-height-1</attribute>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
|
||||
<!-- product -->
|
||||
|
||||
<template id="product" name="Product">
|
||||
|
@ -344,7 +371,8 @@
|
|||
<div class="col-md-3">
|
||||
<ul class="nav nav-pills nav-stacked mt16">
|
||||
<li t-att-class=" '' if category_id else 'active' "><a href="/shop/">All Products</a></li>
|
||||
<t t-foreach="categories" t-as="category">
|
||||
<t t-set="categ" t-value="get_categories()"/>
|
||||
<t t-foreach="categ[0]" t-as="category">
|
||||
<t t-call="website_sale.categories_recursive"/>
|
||||
</t>
|
||||
</ul>
|
||||
|
@ -397,12 +425,16 @@
|
|||
<div class='row mt16'>
|
||||
<t t-foreach="suggested_products" t-as="product">
|
||||
<div class='col-md-2 thumbnail'>
|
||||
<a t-attf-href="/shop/product/#{ product.id }/">
|
||||
<div class='mt16 text-center'>
|
||||
<a t-attf-href="/shop/product/#{ product.id }/">
|
||||
<img t-att-src="product.img('image_small')"/>
|
||||
<h5 t-field='product.name'></h5>
|
||||
</div>
|
||||
</a>
|
||||
<h5>
|
||||
<a t-attf-href="/shop/product/#{ product.id }/" style="display: block;">
|
||||
<span t-field="product.name"/>
|
||||
</a>
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
|
@ -463,43 +495,43 @@
|
|||
<div t-attf-class="form-group #{error.get('name') and 'has-error' or ''}">
|
||||
<label class="col-lg-3 control-label" for="contact_name">Name and firstname</label>
|
||||
<div class="col-lg-4">
|
||||
<input type="text" name="name" class="form-control" t-att-value="checkout.get('name', '')"/>
|
||||
<input type="text" name="name" class="form-control" t-att-value="checkout['name']"/>
|
||||
</div>
|
||||
</div>
|
||||
<div t-attf-class="form-group #{ error.get('phone') and 'has-error' or ''}">
|
||||
<label class="col-lg-3 control-label" for="contact_name">Telephone</label>
|
||||
<div class="col-lg-4">
|
||||
<input type="tel" name="phone" class="form-control" t-att-value="checkout.get('phone', '')"/>
|
||||
<input type="tel" name="phone" class="form-control" t-att-value="checkout['phone']"/>
|
||||
</div>
|
||||
</div>
|
||||
<div t-attf-class="form-group #{error.get('fax') and 'has-error' or ''}">
|
||||
<label class="col-lg-3 control-label" for="contact_name">Fax</label>
|
||||
<div class="col-lg-4">
|
||||
<input type="tel" name="fax" class="form-control" t-att-value="checkout.get('fax', '')"/>
|
||||
<input type="tel" name="fax" class="form-control" t-att-value="checkout['fax']"/>
|
||||
</div>
|
||||
</div>
|
||||
<div t-attf-class="form-group #{error.get('company') and 'has-error' or ''}">
|
||||
<label class="col-lg-3 control-label" for="contact_name">Company</label>
|
||||
<div class="col-lg-4">
|
||||
<input type="text" name="company" class="form-control" t-att-value="checkout.get('company', '')"/>
|
||||
<input type="text" name="company" class="form-control" t-att-value="checkout['company']"/>
|
||||
</div>
|
||||
</div>
|
||||
<div t-attf-class="form-group #{error.get('email') and 'has-error' or ''}">
|
||||
<label class="col-lg-3 control-label" for="contact_name">Email address</label>
|
||||
<div class="col-lg-4">
|
||||
<input type="email" name="email" class="form-control" t-att-value="checkout.get('email', '')"/>
|
||||
<input type="email" name="email" class="form-control" t-att-value="checkout['email']"/>
|
||||
</div>
|
||||
</div>
|
||||
<div t-attf-class="form-group #{error.get('street') and 'has-error' or ''}">
|
||||
<label class="col-lg-3 control-label" for="contact_name">Street</label>
|
||||
<div class="col-lg-4">
|
||||
<input type="text" name="street" class="form-control" t-att-value="checkout.get('street', '')"/>
|
||||
<input type="text" name="street" class="form-control" t-att-value="checkout['street']"/>
|
||||
</div>
|
||||
</div>
|
||||
<div t-attf-class="form-group #{error.get('city') and 'has-error' or ''}">
|
||||
<label class="col-lg-3 control-label" for="contact_name">City</label>
|
||||
<div class="col-lg-4">
|
||||
<input type="text" name="city" class="form-control" t-att-value="checkout.get('city', '')"/>
|
||||
<input type="text" name="city" class="form-control" t-att-value="checkout['city']"/>
|
||||
</div>
|
||||
</div>
|
||||
<div t-attf-class="form-group #{error.get('state_id') and 'has-error' or ''}">
|
||||
|
@ -508,7 +540,7 @@
|
|||
<select name="state_id" class="form-control">
|
||||
<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>
|
||||
<option t-att-value="state.id" t-att-selected="state.id == checkout['state_id']"><t t-esc="state.name"/></option>
|
||||
</t>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -516,7 +548,7 @@
|
|||
<div t-attf-class="form-group #{error.get('zip') and 'has-error' or ''}">
|
||||
<label class="col-lg-3 control-label" for="contact_name">Zip / Postal Code</label>
|
||||
<div class="col-lg-4">
|
||||
<input type="text" name="zip" class="form-control" t-att-value="checkout.get('zip', '')"/>
|
||||
<input type="text" name="zip" class="form-control" t-att-value="checkout['zip']"/>
|
||||
</div>
|
||||
</div>
|
||||
<div t-attf-class="form-group #{error.get('country_id') and 'has-error' or ''}">
|
||||
|
@ -525,7 +557,7 @@
|
|||
<select name="country_id" class="form-control">
|
||||
<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>
|
||||
<option t-att-value="country.id" t-att-selected="country.id == checkout['country_id']"><t t-esc="country.name"/></option>
|
||||
</t>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -601,7 +633,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-default">Last stape</button>
|
||||
<button type="submit" class="btn btn-default">Confirm</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -20,90 +20,29 @@
|
|||
##############################################################################
|
||||
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp.osv import osv, fields
|
||||
from openerp.osv import osv
|
||||
|
||||
|
||||
class product_pricelist(osv.osv):
|
||||
_inherit = "product.pricelist"
|
||||
_columns = {
|
||||
'code': fields.char('Promotionnal Code', size=64, translate=True),
|
||||
}
|
||||
|
||||
class product_template(osv.osv):
|
||||
_inherit = "product.template"
|
||||
_columns = {
|
||||
'website_published': fields.boolean('Available in the website'),
|
||||
'website_description': fields.html('Description for the website'),
|
||||
'suggested_product_id': fields.many2one('product.template', 'Suggested For Product'),
|
||||
'suggested_product_ids': fields.one2many('product.template', 'suggested_product_id', 'Suggested Products'),
|
||||
'website_sizex': fields.selection(map(lambda x: (str(x+1),str(x+1)), range(12)), 'Size X'),
|
||||
'website_sizey': fields.selection(map(lambda x: (str(x+1),str(x+1)), range(6)), 'Size Y'),
|
||||
'website_product_class': fields.selection([('','Default'), ('oe_image_full','Image Full')], 'Size Y'),
|
||||
}
|
||||
_defaults = {
|
||||
'website_sizex': '3',
|
||||
'website_sizey': '2',
|
||||
'website_product_class': '',
|
||||
}
|
||||
|
||||
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 10
|
||||
"""
|
||||
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)], limit=3)
|
||||
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 product_product(osv.osv):
|
||||
_inherit = "product.product"
|
||||
|
||||
def _website_url(self, cr, uid, ids, field_name, arg, context=None):
|
||||
res = {}
|
||||
base_url = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url')
|
||||
for id in ids:
|
||||
res[id] = "%s/shop/product/%s/" % (base_url, id)
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'website_url': fields.function(_website_url, string="Website url"),
|
||||
}
|
||||
|
||||
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):
|
||||
class sale_order(osv.Model):
|
||||
_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 []))
|
||||
|
||||
class sale_order_line(osv.osv):
|
||||
|
||||
class sale_order_line(osv.Model):
|
||||
_inherit = "sale.order.line"
|
||||
|
||||
def _recalculate_product_values(self, cr, uid, ids, product_id=None, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
user_obj = self.pool.get('res.users')
|
||||
product_id = product_id or ids and self.browse(cr, uid, ids[0], context=context).product_id.id
|
||||
return self.product_id_change(cr, SUPERUSER_ID, [],
|
||||
return self.product_id_change(
|
||||
cr, SUPERUSER_ID, [],
|
||||
pricelist=context.pop('pricelist'),
|
||||
product=product_id,
|
||||
partner_id=user_obj.browse(cr, SUPERUSER_ID, uid).partner_id.id,
|
||||
context=context)['value']
|
||||
context=context
|
||||
)['value']
|
||||
|
|
Loading…
Reference in New Issue