[MERGE]Merge main al branch.

bzr revid: bth@tinyerp.com-20130807133950-gm911a2plrqy42ym
This commit is contained in:
bth-openerp
2013-08-07 19:09:50 +05:30
30 changed files with 996 additions and 864 deletions
+1 -1
View File
@@ -203,7 +203,7 @@ class event_event(osv.osv):
'email_confirmation_id' : fields.many2one('email.template','Event Confirmation Email', help="If you set an email template, each participant will receive this email announcing the confirmation of the event."),
'reply_to': fields.char('Reply-To Email', size=64, readonly=False, states={'done': [('readonly', True)]}, help="The email address of the organizer is likely to be put here, with the effect to be in the 'Reply-To' of the mails sent automatically at event or registrations confirmation. You can also put the email address of your mail gateway if you use one."),
'main_speaker_id': fields.many2one('res.partner','Main Speaker', readonly=False, states={'done': [('readonly', True)]}, help="Speaker who will be giving speech at the event."),
'address_id': fields.many2one('res.partner','Location Address', readonly=False, states={'done': [('readonly', True)]}),
'address_id': fields.many2one('res.partner','Location', readonly=False, states={'done': [('readonly', True)]}),
'street': fields.related('address_id','street',type='char',string='Street'),
'street2': fields.related('address_id','street2',type='char',string='Street2'),
'state_id': fields.related('address_id','state_id',type='many2one', relation="res.country.state", string='State'),
+1 -12
View File
@@ -80,18 +80,7 @@
</div>
<group>
<group>
<label for="address_id" string="Location"/>
<div>
<field name="address_id" on_change="on_change_address_id(address_id)" />
<field name="street" placeholder="Street..."/>
<field name="street2"/>
<div class="address_format">
<field name="city" placeholder="City" style="width: 40%%"/>
<field name="state_id" class="oe_no_button" placeholder="State" style="width: 37%%" options='{"no_open": true}'/>
<field name="zip" placeholder="ZIP" style="width: 20%%"/>
</div>
<field name="country_id" placeholder="Country" class="oe_no_button" options='{"no_open": true}'/>
</div>
<field name="address_id" on_change="on_change_address_id(address_id)" context="{'show_address': 1}" options='{"always_reload": True}'/>
</group>
<group>
<field name="user_id"/>
+1 -1
View File
@@ -8,7 +8,7 @@ OpenERP Website CMS
""",
'author': 'OpenERP SA',
'depends': ['base'],
'depends': ['web'],
'installable': True,
'data': [
'views/views.xml',
@@ -0,0 +1,166 @@
<section class="oe_container">
<div class="oe_row oe_spaced">
<div class="oe_span12">
<h2 class="oe_slogan">Enterprise Website Builder</h2>
<h3 class="oe_slogan">Get an awesome website. Customize easily.</h3>
</div>
<div class="oe_span6">
<div class="oe_demo oe_picture oe_screenshot">
<a href="https://www.openerp.com/saas_master/demo?lang=en_US&module=website">
<img src="">
</a>
<div class="oe_demo_footer oe_centeralign">Online Demo</div>
</div>
</div>
<div class="oe_span6">
<p class='oe_mt32'>
Create enterprise-grade website with our super easy builder; no backend, everything
is editable inline. Benefit from out-of-the-box business features; shop, events, blogs,
jobs announces, "our team" pages, etc.
</p>
<div class="oe_centeralign oe_websiteonly">
<a href="http://www.openerp.com/start?app=website" class="oe_button oe_big oe_tacky">Create your <span class="oe_emph">free</span> website</a>
</div>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row">
<h2 class="oe_slogan">Edit Anything Inline</h2>
<h3 class="oe_slogan">What You See Is What You Get. Really!</h3>
<div class="oe_span6">
<p class='oe_mt32'>
Create websites with no technical knowledge. OpenERP's unique
<em>'edit inline'</em> approach makes website creation
surprisingly easy. No more complex backend with menu managers,
page editors, banner manager, ... Just click anywhere to any
content.
</p><p>
"Want to change the price of a product? or put it in bold? Want to
change a blog title?" just click and change. What you see is what
you get. Really.
</p>
</div>
<div class="oe_span6">
<div class="oe_bg_img oe_centered">
<img class="oe_picture" src="">
</div>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row">
<h2 class="oe_slogan">Awsome. Astonishingly Beautiful.</h2>
<h3 class="oe_slogan">Professional themes and building blocks</h3>
<div class="oe_span6">
<img class="oe_picture oe_screenshot" src="">
</div>
<div class="oe_span6">
<p class='oe_mt32'>
OpenERP's building block feature and inline edition approach
allows to design modern website that are not possible with
traditional WYSIWYG page editors.
</p><p>
Whether it's for products descriptions, blogs or static pages,
you don't need to be a professioanl designer to create modern
and clean web pages.
</p>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row">
<h2 class="oe_slogan">Enterprise-Ready, out-of-the-box</h2>
<h3 class="oe_slogan">Install professional features without effort.</h3>
<div class="oe_span6">
<p class='oe_mt32'>
Activate ready-to-use enterprise features in just a click;
ecommerce, call-to-actions, jobs announces, events, customer
references, "our team" page, blogs, newsletters, etc.
</p><p>
Traditional eCommerce and CMS have poor backends as it's not their
core focus. The OpenERP integration allows you to benefit from the
best management software to follow-up on your orders, your jobs
applicants, your leads, etc.
</p><p>
You don't need anymore to synchronize your management software and
your ecommerce.
</p>
</div>
<div class="oe_span6">
<img class="oe_picture oe_screenshot" src="">
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row">
<h2 class="oe_slogan">Multi-languages Without Pain</h2>
<h3 class="oe_slogan">Automate updates and transaltions easily</h3>
<div class="oe_span6">
<div class="oe_bg_img">
<img class="oe_picture" src="">
</div>
</div>
<div class="oe_span6">
<p class='oe_mt32'>
Get your website translated in multiple languages with no effort.
OpenERP proposes and propagates translations automatically
across pages.
</p>
Our translation "on demand" features allows you to benefit from
professional translators to translate all your changes
automatically. Just change any part of your website (a new blog
post, a new pages, updated products, ...) and the translated
versions are updated automatically in around 32 hours.
</p>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row">
<h2 class="oe_slogan">Designer-Friendly Themes</h2>
<h3 class="oe_slogan">Designers love working on OpenERP</h3>
<div class="oe_span6">
<p class='oe_mt32'>
Themes are awesome and easy to design. You don't need to develop
to create new pages, themes or building blocks. We use a clean
HTML structure, a <a href="http://getbootstrap.com/">bootstrap</a>
CSS and our modularity allows to distribute your themes easily.
</p><p>
The building block approach allows the website to remain clean
after the end-users start creating new contents.
</p>
</div>
<div class="oe_span6">
<div class="oe_row_img oe_centered">
<img class="oe_picture" src="">
</div>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row">
<h2 class="oe_slogan">Optimize your online presence efficiently</h2>
<h3 class="oe_slogan">SEO tools at your finger tips</h3>
<div class="oe_span6">
<p class='oe_mt32'>
SEO tools are ready to use, with no configuration required.
OpenERP suggests keywords according to Google most searched
terms, Google Analytics tracks your shopping cart events,
sitemap and structuered content are created automatically for
Google indexation, etc.
</p>
</div>
<div class="oe_span6">
<div class="oe_bg_img">
<img class="oe_picture oe_screenshot" src="">
</div>
</div>
</div>
</section>
@@ -0,0 +1,124 @@
/**
* @license Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
(function() {
'use strict';
var containerTpl = CKEDITOR.addTemplate( 'sharedcontainer', '<div' +
' id="cke_{name}"' +
' class="cke {id} cke_reset_all cke_chrome cke_editor_{name} cke_shared cke_detached cke_{langDir} ' + CKEDITOR.env.cssClass + '"' +
' dir="{langDir}"' +
' title="' + ( CKEDITOR.env.gecko ? ' ' : '' ) + '"' +
' lang="{langCode}"' +
' role="presentation"' +
'>' +
'<div class="cke_inner">' +
'<div id="{spaceId}" class="cke_{space}" role="presentation">{content}</div>' +
'</div>' +
'</div>' );
CKEDITOR.plugins.add( 'sharedspace', {
afterInit: function( editor ) {
var spaces = editor.config.sharedSpaces;
if ( spaces ) {
for ( var spaceName in spaces ) {
create( editor, spaceName, spaces[ spaceName ] );
}
}
}
});
function create( editor, spaceName, targetId ) {
var target = CKEDITOR.document.getById( targetId ),
innerHtml, space;
if ( target ) {
// Have other plugins filling the space.
innerHtml = editor.fire( 'uiSpace', { space: spaceName, html: '' } ).html;
if ( innerHtml ) {
// Block the uiSpace handling by others (e.g. themed-ui).
editor.on( 'uiSpace', function( ev ) {
if ( ev.data.space == spaceName )
ev.cancel();
}, null, null, 1 ); // Hi-priority
// Inject the space into the target.
space = target.append( CKEDITOR.dom.element.createFromHtml( containerTpl.output({
id: editor.id,
name: editor.name,
langDir: editor.lang.dir,
langCode: editor.langCode,
space: spaceName,
spaceId: editor.ui.spaceId( spaceName ),
content: innerHtml
})));
// Only the first container starts visible. Others get hidden.
if ( target.getCustomData( 'cke_hasshared' ) )
space.hide();
else
target.setCustomData( 'cke_hasshared', 1 );
// There's no need for the space to be selectable.
space.unselectable();
// Prevent clicking on non-buttons area of the space from blurring editor.
space.on( 'mousedown', function( evt ) {
evt = evt.data;
if ( !evt.getTarget().hasAscendant( 'a', 1 ) )
evt.preventDefault();
});
// Register this UI space to the focus manager.
editor.focusManager.add( space, 1 );
// When the editor gets focus, show the space container, hiding others.
editor.on( 'focus', function() {
for ( var i = 0, sibling, children = target.getChildren(); ( sibling = children.getItem( i ) ); i++ ) {
if ( sibling.type == CKEDITOR.NODE_ELEMENT &&
!sibling.equals( space ) &&
sibling.hasClass( 'cke_shared' ) ) {
sibling.hide();
}
}
space.show();
});
editor.on( 'destroy', function() {
space.remove();
});
}
}
}
})();
/**
* Makes it possible to place some of the editor UI blocks, like the toolbar
* and the elements path, into any element in the page.
*
* The elements used to hold the UI blocks can be shared among several editor
* instances. In that case, only the blocks of the active editor instance will
* display.
*
* // Place the toolbar inside the element with ID "someElementId" and the
* // elements path into the element with ID "anotherId".
* config.sharedSpaces = {
* top: 'someElementId',
* bottom: 'anotherId'
* };
*
* // Place the toolbar inside the element with ID "someElementId". The
* // elements path will remain attached to the editor UI.
* config.sharedSpaces = {
* top: 'someElementId'
* };
*
* @cfg {Object} [sharedSpaces]
* @member CKEDITOR.config
*/
+10 -1
View File
@@ -1,3 +1,4 @@
@charset "utf-8";
.oe_website_editorbar {
position: fixed;
top: 0;
@@ -43,5 +44,13 @@
}
.oe_editable:focus {
outline: #80b5f2 solid 5px !important;
outline: none !important;
}
.oe_carousel_options {
cursor: pointer;
position: absolute;
white-space: nowrap;
z-index: 1;
display: none;
}
+8 -1
View File
@@ -39,4 +39,11 @@
padding-left: 6px
.oe_editable:focus
outline: #80B5F2 solid 5px !important
outline: none !important
.oe_carousel_options
cursor: pointer
position: absolute
white-space: nowrap
z-index: 1
display: none
+101 -13
View File
@@ -1,3 +1,11 @@
/* THIS CSS FILE IS FOR WEBSITE THEMING CUSTOMIZATION ONLY
*
* css for editor buttons, openerp widget included in the website and other
* stuff must go to the editor.css
*
*/
/* ----- GENERIC LAYOUTING HELPERS ---- */
/* Vertical Spacing */
.mt128 {
margin-top: 128px !important;
}
@@ -34,6 +42,88 @@
margin-top: 0px !important;
}
.mb128 {
margin-bottom: 128px !important;
}
.mb92 {
margin-bottom: 92px !important;
}
.mb64 {
margin-bottom: 64px !important;
}
.mb48 {
margin-bottom: 48px !important;
}
.mb32 {
margin-bottom: 32px !important;
}
.mb16 {
margin-bottom: 16px !important;
}
.mb8 {
margin-bottom: 8px !important;
}
.mb4 {
margin-bottom: 4px !important;
}
.mb0 {
margin-bottom: 0px !important;
}
/* Grid of unequally tall elements */
.grid > [class*="span"] {
display: inline-block;
float: none;
vertical-align: top;
margin-right: -4px;
box-sizing: border-box;
}
.grid > [class*="span"].grid-align-top > [class*="span"] {
vertical-align: top;
}
.grid > [class*="span"].grid-align-middle > [class*="span"] {
vertical-align: middle;
}
.grid > [class*="span"].grid-align-bottom > [class*="span"] {
vertical-align: bottom;
}
/* Table with two collumns aligned on the center */
.table-equalized {
width: 100%;
}
.table-equalized td:first-child {
width: 50%;
text-align: right;
padding-right: 1em;
vertical-align: bottom;
}
.table-equalized td:last-child {
width: 50%;
text-align: left;
vertical-align: bottom;
}
/* Theming pagination inside navbar */
.navbar-inner > .pagination {
margin: 6px 0;
}
.navbar-inner > .pagination ul {
position: relative;
top: 2px;
border: solid 2px rgba(0, 0, 0, 0.05);
border-radius: 8px;
}
/* ----- BOOTSTRAP HACK FOR STICKY FOOTER ----- */
html, body {
height: 100%;
box-sizing: border-box;
@@ -57,6 +147,7 @@ footer {
padding-bottom: 64px;
}
/* ---- HOMEPAGE THEME CUSTOMIZATION ---- */
.subheader {
letter-spacing: 3px;
font-weight: 300;
@@ -75,10 +166,20 @@ h5 {
font-weight: bold;
}
#myCarousel .item {
min-height: 300px;
color: white;
}
.nav > .pull-right {
float: right !important;
}
.thumbnail {
background: white;
}
/* ---- HACK FOR COVERING UP CK EDITOR BOGUS P INSERTION --- */
.navbar .nav > li > p {
margin-bottom: 0px;
}
@@ -98,16 +199,3 @@ h5 {
.nav > li a {
display: block;
}
#myCarousel .item {
min-height: 300px;
color: white;
}
.carousel > .css_carousel_options {
cursor: pointer;
position: absolute;
white-space: nowrap;
z-index: 1;
display: none;
}
+79 -12
View File
@@ -1,5 +1,16 @@
@charset "utf-8"
/*
* THIS CSS FILE IS FOR WEBSITE THEMING CUSTOMIZATION ONLY
*
* css for editor buttons, openerp widget included in the website and other
* stuff must go to the editor.css
*
*/
/* ----- GENERIC LAYOUTING HELPERS ---- */
/* Vertical Spacing */
.mt128
margin-top: 128px !important
.mt92
@@ -19,6 +30,62 @@
.mt0
margin-top: 0px !important
.mb128
margin-bottom: 128px !important
.mb92
margin-bottom: 92px !important
.mb64
margin-bottom: 64px !important
.mb48
margin-bottom: 48px !important
.mb32
margin-bottom: 32px !important
.mb16
margin-bottom: 16px !important
.mb8
margin-bottom: 8px !important
.mb4
margin-bottom: 4px !important
.mb0
margin-bottom: 0px !important
/* Grid of unequally tall elements */
.grid > [class*="span"]
display: inline-block
float: none
vertical-align: top
margin-right: -4px
box-sizing: border-box
&.grid-align-top > [class*="span"]
vertical-align: top
&.grid-align-middle > [class*="span"]
vertical-align: middle
&.grid-align-bottom > [class*="span"]
vertical-align: bottom
/* Table with two collumns aligned on the center */
.table-equalized
width: 100%
td:first-child
width: 50%
text-align: right
padding-right: 1em
vertical-align: bottom
td:last-child
width: 50%
text-align: left
vertical-align: bottom
/* Theming pagination inside navbar */
.navbar-inner > .pagination
margin: 6px 0
ul
position: relative
top: 2px
border: solid 2px rgba(0,0,0,0.05)
border-radius: 8px
/* ----- BOOTSTRAP HACK FOR STICKY FOOTER ----- */
html,body
height: 100%
@@ -39,8 +106,8 @@ footer
background: rgb(239, 248, 248) // rgb(221, 235, 227)
padding-top: 64px
padding-bottom: 64px
//*
color: #1abc9c !important
/* ---- HOMEPAGE THEME CUSTOMIZATION ---- */
.subheader
letter-spacing: 3px
@@ -56,9 +123,19 @@ header.navbar-fixed-top
h5
font-weight: bold
#myCarousel .item
min-height: 300px
color: white
.nav > .pull-right
float: right !important //bugfix for flatly theme
.thumbnail
background: white
/* ---- HACK FOR COVERING UP CK EDITOR BOGUS P INSERTION --- */
.navbar .nav > li > p
margin-bottom: 0px
@@ -75,13 +152,3 @@ h5
.nav > li a
display: block
#myCarousel .item
min-height: 300px
color: white
.carousel > .css_carousel_options
cursor: pointer
position: absolute
white-space: nowrap
z-index: 1
display: none
+26 -173
View File
@@ -159,157 +159,16 @@ instance.website.EditorBar = instance.web.Widget.extend({
},
});
instance.website.Action = instance.web.Widget.extend({
tagName: 'button',
attributes: {
type: 'button',
},
events: { click: 'perform' },
init: function (parent, name) {
this._super(parent);
this.name = name;
},
start: function () {
this.$el.text(this.name);
return this._super();
},
/**
* Executes action
*/
perform: null,
toggle: function (to) {
this.$el.prop('disabled', !to);
},
});
var Style = instance.website.Style = instance.website.Action.extend({
init: function (parent, name, style) {
this._super(parent, name);
this.style = style;
},
perform: function () {
this.getParent().with_editor(function (editor) {
editor.applyStyle(new CKEDITOR.style(this.style))
}.bind(this));
},
});
var Command = instance.website.Command = instance.website.Action.extend({
init: function (parent, name, command) {
this._super(parent, name);
this.command = command;
},
perform: function () {
this.getParent().with_editor(function (editor) {
switch (typeof this.command) {
case 'string': editor.execCommand(this.command); break;
case 'function': this.command(editor); break;
}
}.bind(this));
},
});
var Group = instance.website.ActionGroup = instance.website.Action.extend({
template: 'Website.ActionGroup',
events: { 'click > button': 'perform' },
instances: [],
init: function (parent, name, actions) {
this._super(parent, name);
this.actions = _(actions).map(this.getParent().proxy('init_command'));
},
start: function () {
this.instances.push(this);
var $ul = this.$('ul');
return $.when.apply(null, _(this.actions).map(function (action) {
var $li = $('<li>').appendTo($ul);
return action.appendTo($li);
}));
},
destroy: function () {
this.instances = _(this.instances).without(this);
return this._super();
},
perform: function () {
this.getParent().with_editor(function () {
_(this.instances).chain()
.without(this)
.pluck('$el')
.invoke('removeClass', 'open');
// JS part of bootstrap dropdown does really weird stuff which
// interacts quite badly with the RTE thing, so bypass it
this.$el.toggleClass('open');
}.bind(this), false);
return false;
},
toggle: function (to) {
this.$('> button').prop('disabled', !to);
},
});
instance.website.RTE = instance.web.Widget.extend({
tagName: 'li',
id: 'oe_rte_toolbar',
className: 'oe_right oe_rte_toolbar',
commands: [
[Command, "\uf032", 'bold'],
[Command, "\uf033", 'italic'],
[Command, "\uf0cd", 'underline'],
[Command, "\uf0cc", 'strike'],
[Command, "\uf12b", 'superscript'],
[Command, "\uf12c", 'subscript'],
[Command, "\uf0c1", 'link'],
[Command, "\uf127", 'unlink'],
[Command, "\uf10d", 'blockquote'],
// 'image' uses either filebrowserImageUploadUrl or
// filebrowserUploadUrl, and provides a `link` tab. imagebutton only
// uses filebrowserImageUploadUrl and does not provide a `link` tab to
// hotlink an image from the internets.
[Command, "\uf03e", 'image'],
// [Command, "\uf030", 'imagebutton'],
[Group, "\uf0ca", [
[Command, "\uf0ca", 'bulletedlist'],
[Command, "\uf0cb", 'numberedlist'],
[Command, "\uf03b", 'outdent'],
[Command, "\uf03c", 'indent']
]],
[Group, _lt("Heading"), [
[Style, _lt('H1'), { element: 'h1' }],
[Style, _lt('H2'), { element: 'h2', }],
[Style, _lt('H3'), { element: 'h3', }],
[Style, _lt('H4'), { element: 'h4', }],
[Style, _lt('H5'), { element: 'h5', }],
[Style, _lt('H6'), { element: 'h6', }]
]],
[Group, "\uf039", [
[Command, "\uf039", 'justifyblock'],
[Command, "\uf036", 'justifyleft'],
[Command, "\uf038", 'justifyright'],
[Command, "\uf037", 'justifycenter']
]]
],
// editor.ui.items -> possible commands &al
// editor.applyStyle(new CKEDITOR.style({element: "span",styles: {color: "#(color)"},overrides: [{element: "font",attributes: {color: null}}]}, {color: '#ff0000'}));
start: function () {
this.$el.hide();
return $.when.apply(
null, _(this.commands).map(this.proxy('start_command')));
},
init_command: function (command) {
var type = command[0], args = command.slice(1);
args.unshift(this);
var F = function (args) {
return type.apply(this, args);
};
F.prototype = type.prototype;
return new F(args);
},
start_command: function (command) {
return this.init_command(command).appendTo(this.$el);
},
start_edition: function ($elements) {
var self = this;
this.$el.show();
this.disable();
this.snippet_carousel();
CKEDITOR.on('currentInstance', this.proxy('_change_focused_editor'));
$elements
.not('span, [data-oe-type]')
.each(function () {
@@ -321,48 +180,17 @@ instance.website.RTE = instance.web.Widget.extend({
});
},
/**
* @param {Function} fn
* @param {Boolean} [snapshot=true]
* @returns {$.Deferred}
*/
with_editor: function (fn, snapshot) {
var editor = this._current_editor();
if (snapshot !== false) { editor.fire('saveSnapshot'); }
return $.when(fn(editor)).then(function () {
if (snapshot !== false) { editor.fire('saveSnapshot'); }
editor.focus();
});
},
toggle: function (to) {
_(this.getChildren()).chain()
.filter(function (child) { return child instanceof instance.website.Action })
.invoke('toggle', to);
},
disable: function () {
this.toggle(false);
},
_current_editor: function () {
return CKEDITOR.currentInstance;
},
_change_focused_editor: function () {
this.toggle(!!CKEDITOR.currentInstance);
},
_config: function () {
var removed_plugins = [
// remove toolbar entirely
'toolbar,elementspath,resize',
// remove custom context menu
'contextmenu,tabletools,liststyle',
// magicline captures mousein/mouseout => draggable does not work
'magicline'
];
return {
// Don't load ckeditor's style rules
stylesSet: [],
removePlugins: removed_plugins.join(','),
uiColor: '',
// Ensure no config file is loaded
@@ -372,6 +200,31 @@ instance.website.RTE = instance.web.Widget.extend({
// Don't insert paragraphs around content in e.g. <li>
autoParagraph: false,
filebrowserImageUploadUrl: "/website/attach",
// Support for sharedSpaces in 4.x
extraPlugins: 'sharedspace',
// Place toolbar in controlled location
sharedSpaces: { top: 'oe_rte_toolbar' },
toolbar: [
{name: 'items', items: [
"Bold", "Italic", "Underline", "Strike", "Subscript",
"Superscript", "TextColor", "BGColor", "RemoveFormat",
"Link", "Unlink", "Blockquote", "BulletedList",
"NumberedList", "Image", "Indent", "Outdent",
"JustifyLeft", "JustifyCenter", "JustifyRight",
"JustifyBlock", "Table", "Font", "FontSize", "Format",
"Styles"
]}
],
// styles dropdown in toolbar
stylesSet: [
// emphasis
{name: "Muted", element: 'span', attributes: {'class': 'text-muted'}},
{name: "Primary", element: 'span', attributes: {'class': 'text-primary'}},
{name: "Warning", element: 'span', attributes: {'class': 'text-warning'}},
{name: "Danger", element: 'span', attributes: {'class': 'text-danger'}},
{name: "Success", element: 'span', attributes: {'class': 'text-success'}},
{name: "Info", element: 'span', attributes: {'class': 'text-info'}}
],
};
},
// TODO clean
+8 -7
View File
@@ -53,8 +53,9 @@
<html>
<head>
<title t-raw="title"><t t-esc="res_company.name"/></title>
<script type="text/javascript" src="/web/static/lib/jquery/jquery-1.8.3.js"></script>
<script type="text/javascript" src="/web/static/lib/jquery/jquery.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/ckeditor/4.2/ckeditor.js"></script>
<script type="text/javascript" src="/website/static/lib/ckeditor.sharedspace/plugin.js"></script>
<script type="text/javascript">
CKEDITOR.disableAutoInline = true;
CKEDITOR.dtd.$editable.li = 1;
@@ -198,7 +199,7 @@
<section>
<div id="myCarousel" class="carousel slide" data-interval='1000000'>
<div class="css_carousel_options js_carousel_options" t-ignore="1">
<div class="oe_carousel_options js_carousel_options" t-ignore="1">
<span class="label js_add"><i class="icon-plus-sign"></i></span>
<span class="label js_remove"><i class="icon-minus-sign"></i></span>
</div>
@@ -206,7 +207,7 @@
<div class="carousel-inner">
<div class="item active" style="background-image: url(/website/static/src/img/greenfields.jpg); background-size: cover;" >
<div class='container'>
<h1 class='mt64'>A Nice Banner</h1>
<h1 class='mt64'>A Nice Bidule</h1>
<h2>A convincing subtitle</h2>
<a href='#' class='btn btn-success btn-large mt16'>And a <em>Call To Action</em></a>
</div>
@@ -318,13 +319,13 @@
<div class="row">
<div class="span12">
<h1>404: Page not found!</h1>
<p class="oe_grey">
<p>
The page you were looking for could not be
found; it is possible you have typed the
address incorrectly, but it has most
probably been removed due to the recent
website reorganisation.
</p><p class="oe_grey">
</p><p>
Maybe you were looking for one of these
popular pages ?
</p>
@@ -335,8 +336,8 @@
</div>
</div>
<div class="row">
<div class="span12">
<a class="oe_button oe_big oe_tacky" t-att-href="'/pagenew/'+path" t-if="editable">Create Page</a>
<div class="span12 mt32">
<a class="btn btn-primary" t-att-href="'/pagenew/'+path" t-if="editable">Create Page</a>
</div>
</div>
</div>
+20 -16
View File
@@ -9,13 +9,10 @@ from openerp.addons.web.http import request
def auth_method_public():
registry = openerp.modules.registry.RegistryManager.get(request.db)
request.public_uid = None
with registry.cursor() as cr:
request.public_uid = request.registry['ir.model.data'].get_object_reference(cr, openerp.SUPERUSER_ID, 'website', 'public_user')[1]
if not request.session.uid:
request.uid = request.public_uid
else:
request.uid = request.session.uid
if not request.session.uid:
request.uid = registry['website'].get_public_user().id
else:
request.uid = request.session.uid
http.auth_methods['public'] = auth_method_public
@@ -23,14 +20,21 @@ class website(osv.osv):
_name = "website" # Avoid website.website convention for conciseness (for new api). Got a special authorization from xmo and rco
_description = "Website"
public_user = None
def get_public_user(self):
if not self.public_user:
ref = request.registry['ir.model.data'].get_object_reference(request.cr, openerp.SUPERUSER_ID, 'website', 'public_user')
self.public_user = request.registry[ref[0]].browse(request.cr, openerp.SUPERUSER_ID, ref[1])
return self.public_user
def get_rendering_context(self, additional_values=None):
debug = 'debug' in request.params
editable = False
if request.uid or (request.public_uid and request.uid != request.public_uid):
editable = True
is_public_user = request.uid == self.get_public_user().id
values = {
'debug': debug,
'editable': editable,
'is_public_user': is_public_user,
'editable': not is_public_user,
'request': request,
'registry': request.registry,
'cr': request.cr,
@@ -38,7 +42,7 @@ class website(osv.osv):
'host_url': request.httprequest.host_url,
'res_company': request.registry['res.company'].browse(request.cr, openerp.SUPERUSER_ID, 1),
}
if editable:
if values['editable']:
values.update({
'script': "\n".join(['<script type="text/javascript" src="%s"></script>' % i for i in main.manifest_list('js', db=request.db, debug=debug)]),
'css': "\n".join('<link rel="stylesheet" href="%s">' % i for i in main.manifest_list('css', db=request.db, debug=debug))
@@ -48,7 +52,7 @@ class website(osv.osv):
return values
def render(self, template, values={}):
# context = {
# 'inherit_branding': values['editable'],
# }
return request.registry.get("ir.ui.view").render(request.cr, request.uid, template, values)
context = {
'inherit_branding': values.get('editable', False),
}
return request.registry.get("ir.ui.view").render(request.cr, request.uid, template, values, context=context)
+1 -1
View File
@@ -8,7 +8,7 @@ OpenERP Blog
""",
'author': 'OpenERP SA',
'depends': ['website', 'event', 'website_sale'],
'depends': ['website', 'event_sale', 'website_sale'],
'data': [
'views/website_event.xml',
'security/ir.model.access.csv',
+3 -3
View File
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
from openerp import SUPERUSER_ID
from openerp.addons.web import http
from openerp.addons.web.http import request
from openerp.tools.translate import _
@@ -61,11 +62,10 @@ class website_event(http.Controller):
domain_search["country"] = [("country_id", "=", int(searches.get("country")))]
def dom_without(without):
domain = [(1, "=", 1)]
domain = SUPERUSER_ID != request.uid and [('website_published', '=', True)] or [(1, "=", 1)]
for key, search in domain_search.items():
if key != without:
domain += search
print domain
return domain
# count by domains without self search
@@ -96,7 +96,7 @@ class website_event(http.Controller):
@http.route(['/event/<int:event_id>'], type='http', auth="public")
def event(self, event_id=None, **post):
website = request.registry['website']
event = request.registry['event.event'].browse(request.cr, request.uid, event_id)
event = request.registry['event.event'].browse(request.cr, request.uid, event_id, {'show_address': 1})
values = website.get_rendering_context({
'event_id': event,
'google_map_url': "http://maps.googleapis.com/maps/api/staticmap?center=%s&sensor=false&zoom=12&size=298x298" % urllib.quote_plus('%s, %s %s, %s' % (event.street, event.city, event.zip, event.country_id and event.country_id.name_get()[0][1] or ''))
+15 -2
View File
@@ -8,16 +8,29 @@ class event(osv.osv):
_columns = {
'website_published': fields.boolean('Available in the website'),
'description_website': fields.html('Description for the website'),
'product_ids': fields.one2many('event.event.product', "event_id", "Event"),
'event_product_ids': fields.one2many('event.event.product', "event_id", "Event"),
'organizer_id': fields.many2one('res.partner', "Orgonizer"),
'phone': fields.related('orgonizer_id', 'phone', type='char', string='Phone'),
'email': fields.related('orgonizer_id', 'email', type='char', string='Email'),
}
class event_product(osv.osv):
_name = 'event.event.product'
_columns = {
'deadline': fields.date("Sales End"),
'event_id': fields.many2one('event.event', "Event"),
'product_id': fields.many2one('product.product', 'Product'),
'product_id': fields.many2one('product.product', 'Product', domain=[("event_type_id", "!=", False)]),
'price': fields.float('Price'),
'qty': fields.integer('Current Registrations', readonly=True),
'max_qty': fields.integer('Maximum Registrations'),
}
def onchange_product_id(self, cr, uid, ids, product_id=False, context=None):
return {'value': {'price': self.pool.get("product.product").browse(cr, uid, product_id).list_price or 0}}
class product(osv.osv):
_inherit = 'product.product'
_columns = {
'event_product_ids': fields.one2many('event.event.product', 'product_id', 'Linked event product'),
}
@@ -1,2 +1,4 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_event_event_public,event.event.public,event.model_event_event,base.group_public,1,0,0,0
access_event_event_public,event.event.public,event.model_event_event,base.group_public,1,0,0,0
access_event_event_product_public,event.event.product.public,website_event.model_event_event_product,base.group_public,1,0,0,0
access_event_product_product_public,event.product.product.public,product.model_product_product,base.group_public,1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_event_event_public event.event.public event.model_event_event base.group_public 1 0 0 0
3 access_event_event_product_public event.event.product.public website_event.model_event_event_product base.group_public 1 0 0 0
4 access_event_product_product_public event.product.product.public product.model_product_product base.group_public 1 0 0 0
@@ -11,5 +11,25 @@
<field name="perm_create" eval="False"/>
<field name="perm_unlink" eval="False"/>
</record>
<record id="event_event_product_public" model="ir.rule">
<field name="name">event product: Public</field>
<field name="model_id" ref="website_event.model_event_event_product"/>
<field name="domain_force">[('event_id.website_published', '=', True)]</field>
<field name="groups" eval="[(4, ref('base.group_public'))]"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_unlink" eval="False"/>
</record>
<record id="event_product_product_public" model="ir.rule">
<field name="name">Product linked to event: Public</field>
<field name="model_id" ref="product.model_product_product"/>
<field name="domain_force">[("event_type_id", "!=", False), ('event_product_ids.event_id.website_published', '=', True)]</field>
<field name="groups" eval="[(4, ref('base.group_public'))]"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_unlink" eval="False"/>
</record>
</data>
</openerp>
+86 -71
View File
@@ -10,17 +10,19 @@
<data>
<xpath expr="//notebook" position="inside">
<page string="Tarifs">
<group colspan="4">
<field name="product_ids">
<tree string="Payments" editable="top">
<field name="product_id"/>
<field name="price"/>
<field name="max_qty"/>
</tree>
</field>
</group>
<field name="product_ids">
<tree string="Payments" editable="bottom">
<field name="product_id" on_change='onchange_product_id(product_id)'/>
<field name="deadline"/>
<field name="price"/>
<field name="max_qty"/>
</tree>
</field>
</page>
</xpath>
<field name="address_id" position="after">
<field name="organizer_id"/>
</field>
</data>
</field>
</record>
@@ -51,19 +53,7 @@
</record>
<!-- Page -->
<template id="button">
<t t-if="event_id.register_avail">
<span t-if="event_id.register_avail == 9999" class="label pull-right">No ticket available.</span>
<span t-if="event_id.register_avail != 9999" t-att-class="'label pull-right label-%%s' %% (event_id.register_avail &lt;= 10 and 'warning' or 'info')">
<t t-if="event_id.register_avail &lt;= 10">Only</t>
<t t-esc="event_id.register_avail"/>
<t t-if="event_id.register_avail &gt; 1">tickets </t>
<t t-if="event_id.register_avail == 1">ticket </t>
available.
</span>
</t>
</template>
<template id="index">
<t t-call="website.layout">
<t t-set="head">
@@ -85,7 +75,7 @@
<ul class="nav nav-list">
<li class="nav-header">Category</li>
<t t-foreach="types">
<li t-if="type" t-att-class="searches.get('type') == str(type[0]) and 'active' or ''">
<li t-if="type" t-att-class="searches.get('type') == str(type and type[0]) and 'active' or ''">
<a t-att-href="'/event/%%s&amp;type=%%s' %% (search_path, type[0])"><t t-esc="type[1]"/> <small>(<t t-esc="type_count"/>)</small></a>
</li>
</t>
@@ -93,7 +83,7 @@
<ul class="nav nav-list">
<li class="nav-header">Location</li>
<t t-foreach="countries">
<li t-if="country_id" t-att-class="searches.get('country') == str(country_id[0]) and 'active' or ''">
<li t-if="country_id" t-att-class="searches.get('country') == str(country_id and country_id[0]) and 'active' or ''">
<a t-att-href="'/event/%%s&amp;country=%%s' %% (search_path, country_id[0])"><t t-esc="country_id[1]"/><small>(<t t-esc="country_id_count"/>)</small></a>
</li>
</t>
@@ -101,30 +91,37 @@
</div>
<div class="span8">
<ul class="media-list mt32">
<t t-foreach="event_ids" t-as="event_id">
<li class="media thumbnail">
<div class="media-body">
<t t-call="website_event.button"/>
<h4 class="media-heading"><a t-att-href="'/event/%%s' %% event_id.id"><span t-field="event_id.name"> </span></a></h4>
<a t-if="editable" href="#" t-att-data-id="event_id.id" class="pull-right">
<span t-att-class="'label label-success js_unpublish %%s' %% (not event_id.website_published and 'hidden' or '')">Click to Unpublish</span>
<span t-att-class="'label label-important js_publish %%s' %% (event_id.website_published and 'hidden' or '')">Click to Publish</span>
</a>
<div>
<span t-field="event_id.type">: </span>
<t t-if="event_id.user_id">
Organized by: <span t-field="event_id.user_id"> </span>
</t>
</div>
<div>
<i class="icon-time"></i> <span t-field="event_id.date_begin"> </span> <i>to</i> <span t-field="event_id.date_end"> </span>
</div>
<div t-if="event_id.country_id">
<i class="icon-map-marker"></i> <span t-field="event_id.city"> </span> <span t-field="event_id.zip"> </span>, <span t-field="event_id.country_id"> </span>
</div>
<li t-foreach="event_ids" t-as="event_id" class="media thumbnail">
<div class="media-body">
<t t-if="event_id.register_avail">
<span t-if="event_id.register_avail == 9999" class="label pull-right">No ticket available.</span>
<span t-if="event_id.register_avail != 9999" t-att-class="'label pull-right label-%%s' %% (event_id.register_avail &lt;= 10 and 'warning' or 'info')">
<t t-if="event_id.register_avail &lt;= 10">Only</t>
<t t-esc="event_id.register_avail"/>
<t t-if="event_id.register_avail &gt; 1">tickets </t>
<t t-if="event_id.register_avail == 1">ticket </t>
available.
</span>
</t>
<h4 class="media-heading"><a t-att-href="'/event/%%s/' %% event_id.id"><span t-field="event_id.name"> </span></a></h4>
<a t-if="editable" href="#" t-att-data-id="event_id.id" class="pull-right">
<span t-att-class="'label label-success js_unpublish %%s' %% (not event_id.website_published and 'hidden' or '')">Click to Unpublish</span>
<span t-att-class="'label label-important js_publish %%s' %% (event_id.website_published and 'hidden' or '')">Click to Publish</span>
</a>
<div>
<span t-field="event_id.type">: </span>
<t t-if="event_id.user_id">
Organized by: <span t-field="event_id.user_id"> </span>
</t>
</div>
</li>
</t>
<div>
<i class="icon-time"></i> <span t-field="event_id.date_begin"> </span> <i>to</i> <span t-field="event_id.date_end"> </span>
</div>
<div t-if="event_id.country_id">
<i class="icon-map-marker"></i> <span t-field="event_id.city"> </span> <span t-field="event_id.zip"> </span>, <span t-field="event_id.country_id"> </span>
</div>
</div>
</li>
</ul>
</div>
</div>
@@ -145,41 +142,59 @@
<h4>When &amp; Where</h4>
<img t-att-src="google_map_url"/>
<address>
<h4 t-field="event_id.address_id">Name</h4><br/>
<span t-field="event_id.street"/><br/>
<span t-field="event_id.city"/>, <span t-field="event_id.zip"/><br/>
<span t-field="event_id.country_id"> </span><br/>
<pre t-field="event_id.address_id"/>
<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><br/>
<br/>
<i class="icon-time"></i> <span t-field="event_id.date_end"> </span>
<t t-if="event_id.user_id">
Organized by: <span t-field="event_id.user_id"/><br/>
<span>&amp;#x2706; <span t-field="event_id.user_id.phone"></span></span><br/>
<i class="icon-envelope"></i> <span t-field="event_id.user_id.email"></span>
<h6>Organized by:</h6>
<pre><t t-field="event_id.organizer_id"/><br/><span>&amp;#x2706;</span> <span t-field="event_id.phone"></span><br/><i class="icon-envelope"></i> <span t-field="event_id.email"></span></pre>
</t>
</address>
</div>
<div class="span8">
<div class="media-body">
<t t-call="website_event.button"/>
<h4 class="media-heading"><a t-att-href="'/event/%%s' %% event_id.id"><span t-field="event_id.name"> </span></a></h4>
<t t-if="event_id.register_avail">
<span t-if="event_id.register_avail == 9999" class="label pull-right">No ticket available.</span>
<span t-if="event_id.register_avail != 9999" t-att-class="'label pull-right label-%%s' %% (event_id.register_avail &lt;= 10 and 'warning' or 'info')">
<t t-if="event_id.register_avail &lt;= 10">Only</t>
<t t-esc="event_id.register_avail"/>
<t t-if="event_id.register_avail &gt; 1">tickets </t>
<t t-if="event_id.register_avail == 1">ticket </t>
available.
</span>
</t>
<h4 class="media-heading"><a t-att-href="'/event/%%s/' %% event_id.id"><span t-field="event_id.name"> </span></a></h4>
<h5 class="media-heading">
<span t-field="event_id.address_id"/><br/>
<i class="icon-time"></i> <span t-field="event_id.date_begin"/><br/>
<i class="icon-time"></i> <span t-field="event_id.date_end"/>
</h5>
<a t-if="editable" href="#" t-att-data-id="event_id.id" class="pull-right">
<span t-att-class="'label label-success js_unpublish %%s' %% (not event_id.website_published and 'hidden' or '')">Click to Unpublish</span>
<span t-att-class="'label label-important js_publish %%s' %% (event_id.website_published and 'hidden' or '')">Click to Publish</span>
</a>
<h4>Ticket Information</h4>
<form t-att-action="'/event/%%s/add_cart' %% event_id.id" method="post">
<div t-foreach="event_id.product_ids" t-as="prod">
<span t-field="prod.product_id"/>
<span t-field="prod.price"/>
<span t-field="prod.qty"/>
<span t-field="prod.max_qty"/>
<select t-att-name="'product[%%s]' %% prod.id">
<t t-foreach="range(0,10)" t-as="nb">
<option t-esc="nb"/>
</t>
</select>
</div>
<h4 t-if="event_id.event_product_ids">Ticket Information</h4>
<form t-att-action="'/event/%%s/add_cart' %% event_id.id" method="post" t-if="event_id.event_product_ids">
<table class="table">
<tr>
<th>Ticket type</th>
<th>Sales End</th>
<th>Price</th>
<th>Seats</th>
<th>Quantity</th>
</tr>
<tr t-foreach="event_id.event_product_ids" t-as="prod">
<td t-field="prod.product_id"/>
<td t-field="prod.deadline"/>
<td t-field="prod.price"/>
<td><span t-if="prod.max_qty"><t t-esc="prod.qty"/>/<t t-field="prod.max_qty"/></span></td>
<td>
<select t-att-name="'product[%%s]' %% prod.id">
<t t-foreach="range(0,10)" t-as="nb"><option t-esc="nb"/></t>
</select>
</td>
</tr>
</table>
<button type="submit" class="btn btn-primary">Order Now</button>
</form>
<h4>Event Details</h4>
-1
View File
@@ -7,6 +7,5 @@ class hr(osv.osv):
_inherit = 'hr.employee'
_columns = {
'website_published': fields.boolean('Available in the website'),
'website_published_on_contact_form': fields.boolean('Publish', help="Publish also on contact form"),
}
-16
View File
@@ -15,20 +15,4 @@ $(document).ready(function () {
}
});
});
$(document).on('click', '.js_publish_contact, .js_unpublish_contact', function (e) {
e.preventDefault();
var $link = $(this).parent();
$link.find('.js_publish_contact, .js_unpublish_contact').addClass("hidden");
var $unp = $link.find(".js_unpublish_contact");
var $p = $link.find(".js_publish_contact");
$.post('/hr/publish_contact', {'id': $link.data('id')}, function (result) {
if (+result) {
$p.addClass("hidden");
$unp.removeClass("hidden");
} else {
$p.removeClass("hidden");
$unp.addClass("hidden");
}
});
});
});
+19 -26
View File
@@ -27,35 +27,28 @@
<t t-set="title">Team</t>
<div class="container">
<div class="thumbnails">
<t t-foreach="employee_ids" t-as="employee_id">
<div class="span4 mt16">
<div class="media thumbnail">
<a class="pull-left" href="#">
<img class="media-object" t-att-src="'data:image/png;base64,%%s' %% employee_id.image_small"/>
</a>
<div class="media-body">
<t t-if="editable">
<div class="pull-right">
<a href="#" t-att-data-id="employee_id.id">
<span t-att-class="'label label-success js_unpublish %%s' %% (not employee_id.website_published and 'hidden' or '')">Click to Unpublish</span>
<span t-att-class="'label label-important js_publish %%s' %% (employee_id.website_published and 'hidden' or '')">Click to Publish</span>
</a><br/>
<a href="#" t-att-data-id="employee_id.id">
<span t-att-class="'label label-success js_unpublish_contact %%s' %% (not employee_id.website_published and 'hidden' or '')">hidden on Contacts</span>
<span t-att-class="'label label-important js_publish_contact %%s' %% (employee_id.website_published and 'hidden' or '')">display in Contacts</span>
</a>
</div>
</t>
<h5 class="media-heading"><t t-esc="employee_id.name"/></h5>
<div t-record="employee_id" t-field="department_id"> </div>
<div t-record="employee_id" t-field="job_id"> </div>
<div t-record="employee_id" t-field="work_location"> </div>
<div t-record="employee_id" t-field="work_phone"> </div>
<div t-record="employee_id" t-field="work_email"> </div>
<div t-foreach="employee_ids" t-as="employee_id" class="span4 mt16">
<div class="media thumbnail">
<a class="pull-left" href="#">
<img class="media-object" t-att-src="'data:image/png;base64,%%s' %% employee_id.image_small"/>
</a>
<div class="media-body">
<div t-if="editable" class="pull-right">
<a href="#" t-att-data-id="employee_id.id">
<span t-att-class="'label label-success js_unpublish %%s' %% (not employee_id.website_published and 'hidden' or '')">Click to Unpublish</span>
<span t-att-class="'label label-important js_publish %%s' %% (employee_id.website_published and 'hidden' or '')">Click to Publish</span>
</a>
</div>
<h5 class="media-heading" t-field="employee_id.name"/>
<div t-field="employee_id.department_id"/>
<div t-field="employee_id.job_id"/>
<div t-field="employee_id.work_location"/>
<div t-field="employee_id.work_phone"/>
<div t-field="employee_id.work_email"/>
<div t-field="employee_id.public_info"/>
</div>
</div>
</t>
</div>
</div>
</div>
</t>
+53 -5
View File
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
from openerp import SUPERUSER_ID
from openerp.addons.web import http
from openerp.addons.web.http import request
import werkzeug
@@ -12,11 +13,12 @@ _months = {1:_("January"), 2:_("February"), 3:_("March"), 4:_("April"), 5:_("May
class website_mail(http.Controller):
@http.route(['/blog', '/blog/<int:mail_group_id>', '/blog/<int:mail_group_id>/<int:blog_id>'], type='http', auth="public")
@http.route(['/blog', '/blog/<int:mail_group_id>/', '/blog/<int:mail_group_id>/<int:blog_id>/'], type='http', auth="public")
def blog(self, mail_group_id=None, blog_id=None, **post):
website = request.registry['website']
group_obj = request.registry['mail.group']
message_obj = request.registry['mail.message']
user_obj = request.registry['res.users']
values = website.get_rendering_context({
'blog_ids': None,
@@ -25,7 +27,15 @@ class website_mail(http.Controller):
'prev_date': None,
'next_date': None,
'mail_group_id': mail_group_id,
'subscribe': post.get('subscribe'),
'website': website,
})
if request.uid != website.get_public_user().id and mail_group_id:
message_follower_ids = group_obj.read(request.cr, request.uid, [mail_group_id], ['message_follower_ids'])[0]['message_follower_ids']
parent_id = user_obj.browse(request.cr, SUPERUSER_ID, request.uid).partner_id.id
values['subscribe'] = parent_id in message_follower_ids
domain = mail_group_id and [("res_id", "=", mail_group_id)] or []
for group in message_obj.read_group(request.cr, request.uid, domain + group_obj.get_public_blog(request.cr, request.uid), ['subject', 'date'], groupby="date", orderby="create_date asc"):
@@ -70,10 +80,11 @@ class website_mail(http.Controller):
@http.route(['/blog/<int:mail_group_id>/<int:blog_id>/post'], type='http', auth="public")
def blog_post(self, mail_group_id=None, blog_id=None, **post):
website = request.registry['website']
url = request.httprequest.host_url
if post.get('body'):
request.session.body = post.get('body')
if not request.uid != request.public_uid:
if request.uid == website.get_public_user().id:
return '%s/admin#action=redirect&url=%s/blog/%s/%s/post' % (url, url, mail_group_id, blog_id)
if 'body' in request.session and request.session.body:
@@ -88,9 +99,9 @@ class website_mail(http.Controller):
request.session.body = False
if post.get('body'):
return '%s/blog/%s/%s' % (url, mail_group_id, blog_id)
return '%s/blog/%s/%s/' % (url, mail_group_id, blog_id)
else:
return werkzeug.utils.redirect("/blog/%s/%s" % (mail_group_id, blog_id))
return werkzeug.utils.redirect("/blog/%s/%s/" % (mail_group_id, blog_id))
@http.route(['/blog/<int:mail_group_id>/new'], type='http', auth="public")
def new_blog_post(self, mail_group_id=None, **post):
@@ -102,4 +113,41 @@ class website_mail(http.Controller):
subtype='mt_comment',
context={'mail_create_nosubsrequest.cribe': True},
)
return werkzeug.utils.redirect("/blog/%s/%s" % (mail_group_id, blog_id))
return werkzeug.utils.redirect("/blog/%s/%s/" % (mail_group_id, blog_id))
@http.route(['/blog/<int:mail_group_id>/subscribe', '/blog/<int:mail_group_id>/<int:blog_id>/subscribe'], type='http', auth="public")
def subscribe(self, mail_group_id=None, blog_id=None, **post):
website = request.registry['website']
partner_obj = request.registry['res.partner']
group_obj = request.registry['mail.group']
user_obj = request.registry['res.users']
if mail_group_id and 'subscribe' in post and (post.get('email') or request.uid != website.get_public_user().id):
if request.uid == website.get_public_user().id:
partner_ids = partner_obj.search(request.cr, SUPERUSER_ID, [("email", "=", post.get('email'))])
if not partner_ids:
partner_ids = [partner_obj.create(request.cr, SUPERUSER_ID, {"email": post.get('email'), "name": "Subscribe: %s" % post.get('email')})]
else:
partner_ids = [user_obj.browse(request.cr, request.uid, request.uid).partner_id.id]
group_obj.check_access_rule(request.cr, request.uid, [mail_group_id], 'read')
group_obj.message_subscribe(request.cr, SUPERUSER_ID, [mail_group_id], partner_ids)
return self.blog(mail_group_id=mail_group_id, blog_id=blog_id, subscribe=post.get('email'))
@http.route(['/blog/<int:mail_group_id>/unsubscribe', '/blog/<int:mail_group_id>/<int:blog_id>/unsubscribe'], type='http', auth="public")
def unsubscribe(self, mail_group_id=None, blog_id=None, **post):
website = request.registry['website']
partner_obj = request.registry['res.partner']
group_obj = request.registry['mail.group']
user_obj = request.registry['res.users']
if mail_group_id and 'unsubscribe' in post and (post.get('email') or request.uid != website.get_public_user().id):
if request.uid == website.get_public_user().id:
partner_ids = partner_obj.search(request.cr, SUPERUSER_ID, [("email", "=", post.get('email'))])
else:
partner_ids = [user_obj.browse(request.cr, request.uid, request.uid).partner_id.id]
group_obj.check_access_rule(request.cr, request.uid, [mail_group_id], 'read')
group_obj.message_unsubscribe(request.cr, SUPERUSER_ID, [mail_group_id], partner_ids)
return self.blog(mail_group_id=mail_group_id, blog_id=blog_id, subscribe=None)
+60 -58
View File
@@ -18,7 +18,7 @@
<field name="arch" type="xml">
<data>
<xpath expr="//li[last()]" position="after">
<li class="pull-right"><a href="/blog/%(website_mail.website_mail_blog)d">News</a></li>
<li class="pull-right"><a href="/blog/%(website_mail.website_mail_blog)d/">News</a></li>
</xpath>
</data>
</field>
@@ -29,7 +29,7 @@
<field name="arch" type="xml">
<data>
<xpath expr="//a[@href='/page/website.news']" position="replace">
<a href="/blog/%(website_mail.website_mail_blog)d">News</a>
<a href="/blog/%(website_mail.website_mail_blog)d/">News</a>
</xpath>
</data>
</field>
@@ -50,20 +50,27 @@
<div class="span4">
<ul class="nav nav-list">
<a t-if="mail_group_id and editable" t-att-href="'/blog/%%s/new' %% mail_group_id" class="btn">Add a new Blog</a>
<li class="nav-header">BLOG ARCHIVE</li>
<li class="nav-header"><a t-att-href="'/blog/%%s/' %% mail_group_id">BLOG ARCHIVE</a></li>
<!-- TODO: check qweb iteration -->
<t t-foreach="nav_list" t-as="year">
<li t-foreach="nav_list" t-as="year" class="js_nav_year">
<t t-set="year" t-value="nav_list[year]"/>
<li class="js_nav_year"><a href="#"><t t-esc="year['name']"/> <small>(<t t-esc="year['date_count']"/>)</small></a>
<ul class="nav nav-list css_nav_month">
<t t-foreach="year['months']">
<li class="js_nav_month"><a href="#" t-att-data-domain="__domain"><t t-esc="date"/> <small>(<t t-esc="date_count"/>)</small></a>
<ul class="nav nav-list"/>
</li>
</t>
</ul>
</li>
</t>
<a href="#"><t t-esc="year['name']"/> <small>(<t t-esc="year['date_count']"/>)</small></a>
<ul class="nav nav-list css_nav_month">
<t t-foreach="year['months']">
<li class="js_nav_month"><a href="#" t-att-data-domain="__domain"><t t-esc="date"/> <small>(<t t-esc="date_count"/>)</small></a>
<ul class="nav nav-list"/>
</li>
</t>
</ul>
</li>
<form action="./subscribe" method="POST" class="form-inline" t-if="not subscribe">
<input placeholder="Email Address" type="email" name="email" class="input-medium" t-if="is_public_user"/>
<button type="submit" class="btn btn-primary" name="subscribe">Subscribe</button>
</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" name="unsubscribe">Unsubscribe</button>
</form>
</ul>
</div>
<div class="span8" t-if="blog_id">
@@ -73,61 +80,56 @@
<span t-att-class="'label label-success js_unpublish %%s' %% (not blog_id.website_published and 'hidden' or '')">Click to Unpublish</span>
<span t-att-class="'label label-important js_publish %%s' %% (blog_id.website_published and 'hidden' or '')">Click to Publish</span>
</a>
<h3 t-field="blog_id.subject"></h3>
<div t-field="blog_id.body"></div>
<h3 t-field="blog_id.subject"/>
<div t-field="blog_id.body"/>
<small class="pull-right muted text-right">
<div><t t-field="blog_id.author_id"/></div>
<div><t t-field="blog_id.date"/></div>
<div t-field="blog_id.author_id"/>
<div t-field="blog_id.date"/>
</small>
</div>
<ul class="media-list">
<t t-foreach="blog_id.child_ids" t-as="comment">
<!-- TODO: check qweb iteration -->
<li class="media">
<div class="media-body">
<a href="#" t-att-data-id="blog_id.id" class="pull-right" t-if="editable">
<span t-att-class="'label label-success js_unpublish %%s' %% (not comment.website_published and 'hidden' or '')">Click to Unpublish</span>
<span t-att-class="'label label-important js_publish %%s' %% (comment.website_published and 'hidden' or '')">Click to Publish</span>
</a>
<t t-raw="comment.body"/>
<small class="pull-right muted text-right">
<div><t t-esc="comment.author_id"/></div>
<div><t t-esc="comment.date"/></div>
</small>
</div>
</li>
</t>
<ul class="media-list" id="comment">
<li t-foreach="blog_id.child_ids" t-as="comment" class="media">
<div class="media-body">
<a href="#" t-att-data-id="blog_id.id" class="pull-right" t-if="editable">
<span t-att-class="'label label-success js_unpublish %%s' %% (not comment.website_published and 'hidden' or '')">Click to Unpublish</span>
<span t-att-class="'label label-important js_publish %%s' %% (comment.website_published and 'hidden' or '')">Click to Publish</span>
</a>
<t t-raw="comment.body"/>
<small class="pull-right muted text-right">
<div t-field="comment.author_id"/>
<div t-field="comment.date"/>
</small>
</div>
</li>
<form id="post" t-att-action="'/blog/%%s/%%s/post#post' %% (blog_id.res_id, blog_id.id)" method="POST" class="form-horizontal text-center" groups="group_website_mail_reply">
<textarea rows="4" placeholder="Your message" class="span7"> </textarea>
<button type="submit" class="btn">Post your message</button>
<textarea rows="4" placeholder="Your comment" class="span7"> </textarea>
<button type="submit" class="btn">Post your comment</button>
</form>
</ul>
</div>
</div>
<div class="span8" t-if="not blog_id and blog_ids">
<ul class="media-list">
<t t-foreach="blog_ids" t-as="blog">
<li class="media well">
<div t-att-class="'media-body %%s' %% (blog.website_published and 'css_published' or '')">
<a href="#" t-att-data-id="blog.id" class="pull-right" t-if="editable">
<span t-att-class="'label label-success js_unpublish %%s' %% (not blog.website_published and 'hidden' or '')">Click to Unpublish</span>
<span t-att-class="'label label-important js_publish %%s' %% (blog.website_published and 'hidden' or '')">Click to Publish</span>
</a>
<h4 class="media-heading" ><a t-att-href="'/blog/%%s/%%s' %% (blog.res_id, blog.id)" t-field="blog.subject"></a></h4>
<div class="media">
<div t-field="blog.body"></div>
<small class="pull-left muted text-right" t-if="len(blog.child_ids)">
<a t-if="len(blog.child_ids) &lt;= 1" t-att-href="'/blog/%%s/%%s' %% (blog.res_id, blog.id)"><t t-esc="len(blog.child_ids)"/> Message</a>
<a t-if="len(blog.child_ids) > 1" t-att-href="'/blog/%%s/%%s' %% (blog.res_id, blog.id)"><t t-esc="len(blog.child_ids)"/> Messages</a>
</small>
<small class="pull-right muted text-right">
<div><t t-field="blog.author_id"/></div>
<div><t t-field="blog.date"/></div>
</small>
</div>
<li t-foreach="blog_ids" t-as="blog" class="media well">
<div t-att-class="'media-body %%s' %% (blog.website_published and 'css_published' or '')">
<a href="#" t-att-data-id="blog.id" class="pull-right" t-if="editable">
<span t-att-class="'label label-success js_unpublish %%s' %% (not blog.website_published and 'hidden' or '')">Click to Unpublish</span>
<span t-att-class="'label label-important js_publish %%s' %% (blog.website_published and 'hidden' or '')">Click to Publish</span>
</a>
<h4 class="media-heading" ><a t-att-href="'/blog/%%s/%%s#comment' %% (blog.res_id, blog.id)" t-field="blog.subject"></a></h4>
<div class="media">
<div t-field="blog.body"/>
<small class="pull-left muted text-right" t-if="len(blog.child_ids)">
<a t-if="len(blog.child_ids) &lt;= 1" t-att-href="'/blog/%%s/%%s#comment' %% (blog.res_id, blog.id)"><t t-esc="len(blog.child_ids)"/> Comment</a>
<a t-if="len(blog.child_ids) > 1" t-att-href="'/blog/%%s/%%s#comment' %% (blog.res_id, blog.id)"><t t-esc="len(blog.child_ids)"/> Comments</a>
</small>
<small class="pull-right muted text-right">
<div t-field="blog.author_id"/>
<div t-field="blog.date"/>
</small>
</div>
</li>
</t>
</div>
</li>
</ul>
<ul class="pager">
<li t-if="next_date" class="previous">
+79 -14
View File
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
import math
import openerp
import simplejson
from openerp.osv import osv
@@ -17,9 +18,7 @@ def get_order(order_id=None):
if not order_id:
fields = [k for k, v in order_obj._columns.items()]
order_value = order_obj.default_get(request.cr, openerp.SUPERUSER_ID, fields)
order_value['partner_id'] = openerp.SUPERUSER_ID != request.public_uid and \
request.registry.get('res.users').browse(request.cr, openerp.SUPERUSER_ID, request.uid).partner_id.id or \
None
order_value['partner_id'] = request.registry.get('res.users').browse(request.cr, openerp.SUPERUSER_ID, request.uid).partner_id.id
order_value.update(order_obj.onchange_partner_id(request.cr, openerp.SUPERUSER_ID, [], request.uid, context={})['value'])
order_id = order_obj.create(request.cr, openerp.SUPERUSER_ID, order_value)
return order_obj.browse(request.cr, openerp.SUPERUSER_ID, order_id)
@@ -49,9 +48,47 @@ class website(osv.osv):
class Ecommerce(http.Controller):
def get_categories(self):
category_obj = request.registry.get('pos.category')
category_ids = category_obj.search(request.cr, openerp.SUPERUSER_ID, [('parent_id', '=', False)])
categories = category_obj.browse(request.cr, openerp.SUPERUSER_ID, category_ids)
print categories
return categories
def get_current_order(self):
order = self.get_order(request.httprequest.session.get('ecommerce_order_id'))
request.httprequest.session['ecommerce_order_id'] = order.id
return order
def get_order(self, order_id=None):
order_obj = request.registry.get('sale.order')
# check if order allready exists
if order_id:
try:
order_obj.browse(request.cr, openerp.SUPERUSER_ID, order_id).pricelist_id
except:
order_id = None
if not order_id:
fields = [k for k, v in order_obj._columns.items()]
order_value = order_obj.default_get(request.cr, openerp.SUPERUSER_ID, fields)
order_value['partner_id'] = request.registry.get('res.users').browse(request.cr, openerp.SUPERUSER_ID, request.uid).partner_id.id
order_value.update(order_obj.onchange_partner_id(request.cr, openerp.SUPERUSER_ID, [], request.uid, context={})['value'])
order_id = order_obj.create(request.cr, openerp.SUPERUSER_ID, order_value)
return order_obj.browse(request.cr, openerp.SUPERUSER_ID, order_id)
def render(self, template, values={}):
_values = {
'order': self.get_current_order(),
'categories': self.get_categories(),
}
_values.update(values)
return website.render(template, _values)
def recommended_product(self, my_pids):
if not my_pids:
return []
product_obj = request.registry.get('product.product')
my_pids = str(my_pids)[1:-1]
product_ids = []
@@ -69,26 +106,55 @@ class Ecommerce(http.Controller):
request.cr.execute(query)
for p in request.cr.fetchall():
product_ids.append(p[0])
return request.registry.get('product.product').browse(request.cr, request.uid, product_ids)
@http.route(['/shop', '/shop/category/<cat_id>'], type='http', auth="public")
def category(self, cat_id=0, offset=0, **post):
# search to apply access rules
product_ids = product_obj.search(request.cr, request.uid, [("id", "in", product_ids)])
return product_obj.browse(request.cr, request.uid, product_ids)
@http.route(['/shop', '/shop/category/<cat_id>', '/shop/category/<cat_id>/page/<page>', '/shop/page/<page>'], type='http', auth="public")
def category(self, cat_id=0, page=0, **post):
website = request.registry['website']
product_obj = request.registry.get('product.product')
domain = [("sale_ok", "=", True)]
if post.get("search"):
domain += ['|', '|', ('name', 'ilike', "%%%s%%" % post.get("search")), ('desrequest.cription', 'ilike', "%%%s%%" % post.get("search")), ('pos_categ_id.name', 'ilike', "%%%s%%" % post.get("search"))]
if openerp.SUPERUSER_ID != request.uid:
domain += [('website_published', '=', True)]
if cat_id:
cat_id = cat_id and int(cat_id) or 0
cat_id = int(cat_id)
domain = [('pos_categ_id.id', 'child_of', cat_id)] + domain
product_obj = request.registry.get('product.product')
product_count = len(product_obj.search(request.cr, request.uid, domain))
page_count = int(math.ceil(product_count / 20.0))
#if post.get("search"):
# domain += ['|', '|', ('name', 'ilike', "%%%s%%" % post.get("search")), ('description', 'ilike', "%%%s%%" % post.get("search")), ('pos_categ_id.name', 'ilike', "%%%s%%" % post.get("search"))]
page = max(1,min(int(page),page_count))
offset = (page-1) * 20
if page_count <= 5 or page <= 3:
pmin = 1
pmax = min(page_count,5)
elif page >= page_count - 2:
pmin = page_count - 4
pmax = page_count
else:
pmin = page - 2
pmax = page + 2
pages = range(pmin, pmax+1)
product_ids = product_obj.search(request.cr, request.uid, domain, limit=20, offset=offset)
values = website.get_rendering_context({
'current_category': cat_id,
'products': product_obj.browse(request.cr, request.uid, product_ids),
'search': post.get("search"),
'page_count': page_count,
'pages': pages,
'page': page,
})
return website.render("website_sale.products", values)
@@ -134,7 +200,6 @@ class Ecommerce(http.Controller):
values = website.get_rendering_context()
context = {}
order_obj = request.registry.get('sale.order')
order_line_obj = request.registry.get('sale.order.line')
user_obj = request.registry.get('res.users')
@@ -196,8 +261,7 @@ class Ecommerce(http.Controller):
country_state_obj = request.registry.get('res.country.state')
payment_obj = request.registry.get('portal.payment.acquirer')
if request.uid != request.public_uid:
if request.uid != website.get_public_user().id:
values['partner'] = user_obj.browse(request.cr, request.uid, request.uid).partner_id
shipping_ids = partner_obj.search(request.cr, request.uid, [("parent_id", "=", values['partner'].id), ('type', "=", 'delivery')])
values['shipping'] = None
@@ -217,6 +281,7 @@ class Ecommerce(http.Controller):
@http.route(['/shop/confirm_order'], type='http', auth="public")
def confirm_order(self, **post):
website = request.registry['website']
order = get_current_order()
json = {'error': [], 'validation': False}
@@ -260,7 +325,7 @@ class Ecommerce(http.Controller):
'country_id': post['country_id'],
'state_id': post['state_id'],
}
if request.uid != request.public_uid:
if request.uid != website.get_public_user().id:
partner_id = user_obj.browse(request.cr, request.uid, request.uid).partner_id.id
partner_obj.write(request.cr, request.uid, [partner_id], partner_value)
else:
+1
View File
@@ -7,4 +7,5 @@ class product_pricelist(osv.osv):
_inherit = "product.product"
_columns = {
'website_published': fields.boolean('Available in the website'),
'description_website': fields.html('Description for the website'),
}
+1 -1
View File
@@ -1,2 +1,2 @@
sass:
sass --compass --trace -t expanded ecommerce.sass ecommerce.css
sass --compass --trace -t expanded --watch ecommerce.sass:ecommerce.css
@@ -1,200 +0,0 @@
.oe_ecommerce .oe_total {
font-size: 13px;
margin-top: 10px;
}
.oe_ecommerce .oe_total td {
padding: 5px 10px;
}
.oe_ecommerce .oe_total table {
width: auto;
}
.oe_ecommerce .oe_total td:last-child {
text-align: right;
}
.oe_ecommerce .oe_total th:last-child {
text-align: center;
}
.oe_ecommerce .oe_products .oe_product {
text-align: center;
display: inline-block;
padding: 4px;
width: 180px;
height: 220px;
margin-right: 15px;
margin-left: 3px;
padding-top: 8px;
}
.oe_ecommerce .oe_products .oe_product .oe_hidden {
visibility: hidden;
}
.oe_ecommerce .oe_products .oe_product .pull-left {
margin: 0;
float: none;
}
.oe_ecommerce .oe_products .oe_product .oe_ecommerce_description {
display: none;
}
.oe_ecommerce .oe_products .oe_product h4 {
text-align: center;
text-shadow: 0px 1px 1px rgba(200, 200, 200, 0.2);
margin-bottom: 16px;
}
.oe_ecommerce .oe_products .oe_product img {
max-height: 110px;
max-width: 130px;
margin: 0 auto;
padding-bottom: 14px;
}
.oe_ecommerce .oe_products .oe_product:nth-child(3n) {
margin-right: 0;
}
.oe_ecommerce .oe_products .oe_product .oe_ecommerce_price {
width: 100%;
position: absolute;
bottom: 44px;
text-shadow: 0px 1px 3px rgba(255, 255, 255, 0.7);
text-align: center;
font-size: 25px;
}
.oe_ecommerce .oe_products .oe_product .oe_ecommerce_price span {
font-weight: bold;
}
.oe_ecommerce .oe_products .oe_product .oe_button_cart {
bottom: 5px;
left: 0;
}
.oe_ecommerce .oe_products .oe_product .oe_button_cart .btn-inverse {
display: none;
}
.oe_ecommerce .oe_mycart .oe_product {
display: inline-block;
width: 250px;
margin-left: 0px;
float: none;
margin-right: 16px;
padding: 8px 5px 6px 10px;
}
.oe_ecommerce .oe_mycart .oe_product > .pull-left {
width: 84px;
height: 64px;
}
.oe_ecommerce .oe_mycart .oe_product > .pull-left img {
max-width: 64px;
max-height: 64px;
margin: auto;
}
.oe_ecommerce .oe_mycart .oe_product .oe_button_cart {
position: static;
right: 6px;
top: 6px;
}
.oe_ecommerce .oe_mycart form input {
margin-bottom: 0;
}
.oe_ecommerce .oe_product {
vertical-align: top;
position: relative;
margin-top: 0;
margin-bottom: 15px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
-ms-border-radius: 5px;
-o-border-radius: 5px;
border-radius: 5px;
border: 1px solid rgba(0, 0, 0, 0.1);
-webkit-box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.1);
-moz-box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.1);
box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.1);
}
.oe_ecommerce .oe_button_cart {
width: 100%;
font-size: 11px;
position: absolute;
}
.oe_ecommerce .oe_button_cart button {
text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.44);
overflow: hidden;
text-align: center;
font-size: 12px;
margin: 0 auto;
margin-bottom: 5px;
padding: 2px;
height: 22px;
position: relative;
}
.oe_ecommerce .oe_button_cart button.btn-inverse {
background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #aaaaaa), color-stop(100%, #999999));
background: -webkit-linear-gradient(#aaaaaa, #999999);
background: -moz-linear-gradient(#aaaaaa, #999999);
background: -o-linear-gradient(#aaaaaa, #999999);
background: linear-gradient(#aaaaaa, #999999);
}
.oe_ecommerce .oe_button_cart button.btn-primary {
background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #0088cc), color-stop(100%, #0076b1));
background: -webkit-linear-gradient(#0088cc, #0076b1);
background: -moz-linear-gradient(#0088cc, #0076b1);
background: -o-linear-gradient(#0088cc, #0076b1);
background: linear-gradient(#0088cc, #0076b1);
}
.oe_ecommerce .oe_button_cart button.btn-success {
background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #51a351), color-stop(100%, #418541));
background: -webkit-linear-gradient(#51a351, #418541);
background: -moz-linear-gradient(#51a351, #418541);
background: -o-linear-gradient(#51a351, #418541);
background: linear-gradient(#51a351, #418541);
}
.oe_ecommerce .oe_search form {
width: 100%;
margin: 24px;
text-align: center;
}
.oe_ecommerce .oe_product_detail .oe_button_cart {
position: relative;
text-align: right;
}
.oe_ecommerce .oe_recommended a {
margin: 0 3px;
}
.oe_ecommerce .oe_recommended img {
max-width: 64px;
max-height: 64px;
}
.oe_ecommerce .oe_checkout h4 {
border-bottom: 1px solid #dddddd;
margin-right: 30px;
}
.oe_ecommerce .oe_checkout input:not([type="radio"]):not([type="checkbox"]):not([type="image"]) {
height: 20px;
}
.oe_ecommerce .oe_checkout input[type="image"] {
height: 30px;
}
.oe_ecommerce .oe_checkout label > input:not([type="radio"]):not([type="checkbox"]), .oe_ecommerce .oe_checkout label > div, .oe_ecommerce .oe_checkout label > select {
display: block;
margin-top: 3px;
}
.oe_ecommerce .oe_checkout label select {
margin-top: 3px;
}
.oe_ecommerce .oe_checkout label > div > input {
margin-bottom: 0;
}
.oe_ecommerce .oe_checkout .css_payments {
clear: both;
}
.oe_ecommerce .oe_checkout .css_payments .css_payment {
position: relative;
width: 80px;
overflow: hidden;
height: 30px;
text-align: center;
padding: 10px 10px 0 0;
}
.oe_ecommerce .oe_checkout .css_payments .css_error_payment {
width: 100%;
height: 100%;
position: absolute;
top: +O;
left: 0;
cursor: pointer;
}
@@ -1,156 +0,0 @@
@import "compass/css3"
.oe_ecommerce
.oe_total
font-size: 13px
margin-top: 10px
td
padding: 5px 10px
table
width: auto
td:last-child
text-align: right
th:last-child
text-align: center
.oe_products
.oe_product
.oe_hidden
visibility: hidden
.pull-left
margin: 0
float: none
.oe_ecommerce_description
display: none
h4
text-align: center
+text-shadow(0px 1px 1px rgba(200, 200, 200,.2))
margin-bottom: 16px
img
max-height: 110px
max-width: 130px
margin: 0 auto
padding-bottom: 14px
text-align: center
display: inline-block
padding: 4px
width: 180px
height: 220px
margin-right: 15px
margin-left: 3px
padding-top: 8px
&:nth-child(3n)
margin-right: 0
.oe_ecommerce_price
width: 100%
position: absolute
bottom: 44px
+text-shadow(0px 1px 3px rgba(255, 255, 255, 0.7))
text-align: center
font-size: 25px
span
font-weight: bold
.oe_button_cart
bottom: 5px
left: 0
.btn-inverse
display: none
.oe_mycart
.oe_product
display: inline-block
width: 250px
margin-left: 0px
float: none
margin-right: 16px
padding: 8px 5px 6px 10px
> .pull-left
width: 84px
height: 64px
img
max-width: 64px
max-height: 64px
margin: auto
.oe_button_cart
position: static
right: 6px
top: 6px
form
input
margin-bottom: 0
.oe_product
vertical-align: top
position: relative
margin-top: 0
margin-bottom: 15px
+border-radius(5px)
border: 1px solid rgba(0,0,0,.1)
+box-shadow(0px 1px 3px rgba(0,0,0,.1))
.oe_button_cart
width: 100%
font-size: 11px
position: absolute
button
+text-shadow(0px 1px 1px rgba(0, 0, 0, 0.44))
overflow: hidden
text-align: center
font-size: 12px
margin: 0 auto
margin-bottom: 5px
padding: 2px
height: 22px
position: relative
&.btn-inverse
@include background(linear-gradient(#aaaaaa,#999999))
&.btn-primary
@include background(linear-gradient(#0088cc,#0076b1))
&.btn-success
@include background(linear-gradient(#51a351, #418541))
.oe_search
form
width: 100%
margin: 24px
text-align: center
.oe_product_detail
.oe_button_cart
position: relative
text-align: right
.oe_recommended
a
margin: 0 3px
img
max-width: 64px
max-height: 64px
.oe_checkout
.css_required
input, select
//background-color: #d2d2ff !important
h4
border-bottom: 1px solid #ddd
margin-right: 30px
input:not([type="radio"]):not([type="checkbox"]):not([type="image"])
height: 20px
input[type="image"]
height: 30px
label
> input:not([type="radio"]):not([type="checkbox"]), > div, > select
display: block
margin-top: 3px
select
margin-top: 3px
> div > input
margin-bottom: 0
.css_payments
clear: both
.css_payment
position: relative
width: 80px
overflow: hidden
height: 30px
text-align: center
padding: 10px 10px 0 0
.css_error_payment
width: 100%
height: 100%
position: absolute
top: +O
left: +0
cursor: pointer
@@ -30,7 +30,7 @@ $(document).ready(function () {
.html(quantity);
$add.toggleClass('btn-primary', !quantity)
.toggleClass('btn-success', !!quantity);
$remove.toggleClass('oe_hidden', !quantity);
$remove.toggleClass('hidden', !quantity);
if ($('.oe_mycart').size() && !quantity) {
$product.remove()
}
@@ -65,4 +65,4 @@ $(document).ready(function () {
}
});
});
});
});
+108 -70
View File
@@ -54,17 +54,8 @@
<t t-set="title">Shop - <t t-raw="title">Categories</t></t>
<div class="container mt48 oe_ecommerce">
<div class="row">
<div class="span4 css_noprint">
<ul class="nav nav-list">
<t t-foreach="website_sale_get_categories()" t-as="category">
<t t-call="website_sale.categories_recursive"/>
</t>
</ul>
</div>
<div class="span8">
<t t-raw="shop_content">
</t>
</div>
<t t-call='website_sale.categories' />
<t t-raw="shop_content" />
</div>
</div>
</t>
@@ -72,9 +63,20 @@
<!-- List of categories -->
<template id="categories">
<div class="span4">
<ul class="nav nav-list">
<li t-att-class=" '' if current_category else 'active' " class='active'><a href='/shop/'>All Products</a></li>
<t t-foreach="website_sale_get_categories()" t-as="category">
<t t-call="website_sale.categories_recursive"/>
</t>
</ul>
</div>
</template>
<template id="categories_recursive">
<li t-att-class="category.id == current_category and 'active' or ''">
<a t-att-href="'/shop/category/%%s' %% category.id"><span t-field="category.name"><t t-esc="category.name"/></span></a>
<a t-att-href="'/shop/category/%%s' %% category.id" t-field="category.name"></a>
<ul t-if="category.child_id" class="nav nav-list">
<t t-foreach="category.child_id" t-as="category">
<t t-call="website_sale.categories_recursive"/>
@@ -85,52 +87,84 @@
<!-- Product list -->
<template id="product_pager">
<t t-set="classname" t-value="classname or ''" />
<div t-if="page_count != 1" t-att-class="classname + ' pagination'">
<ul>
<li t-att-class=" 'disabled' if page == 1 else '' " ><a t-att-href=" '#' if page == 1 else ('/shop/category/%%s/page/%%s' %% (current_category, max(0,page-1))) ">Prev</a></li>
<t t-foreach="pages" t-as="p">
<li t-att-class=" 'active' if p == page else '' " ><a t-att-href=" '/shop/category/%%s/page/%%s' %% (current_category, p)" t-raw='p'></a></li>
</t>
<li t-att-class=" 'disabled' if page == page_count else '' "><a t-att-href=" '#' if page == page_count else ('/shop/category/%%s/page/%%s' %% (current_category, min(page_count,page+1))) ">Next</a></li>
</ul>
</div>
</template>
<template id="products">
<t t-call="website_sale.page">
<t t-set="title">Product</t>
<t t-set="shop_content">
<div class="oe_search clearfix">
<form action="/shop" method="get" class="navbar-search pull-right">
<input type="text" name="search" class="search-query span4" placeholder="Search" t-att-value="search or '' or ''"/>
<button type="submit" class="btn">Submit</button>
</form>
<div class='span8 navbar navbar-inverse'>
<div class='navbar-inner'>
<t t-call="website_sale.product_pager" >
<t t-set="classname">pull-left</t>
</t>
<form action="/shop" method="get" class="navbar-search pull-right">
<input type="text" name="search" class="search-query span2" placeholder="Search" t-att-value="search or '' or ''"/>
</form>
</div>
</div>
<div class="span8">
<div class='row grid grid-align-top'>
<t t-foreach="products" t-as="product">
<t t-set="quantity" t-value="([int(line.product_uom_qty) for line in (order.order_line or []) if line.product_id.id == product.id] + [0])[0]"/>
<t t-call="website_sale.product_card"/>
</t>
</div>
</div>
<div class="span8 offset4 text-center">
<t t-call="website_sale.product_pager" />
</div>
<span class="oe_products">
<t t-foreach="products" t-as="product">
<t t-set="quantity" t-value="([int(line.product_uom_qty) for line in (order.order_line or []) if line.product_id.id == product.id] + [0])[0]"/>
<t t-call="website_sale.product_card"/>
</t>
</span>
</t>
</t>
</template>
<template id="product_card">
<div class="media oe_product span3">
<a t-att-href="'/shop/product/%%s' %% product.id"><h4 class="media-heading"><span t-field="product.name"><t t-esc="product.name"/></span></h4></a>
<a class="pull-left" t-att-href="'/shop/product/%%s' %% product.id"><img class="media-object" t-att-src="'data:image/png;base64,' + product.image"/></a>
<div class="media-body">
<div class="oe_ecommerce_description" t-field="product.description_sale"><t t-esc="product.description_sale"/></div>
<div class="oe_ecommerce_price"><span><span t-field="product.list_price"><t t-esc="product.list_price"/></span>€</span></div>
<div class="oe_button_cart">
<div class="alert mb0" t-if="editable and not product.website_published">Product not published</div>
<t t-if="product.website_published">
<button t-att-class="'btn btn-small btn-inverse %%s' %% (not quantity and 'oe_hidden' or '')" t-att-data-id="product.id">Remove one</button>
<button t-att-class="'btn btn-small %%s' %% (quantity and 'btn-success' or 'btn-primary')" t-att-data-id="product.id">Add to cart
<span class="oe_txt">(<span class="oe_quantity"><t t-esc="quantity"/></span>)</span>
</button>
</t>
<div class="oe_product span2 mb16 thumbnail text-center">
<a t-att-href="'/shop/product/%%s' %% product.id">
<h5 t-field="product.name"> </h5>
</a>
<a t-att-href="'/shop/product/%%s' %% product.id">
<img class="img-rounded" t-att-src="'data:image/png;base64,' + product.image"/>
</a>
<div>
<div t-field="product.description_sale"></div>
<div><span t-field="product.list_price"></span>€</div>
<div class="mb8 mt8">
<button t-att-class="'btn mb8 btn-small btn-inverse %%s' %% (not quantity and 'hidden' or '')" t-att-data-id="product.id">Remove one</button>
<button t-att-class="'btn btn-small %%s' %% (quantity and 'btn-success' or 'btn-primary')" t-att-data-id="product.id">
Add to cart <t t-if="quantity">(<t t-esc="quantity"/>)</t>
</button>
</div>
</div>
</div>
</template>
<template id="product_recommended">
<div class="oe_recommended media well well-small" t-if="recommended_products">
<h6>Other customers have also take this products:</h6>
<div class="well mt32" t-if="recommended_products">
<h4>Customers who have bought this item also bought</h4>
<div class='row mt16'>
<t t-foreach="recommended_products or []" t-as="product">
<a t-att-href="'/shop/product/%%s' %% product.id"><img t-att-src="'data:image/png;base64,' + product.image"/></a>
<div class='span2 thumbnail'>
<a t-att-href="'/shop/product/%%s' %% product.id">
<div class='mt16 text-center'>
<img t-att-src="'data:image/png;base64,' + product.image"/>
<h5 t-field='product.name'></h5>
</div>
</a>
</div>
</t>
</div>
</div>
</template>
@@ -140,21 +174,22 @@
<t t-call="website_sale.page">
<t t-set="title">Product</t>
<t t-set="shop_content">
<div class="oe_product_detail">
<div class="oe_product_detail span8">
<a href="#" t-att-data-id="product.id" class="pull-right" t-if="editable">
<span t-att-class="'label label-success js_unpublish %%s' %% (not product.website_published and 'hidden' or '')">Click to Unpublish</span>
<span t-att-class="'label label-important js_publish %%s' %% (product.website_published and 'hidden' or '')">Click to Publish</span>
</a>
<h1 t-field="product.name"></h1>
<h2 t-field="product.name"></h2>
<div class="oe_button_cart">
<button t-att-class="'btn btn-inverse %%s' %% (not quantity and 'oe_hidden' or '')" t-att-data-id="product.id">Remove one</button>
<button t-att-class="'btn %%s' %% (quantity and 'btn-success' or 'btn-primary')" t-att-data-id="product.id">Add to cart
<span class="oe_txt">(<span class="oe_quantity"><t t-esc="quantity"/></span>)</span>
<button t-att-class="'btn btn-small btn-inverse %%s' %% (not quantity and 'oe_hidden' or '')" t-att-data-id="product.id">Remove one</button>
<button t-att-class="'btn btn-small %%s' %% (quantity and 'btn-success' or 'btn-primary')" t-att-data-id="product.id">
Add to cart <t t-if="quantity" >(<t t-esc="quantity"/>)</t>
</button>
</div>
<img class="media-object" t-att-src="'data:image/png;base64,' + product.image"/>
<div t-field="product.description_sale"></div>
<div class="oe_ecommerce_price" t-field="product.list_price"><t t-esc="product.list_price"/> €</div>
<div t-field="product.description_website"></div>
<div class="oe_ecommerce_price"><t t-field="product.list_price" />€</div>
<t t-call="website_sale.product_recommended"/>
</div>
</t>
@@ -167,22 +202,24 @@
<t t-call="website_sale.page">
<t t-set="title">My cart</t>
<t t-set="shop_content">
<span class="oe_mycart">
<t t-foreach="order.order_line or []" t-as="line">
<t t-set="product" t-value="line.product_id"/>
<t t-set="quantity" t-value="int(line.product_uom_qty)"/>
<t t-call="website_sale.product_card"/>
</t>
<t t-call="website_sale.product_recommended"/>
<t t-call="website_sale.total"/>
<div class="media well well-small" t-if="order.order_line">
<form action="/shop/mycart" class="navbar-form">
<input name="code" type="text" placeholder="Reduction Code..."/>
<button class="btn">Submit your Reduction Code</button>
</form>
<div class="span8 oe_mycart">
<h2>My Shopping Cart</h2>
<h3 t-if="not order.order_line">Your cart is empty</h3>
<div class='row mt32 grid grid-align-top'>
<t t-foreach="order.order_line or []" t-as="line">
<t t-set="product" t-value="line.product_id"/>
<t t-set="quantity" t-value="int(line.product_uom_qty)"/>
<t t-call="website_sale.product_card"/>
</t>
</div>
<a t-if="order.order_line" href="/shop/checkout"><button class="btn btn-success">Next stage</button></a>
</span>
<t t-call="website_sale.total"/>
<form t-if="order.order_line" class="well form-search" action="/shop/mycart" >
<input name="code" class='input' type="text" placeholder="Reduction Code..."/>
<button class="btn">Apply Code</button>
</form>
<a t-if="order.order_line" href="/shop/checkout"><button class="btn btn-success">Proceed To Payment</button></a>
<t t-call="website_sale.product_recommended"/>
</div>
</t>
</t>
</template>
@@ -190,14 +227,15 @@
<!-- Total Shop my cart -->
<template id="total">
<div class="oe_total">
<div class="media well well-small">
<table t-if="order.order_line">
<tr><td>Untaxed Amount</td><td><t t-esc="order.amount_untaxed"/> €</td></tr>
<tr><td>Taxes</td><td><t t-esc="order.amount_tax"/> €</td></tr>
<tr><td>Total</td><td><h3><t t-esc="order.amount_total"/> €</h3></td></tr>
</table>
<span t-if="not order.order_line">Your cart is empty</span>
<div class="row oe_total">
<div class="span4">
<div class="well">
<table class='table-equalized' t-if="order.order_line">
<tr> <td>Subtotal </td> <td><t t-esc="order.amount_untaxed"/> €</td></tr>
<tr> <td>Taxes </td> <td><t t-esc="order.amount_tax"/> €</td></tr>
<tr> <td><h4>Total</h4></td> <td><h4><t t-esc="order.amounttotal"/> €</h4></td></tr>
</table>
</div>
</div>
</div>
</template>