[MERGE] trunk-website-al

bzr revid: ddm@openerp.com-20131002085338-8jw3dkqtq842nwhe
This commit is contained in:
ddm
2013-10-02 10:53:38 +02:00
81 changed files with 1454 additions and 936 deletions
+9 -3
View File
@@ -68,8 +68,10 @@
<field name="event_id" ref="event.event_0"/>
<field name="product_id" ref="event_0_product"/>
<field name="deadline" eval="(DateTime.today() + timedelta(60)).strftime('%Y-%m-%d')"/>
<field name="price">5000.0</field>
<field name="price">1500.0</field>
<field name="register_max">10</field>
<field name="description_sale">Cathering for breakfast and lunch
VIP Parking access</field>
</record>
@@ -97,8 +99,10 @@
<field name="event_id" ref="event.event_2"/>
<field name="product_id" ref="event_2_product"/>
<field name="deadline" eval="(DateTime.today() + timedelta(60)).strftime('%Y-%m-%d')"/>
<field name="price">5000.0</field>
<field name="price">1500.0</field>
<field name="register_max">5</field>
<field name="description_sale">Cathering for breakfast and lunch
VIP Parking access</field>
</record>
<record id="event_3_ticket_1" model="event.event.ticket">
@@ -115,8 +119,10 @@
<field name="event_id" ref="event.event_3"/>
<field name="product_id" ref="event_3_product"/>
<field name="deadline" eval="(DateTime.today() + timedelta(60)).strftime('%Y-%m-%d')"/>
<field name="price">5000.0</field>
<field name="price">1500.0</field>
<field name="register_max">5</field>
<field name="description_sale">Cathering for breakfast and lunch
VIP Parking access</field>
</record>
</data>
+1 -3
View File
@@ -1,5 +1,3 @@
import controllers
import res_config
import website
import view
import models
+1 -1
View File
@@ -14,7 +14,7 @@ import werkzeug.wrappers
from PIL import Image
import openerp
from openerp.addons.website import website
from openerp.addons.website.models import website
from openerp.addons.web import http
from openerp.addons.web.http import request
+6
View File
@@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-
import ir_fields
import res_config
import view
import website
+87
View File
@@ -0,0 +1,87 @@
# -*- coding: utf-8 -*-
from lxml import etree, html
from openerp.osv import orm, fields
from openerp.tools import ustr
class converter(orm.Model):
_inherit = 'ir.fields.converter'
def _html_to_integer(self, cr, uid, model, column, value, context=None):
return int(value.text_content().strip()), []
def _html_to_float(self, cr, uid, model, column, value, context=None):
return float(value.text_content().strip()), []
def _html_to_passthrough(self, cr, uid, model, column, value, context=None):
return value.text_content().strip(), []
_html_to_char = _html_to_date = _html_to_datetime = _html_to_passthrough
def _html_to_text(self, cr, uid, model, column, value, context=None):
return value.text_content(), []
def _html_to_selection(self, cr, uid, model, column, value, context=None):
text = value.text_content().strip()
selection = column.reify(cr, uid, model, column, context=context)
for k, v in selection:
if isinstance(v, str):
v = ustr(v)
if text == v:
return k, []
warning = u"No value found for label %s in selection %s" % (text, selection)
# FIXME: ?
return False, [Warning(warning.encode('utf-8'))]
def _html_to_many2one(self, cr, uid, model, column, value, context=None):
matches = self.pool[column._obj].name_search(
cr, uid, name=value.text_content().strip(), context=context)
# FIXME: more than one match, error reporting
return matches[0][0], []
def _html_to_html(self, cr, uid, model, column, value, context=None):
content = []
if value.text: content.append(value.text)
content.extend(html.tostring(child)
for child in value.iterchildren(tag=etree.Element))
return '\n'.join(content), []
class test_converter(orm.Model):
_name = 'website.converter.test'
_columns = {
'char': fields.char(),
'integer': fields.integer(),
'float': fields.float(),
'numeric': fields.float(digits=(16, 2)),
'many2one': fields.many2one('website.converter.test.sub'),
'binary': fields.binary(),
'date': fields.date(),
'datetime': fields.datetime(),
'selection': fields.selection([
(1, "réponse A"),
(2, "réponse B"),
(3, "réponse C"),
(4, "réponse D"),
]),
'selection_str': fields.selection([
('A', "Qu'il n'est pas arrivé à Toronto"),
('B', "Qu'il était supposé arriver à Toronto"),
('C', "Qu'est-ce qu'il fout ce maudit pancake, tabernacle ?"),
('D', "La réponse D"),
], string="Lorsqu'un pancake prend l'avion à destination de Toronto et "
"qu'il fait une escale technique à St Claude, on dit:"),
'html': fields.html(),
'text': fields.text(),
}
class test_converter_sub(orm.Model):
_name = 'website.converter.test.sub'
_columns = {
'name': fields.char(),
}
@@ -55,57 +55,19 @@ class view(osv.osv):
def extract_embedded_fields(self, cr, uid, arch, context=None):
return arch.xpath('//*[@data-oe-model != "ir.ui.view"]')
def convert_embedded_field(self, cr, uid, el, column,
type_override=None, context=None):
""" Converts the content of an embedded field to a value acceptable
for writing in the column
:param etree._Element el: embedded field being saved
:param fields._column column: column object corresponding to the field
:param type type_override: column type to dispatch on instead of the
column's actual type (for proxy column types
e.g. relateds)
:return: converted value
"""
column_type = type_override or type(column)
if issubclass(column_type, fields.html):
content = []
if el.text: content.append(el.text)
content.extend(html.tostring(child)
for child in el.iterchildren(tag=etree.Element))
return '\n'.join(content)
elif issubclass(column_type, fields.integer):
return int(el.text_content())
elif issubclass(column_type, fields.float):
return float(el.text_content())
elif issubclass(column_type, (fields.char, fields.text,
fields.date, fields.datetime)):
return el.text_content()
# TODO: fields.selection
elif issubclass(column_type, fields.many2one):
matches = self.pool[column._obj].name_search(
cr, uid, name=el.text_content().strip(), context=context)
# FIXME: more than one match, error reporting
return matches[0][0]
elif issubclass(column_type, fields.function):
# FIXME: special-case selection as in get_pg_type?
return self.convert_embedded_field(
cr, uid, el, column,
type_override=getattr(fields, column._type),
context=context)
# TODO?: fields.many2many, fields.one2many
# TODO?: fields.reference
else:
raise TypeError("Un-convertable column type %s" % column_type)
def save_embedded_field(self, cr, uid, el, context=None):
Model = self.pool[el.get('data-oe-model')]
field = el.get('data-oe-field')
column = Model._all_columns[field].column
convert = self.pool['ir.fields.converter'].to_field(
cr, uid, Model, column, fromtype="html", context=context)
value, warnings = convert(el)
# FIXME: report error
if warnings: return
Model.write(cr, uid, [int(el.get('data-oe-id'))], {
field: self.convert_embedded_field(cr, uid, el, column, context=context)
field: value
}, context=context)
def to_field_ref(self, cr, uid, el, context=None):
@@ -137,7 +99,8 @@ class view(osv.osv):
"""
res_id = int(res_id)
arch_section = html.fromstring(value)
arch_section = html.fromstring(
value, parser=html.HTMLParser(encoding='utf-8'))
if xpath is None:
# value is an embedded field on its own, not a view section
+25 -23
View File
@@ -1,4 +1,4 @@
@charset "utf-8";
@charset "UTF-8";
/* ---- CKEditor Minimal Reset ---- */
.navbar.navbar-inverse .cke_chrome {
border: none;
@@ -167,7 +167,6 @@ table.editorbar-panel td.selected {
box-shadow: 0px 10px 10px -10px black inset;
z-index: 1010;
overflow: hidden;
height: 110px;
}
#oe_snippets:hover {
height: auto;
@@ -177,16 +176,13 @@ table.editorbar-panel td.selected {
overflow-y: auto;
}
#oe_snippets .nav {
padding: 3px 15px;
width: 162px;
background: #444444;
position: fixed;
z-index: 1;
height: 108px;
}
#oe_snippets .nav > li {
display: block;
display: inline-block;
float: none;
font-size: 13px;
}
#oe_snippets .nav > li > a {
padding: 2px 10px !important;
@@ -194,13 +190,14 @@ table.editorbar-panel td.selected {
display: block;
}
#oe_snippets .pill-content {
margin-top: 24px;
display: inline-block;
height: 110px;
white-space: nowrap;
padding-left: 166px;
}
#oe_snippets .pill-content > div {
display: inline-block;
background: black;
padding: 5px;
}
#oe_snippets .pill-content > div label {
width: 44px;
@@ -211,23 +208,23 @@ table.editorbar-panel td.selected {
#oe_snippets .pill-content > div label div {
width: 100px;
text-align: center;
-webkit-transform: translate(-39px, 44px) rotate(-90deg);
-moz-transform: translate(-39px, 44px) rotate(-90deg);
-o-transform: translate(-39px, 44px) rotate(-90deg);
transform: translate(-39px, 44px) rotate(-90deg);
-webkit-transform-origin: 50% 50%;
-moz-transform-origin: 50% 50%;
-ms-transform-origin: 50% 50%;
-o-transform-origin: 50% 50%;
transform-origin: 50% 50%;
-webkit-transform: translate(-39px, 44px);
-moz-transform: translate(-39px, 44px);
-ms-transform: translate(-39px, 44px);
-o-transform: translate(-39px, 44px);
transform: translate(-39px, 44px);
-webkit-transform-origin: 50% 50% 50%;
-moz-transform-origin: 50% 50% 50%;
-ms-transform-origin: 50% 50% 50%;
-o-transform-origin: 50% 50% 50%;
transform-origin: 50% 50% 50%;
}
.oe_snippet {
display: inline-block;
vertical-align: top;
width: 108px;
height: 108px;
border-radius: 3px;
width: 100px;
height: 100px;
margin: 1px;
margin-top: 0px;
position: relative;
@@ -243,9 +240,15 @@ table.editorbar-panel td.selected {
height: 100%;
background: transparent;
color: white;
text-shadow: 0px 1px 2px rgba(0, 0, 0, 0.95);
position: relative;
}
.oe_snippet .oe_snippet_thumbnail .oe_snippet_thumbnail_title {
font-size: 12px;
display: block;
}
.oe_snippet .oe_snippet_thumbnail .oe_snippet_thumbnail_img {
box-shadow: inset 0px 0px 0px 3px #333333;
}
.oe_snippet .oe_snippet_thumbnail span, .oe_snippet .oe_snippet_thumbnail div {
line-height: 18px;
}
@@ -256,7 +259,6 @@ table.editorbar-panel td.selected {
#oe_snippets .oe_snippet_thumbnail {
background: #747474;
background-image: radial-gradient(rgba(0, 0, 0, 0.25), rgba(0, 0, 0, 0.4));
box-shadow: 0px 0px 0px 1px rgba(255, 255, 255, 0.07) inset;
}
/* ---- SNIPPETS DROP ZONES ---- */
+16 -23
View File
@@ -1,5 +1,7 @@
@charset "utf-8"
@import "compass/css3"
/* ---- CKEditor Minimal Reset ---- */
.navbar.navbar-inverse .cke_chrome
@@ -145,33 +147,30 @@ table.editorbar-panel
box-shadow: 0px 10px 10px -10px black inset
z-index: 1010
overflow: hidden
height: 110px
&:hover
height: auto
.scroll
white-space: nowrap
overflow-y: auto
.nav
padding: 3px 15px
width: 162px
background: #444444
> li
display: block
display: inline-block
float: none
font-size: 13px
> a
padding: 2px 10px !important
width: 100%
display: block
position: fixed
z-index: 1
height: 108px
.pill-content
margin-top: 24px
display: inline-block
height: 110px
white-space: nowrap
padding-left: 166px
> div
display: inline-block
background: rgb(0,0,0)
padding: 5px
label
width: 44px
height: 100%
@@ -180,22 +179,14 @@ table.editorbar-panel
div
width: 100px
text-align: center
-webkit-transform: translate(-39px, 44px) rotate(-90deg)
-moz-transform: translate(-39px, 44px) rotate(-90deg)
-o-transform: translate(-39px, 44px) rotate(-90deg)
transform: translate(-39px, 44px) rotate(-90deg)
-webkit-transform-origin: 50% 50%
-moz-transform-origin: 50% 50%
-ms-transform-origin: 50% 50%
-o-transform-origin: 50% 50%
transform-origin: 50% 50%
@include transform( translate(-39px, 44px) , rotate(-90deg) )
@include transform-origin(50% 50%)
.oe_snippet
display: inline-block
vertical-align: top
width: 108px
height: 108px
border-radius: 3px
width: 100px
height: 100px
margin: 1px
margin-top: 0px
position: relative
@@ -204,15 +195,18 @@ table.editorbar-panel
user-select: none
cursor: move
pointer-events: none
.oe_snippet_thumbnail
pointer-events: auto
text-align: center
height: 100%
background: transparent
color: white
text-shadow: 0px 1px 2px rgba(0, 0, 0, 0.95)
position: relative
.oe_snippet_thumbnail_title
font-size: 12px
display: block
.oe_snippet_thumbnail_img
box-shadow: inset 0px 0px 0px 3px #333333
span, div
line-height: 18px
& > :not(.oe_snippet_thumbnail)
@@ -221,7 +215,6 @@ table.editorbar-panel
#oe_snippets .oe_snippet_thumbnail
background: rgb(116, 116, 116)
background-image: radial-gradient(rgba(0,0,0,0.25),rgba(0,0,0,0.4))
box-shadow: 0px 0px 0px 1px rgba(255, 255, 255, 0.07) inset
/* ---- SNIPPETS DROP ZONES ---- */
+19
View File
@@ -367,6 +367,25 @@ ul.nav-stacked > li > a {
}
/* ---- PUBLISH ---- */
a[data-publish] {
text-decoration: none !important;
}
a[data-publish] .css_unpublish, a[data-publish] .css_publish, a[data-publish] .css_unpublished, a[data-publish] .css_published {
display: none;
}
a[data-publish][data-publish='off'] .css_unpublished, a[data-publish][data-publish='off']:hover .css_publish {
display: inline;
}
a[data-publish][data-publish='off']:hover .css_unpublished {
display: none;
}
a[data-publish][data-publish='on'] .css_published, a[data-publish][data-publish='on']:hover .css_unpublish {
display: inline;
}
a[data-publish][data-publish='on']:hover .css_published {
display: none;
}
.dropdown .css_unpublish, .dropdown .css_publish {
display: none;
}
@@ -283,6 +283,20 @@ ul.nav-stacked > li > a
text-transform: uppercase
/* ---- PUBLISH ---- */
a[data-publish]
text-decoration: none !important
.css_unpublish, .css_publish, .css_unpublished, .css_published
display: none
&[data-publish='off']
.css_unpublished, &:hover .css_publish
display: inline
&:hover .css_unpublished
display: none
&[data-publish='on']
.css_published, &:hover .css_unpublish
display: inline
&:hover .css_published
display: none
.dropdown .css_unpublish, .dropdown .css_publish
display: none
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

+78 -36
View File
@@ -18,7 +18,7 @@
return new website.editor.LinkDialog(editor).appendTo(document.body);
}
function image_dialog(editor) {
return new website.editor.ImageDialog(editor).appendTo(document.body);
return new website.editor.RTEImageDialog(editor).appendTo(document.body);
}
if (website.is_editable) {
@@ -673,6 +673,23 @@
});
},
});
/**
* ImageDialog widget. Lets users change an image, including uploading a
* new image in OpenERP or selecting the image style (if supported by
* the caller).
*
* Initialized as usual, but the caller can hook into two events:
*
* @event start({url, style}) called during dialog initialization and
* opening, the handler can *set* the ``url``
* and ``style`` properties on its parameter
* to provide these as default values to the
* dialog
* @event save({url, style}) called during dialog finalization, the handler
* is provided with the image url and style
* selected by the users (or possibly the ones
* originally passed in)
*/
website.editor.ImageDialog = website.editor.Dialog.extend({
template: 'website.editor.dialog.image',
events: _.extend({}, website.editor.Dialog.prototype.events, {
@@ -685,47 +702,30 @@
'click a[href=#existing]': 'browse_existing',
'change select.image-style': 'preview_image',
}),
start: function () {
var selection = this.editor.getSelection();
var el = selection && selection.getSelectedElement();
this.element = null;
var $select = this.$('.image-style');
var $options = $select.children();
start: function () {
var $options = this.$('.image-style').children();
this.image_styles = $options.map(function () { return this.value; }).get();
if (el && el.is('img')) {
this.element = el;
_(this.image_styles).each(function (style) {
if (el.hasClass(style)) {
$select.val(style);
}
});
// set_image must follow setup of image style
this.set_image(el.getAttribute('src'));
var o = { url: null, style: null, };
// avoid typos, prevent addition of new properties to the object
Object.preventExtensions(o);
this.trigger('start', o);
if (o.url) {
if (o.style) {
this.$('.image-style').val(o.style);
}
this.set_image(o.url);
}
return this._super();
},
save: function () {
var url = this.$('input.url').val();
var style = this.$('.image-style').val();
var element, editor = this.editor;
if (!(element = this.element)) {
element = editor.document.createElement('img');
// focus event handler interactions between bootstrap (modal)
// and ckeditor (RTE) lead to blowing the stack in Safari and
// Chrome (but not FF) when this is done synchronously =>
// defer insertion so modal has been hidden & destroyed before
// it happens
setTimeout(function () {
editor.insertElement(element);
}, 0);
}
element.setAttribute('src', url);
$(element.$).removeClass(this.image_styles.join(' '));
if (style) { element.addClass(style); }
this.trigger('save', {
url: this.$('input.url').val(),
style: this.$('.image-style').val(),
});
return this._super();
},
@@ -769,12 +769,53 @@
.removeClass(this.image_styles.join(' '))
.addClass(this.$('select.image-style').val());
},
browse_existing: function (e) {
e.preventDefault();
new website.editor.ExistingImageDialog(this).appendTo(document.body);
},
});
website.editor.RTEImageDialog = website.editor.ImageDialog.extend({
init: function () {
this._super.apply(this, arguments);
this.on('start', this, this.proxy('started'));
this.on('save', this, this.proxy('saved'));
},
started: function (holder) {
var selection = this.editor.getSelection();
var el = selection && selection.getSelectedElement();
this.element = null;
if (el && el.is('img')) {
this.element = el;
_(this.image_styles).each(function (style) {
if (el.hasClass(style)) {
holder.style = style;
}
});
holder.url = el.getAttribute('src');
}
},
saved: function (data) {
var element, editor = this.editor;
if (!(element = this.element)) {
element = editor.document.createElement('img');
// focus event handler interactions between bootstrap (modal)
// and ckeditor (RTE) lead to blowing the stack in Safari and
// Chrome (but not FF) when this is done synchronously =>
// defer insertion so modal has been hidden & destroyed before
// it happens
setTimeout(function () {
editor.insertElement(element);
}, 0);
}
var style = data.style;
element.setAttribute('src', data.url);
$(element.$).removeClass(this.image_styles.join(' '));
if (style) { element.addClass(style); }
},
});
var IMAGES_PER_ROW = 6;
var IMAGES_ROWS = 4;
@@ -893,7 +934,7 @@
if (m.attributeName !== 'class') { return true; }
// find out what classes were added or removed
var oldClasses = m.oldValue.split(/\s+/);
var oldClasses = (m.oldValue || '').split(/\s+/);
var newClasses = m.target.className.split(/\s+/);
var change = _.union(_.difference(oldClasses, newClasses),
_.difference(newClasses, oldClasses));
@@ -911,6 +952,7 @@
while (node && !$(node).hasClass('oe_editable')) {
node = node.parentNode;
}
$(m.target).trigger('node_changed');
return node;
})
.compact()
+20
View File
@@ -117,9 +117,29 @@
};
dom_ready.then(function () {
/* ----- PUBLISHING STUFF ---- */
$('[data-publish]:has(.js_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_management)').each(function () {
$(this).attr("data-publish", $(".js_publish_management .btn-success", this).size() ? "on" : 'off');
$(this).attr("data-publish", $(".js_publish_management .btn-success", 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');
openerp.jsonRpc('/website/publish', 'call', {'id': $(this).data('id'), 'object': $(this).data('object')})
.then(function (result) {
$data.attr("data-publish", +result ? 'on' : 'off');
});
});
$(document).on('click', '.js_publish_management .js_publish_btn', function (e) {
@@ -8,8 +8,8 @@
start: function () {
var self = this;
$("[data-oe-model]").on('click', function (event) {
var tag = event.srcElement.tagName.toLowerCase();
var $this = $(event.srcElement);
var tag = $this[0].tagName.toLowerCase();
if (!(tag === 'a' || tag === "button") && !$this.parents("a, button").length) {
self.$('[data-action="edit"]').parent().effect('bounce', {distance: 18, times: 5}, 250);
}
@@ -158,23 +158,29 @@
var $pill = self.$(".pill-content");
var padding = parseInt($pill.css("padding-left"));
var $scroll = this.$(".scroll");
$scroll.scroll(function () {
$scroll.scroll(function () {
$pill.find("> div").each(function () {
/*
if ($(this).position().left <= padding) {
$ul.find("> li").removeClass('active');
$ul.find("a[href='#" + $(this).attr("id") + "']").parent("li").addClass('active');
}
}*/
});
});
$ul.find("a").click(function (event) {
event.preventDefault();
$scroll.scrollLeft( $scroll.scrollLeft() + $($(event.currentTarget).attr("href")).position().left - padding );
$pill.find("> div").hide();
$pill.find( $(event.currentTarget).attr('href')).show();
$ul.find('> li').removeClass('active');
$(event.currentTarget).parent().addClass('active');
return false;
});
$pill.css("padding-right", self.$el.outerWidth() - padding + 10 - $pill.find("> div:last").outerWidth());
// $pill.css("padding-right", self.$el.outerWidth() - padding + 10 - $pill.find("> div:last").outerWidth());
$pill.find("> div").hide();
$pill.find("div:first").show();
$ul.find("> li:first").addClass('active');
},
cover_target: function ($el, $target){
@@ -389,7 +395,7 @@
},
stop: function(){
$('.oe_drop_zone').droppable('destroy').remove();
if (!dropped) {
if (!dropped && self.$modal.find('input:not(:checked)').length) {
self.$modal.modal('toggle');
}
},
@@ -573,7 +579,6 @@
onBlurEdit : function () {},
});
website.snippet.editorRegistry = {};
website.snippet.Editor = openerp.Class.extend({
init: function (parent, dom) {
@@ -700,6 +705,7 @@
this.$overlay.on('click', '.oe_snippet_clone', function () {
var $clone = self.$target.clone(false);
self.$target.after($clone);
return false;
});
},
@@ -793,6 +799,50 @@
onBlur : function () {
this.$overlay.removeClass('oe_active');
},
change_background: function (bg, ul_options) {
var self = this;
var $ul = this.$editor.find(ul_options);
var bg_value = (typeof bg == 'string' ? self.$target.find(bg) : $(bg)).css("background-image").replace(/url\(['"]*|['"]*\)/g, "");
// select in ul options
$ul.find("li").removeClass("active");
var selected = $ul.find('[data-value="' + bg_value + '"], [data-value="' + bg_value.replace(/.*:\/\/[^\/]+/, '') + '"]');
selected.addClass('active');
if (!selected.length) {
$ul.find('.oe_custom_bg b').html(bg_value);
}
// bind envent on options
var $li = $ul.find("li");
$li.on('click', function (event) {
if ($(this).data("value")) {
$li.removeClass("active");
$(this).addClass("active");
self.$editor.find('input').val("");
} else {
var editor = new website.editor.ImageDialog();
editor.on('start', self, function (o) {o.url = bg_value;});
editor.on('save', self, function (o) {
var $bg = typeof bg == 'string' ? self.$target.find(bg) : $(bg);
$bg.css("background-image", "url(" + o.url + ")");
});
editor.appendTo($('body'));
}
})
.on('mouseover', function (event) {
if ($(this).data("value")) {
var src = $(this).data("value");
var $bg = typeof bg == 'string' ? self.$target.find(bg) : $(bg);
$bg.css("background-image", "url(" + src + ")");
}
})
.on('mouseout', function (event) {
var src = $ul.find('li.active').data("value");
var $bg = typeof bg == 'string' ? self.$target.find(bg) : $(bg);
$bg.css("background-image", "url(" + src + ")");
});
},
});
@@ -863,13 +913,13 @@
var change = false;
if (dd > (2*resize[1][next] + resize[1][current])/3) {
self.$target.attr("class",self.$target.attr("class").replace(regClass, ''));
self.$target.attr("class", (self.$target.attr("class")||'').replace(regClass, ''));
self.$target.addClass(resize[0][next]);
current = next;
change = true;
}
if (prev != current && dd < (2*resize[1][prev] + resize[1][current])/3) {
self.$target.attr("class",self.$target.attr("class").replace(regClass, ''));
self.$target.attr("class", (self.$target.attr("class")||'').replace(regClass, ''));
self.$target.addClass(resize[0][prev]);
current = prev;
change = true;
@@ -991,8 +1041,9 @@
this.$editor.find(".js_add").on('click', _.bind(this.on_add, this));
this.$editor.find(".js_remove").on('click', _.bind(this.on_remove, this));
this.change_background();
this.change_background(".item.active", 'ul[name="carousel-background"]');
this.change_style();
this.set_options_style();
this.change_size();
},
on_add: function (e) {
@@ -1014,48 +1065,12 @@
.find('.item.active').remove().end()
.find('.item:first').addClass('active');
this.$target.carousel(0);
this.set_options_background();
this.set_options_style();
}
if (nb <= 1) {
this.$target.find('.carousel-control').addClass("hidden");
}
},
onFocus: function () {
this.set_options_background();
this.set_options_style();
this._super();
},
set_options_background: function () {
var $image = this.$target.find('.carousel-inner .item.active > img');
var bg = $image.attr('src');
var $ul = this.$editor.find('ul[name="carousel-background"]');
$ul.find("li").removeClass("active");
var selected = $ul.find('[data-value="' + bg + '"], [data-value="' + bg.replace(/.*:\/\/[^\/]+/, '') + '"]')
.addClass('active').length;
this.$editor.find('.oe_custom_bg b').html(selected ? "" : bg);
},
change_background: function () {
var self = this;
var $ul = this.$editor.find('ul[name="carousel-background"]');
var $li = $ul.find("li");
$li.on('click', function (event) {
$li.removeClass("active");
$(this).addClass("active");
self.$editor.find('input').val("");
})
.on('mouseover', function (event) {
if ($(this).data("value")) {
self.$target.find('.carousel-inner .item.active > img')
.attr('src', $(this).data("value"));
}
})
.on('mouseout', function (event) {
self.$target.find('.carousel-inner .item.active > img')
.attr('src', $ul.find('li.active').data("value"));
});
},
set_options_style: function () {
var style = false;
var $el = this.$target.find('.carousel-inner .item.active');
@@ -1124,50 +1139,7 @@
website.snippet.editorRegistry.parallax = website.snippet.editorRegistry.resize.extend({
start : function () {
this._super();
this.change_background();
},
onFocus: function () {
this.$imagebg = $("<img/>");
this.$imagebg.prependTo(this.$target);
this.set_options_background();
this._super();
},
onBlur : function () {
this._super();
this.$imagebg.remove();
},
set_options_background: function () {
var bg = this.$target.css("background-image").replace(/url\(|\)/g, "");
this.$imagebg.attr("src", bg);
var $ul = this.$editor.find('ul[name="parallax-background"]');
$ul.find("li").removeClass("active");
var selected = $ul.find('[data-value="' + bg + '"], [data-value="' + bg.replace(/.*:\/\/[^\/]+/, '') + '"]')
.addClass('active').length;
this.$editor.find('.oe_custom_bg b').html(selected ? "" : bg);
},
change_background: function () {
var self = this;
var $ul = this.$editor.find('ul[name="parallax-background"]');
var $li = $ul.find("li");
$li.on('click', function (event) {
$li.removeClass("active");
$(this).addClass("active");
self.$editor.find('input').val("");
})
.on('mouseover', function (event) {
if ($(this).data("value")) {
var src = $(this).data("value");
self.$imagebg.attr('src', src);
self.$target.css("background-image", "url(" + src + ")");
}
})
.on('mouseout', function (event) {
var src = $ul.find('li.active').data("value");
self.$imagebg.attr('src', src);
self.$target.css("background-image", "url(" + src + ")");
});
this.change_background(this.$target, 'ul[name="parallax-background"]');
},
});
@@ -63,10 +63,10 @@
<li><a href="#snippet_effect">Effects</a></li>
</ul>
<div class="pill-content">
<div id="snippet_structure"><label><div>Structure</div></label></div>
<div id="snippet_content"><label><div>Content</div></label></div>
<div id="snippet_business"><label><div>Business</div></label></div>
<div id="snippet_effect"><label><div>Effects</div></label></div>
<div id="snippet_structure"></div>
<div id="snippet_content"></div>
<div id="snippet_business"></div>
<div id="snippet_effect"></div>
</div>
</div>
</div>
@@ -160,17 +160,14 @@
<!-- thumbnail to display inside the bottom widget list editor -->
<div class='oe_snippet_thumbnail'>
<img src="/website/static/src/img/banner/color_splash.jpg" style="position: absolute; left: 0; top: 40px; max-width: 100%"/>
<img src="/website/static/src/img/banner/banner_picture.png" style="position: absolute; left: 10px; top: 52px; max-width: 25%"/>
<span style="position: absolute; top: 50px; right: 10px;">Banner</span>
<img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_banner.png"/>
<span class="oe_snippet_thumbnail_title">Banner</span>
</div>
<!-- body to insert after drag and drop thumbnail -->
<div id="myCarousel" class="oe_snippet_body carousel slide oe_medium mb32" data-interval="10000">
<!-- Carousel items -->
<div class="carousel-inner">
<div class="item image_text active">
<img src="/website/static/src/img/banner/color_splash.jpg" width="100%" height="100%"/>
<div class="item image_text active" style="background-image: url('/website/static/src/img/banner/color_splash.jpg')">
<div class="container">
<div class="carousel-caption content">
<h2>Set Your Banner Title</h2>
@@ -197,7 +194,9 @@
</div>
<div t-name="website.snippets.well" data-snippet-id='well' data-category='content' data-selector-siblings='p, h1, h2, h3, blockquote'>
<div class='oe_snippet_thumbnail'>Well</div>
<div class='oe_snippet_thumbnail'>
<span class="oe_snippet_thumbnail_title">Well</span>
</div>
<div class="oe_snippet_body well">
Manage your sales funnel with no effort with OpenERP CRM. Attract
leads, follow-up on phone calls and meetings. Analyse the quality
@@ -206,7 +205,10 @@
</div>
<div t-name="website.snippets.quote" data-snippet-id='quote' data-category='content' data-selector-siblings='p, h1, h2, h3, blockquote'>
<div class='oe_snippet_thumbnail'>Quote</div>
<div class='oe_snippet_thumbnail'>
<img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_quote.png"/>
<span class="oe_snippet_thumbnail_title">Quote</span>
</div>
<blockquote class="oe_snippet_body">
<p>
OpenERP provides essential platform for our project management.
@@ -217,7 +219,10 @@
</div>
<div t-name="website.snippets.panel" data-snippet-id='panel' data-category='content' data-selector-siblings='p, h1, h2, h3, blockquote'>
<div class='oe_snippet_thumbnail'>Panel</div>
<div class='oe_snippet_thumbnail'>
<img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_panel.png"/>
<span class="oe_snippet_thumbnail_title">Panel</span>
</div>
<div class="oe_snippet_body panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">OpenERP Features</h3>
@@ -233,13 +238,16 @@
<div t-name="website.snippets.surprise" data-snippet-id='vomify' data-category='content' data-selector-children='.oe_structure'>
<div class="oe_snippet_body" style="height: 0; position: absolute;"></div>
<div class='oe_snippet_thumbnail' style='background-image:radial-gradient(red,orange,yellow,green,blue);'>Surprise!</div>
<div class='oe_snippet_thumbnail'>
<img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_surprise.png"/>
<span class="oe_snippet_thumbnail_title">Surprise!</span>
</div>
</div>
<div t-name="website.snippets.text-image" data-snippet-id='text-image' data-category='structure' data-selector-children='.oe_structure, [data-oe-type=html]'>
<div class='oe_snippet_thumbnail'>
<span style="position: absolute; top: 50px; left: 5px;">Text-Image</span>
<img src="/website/static/src/img/banner/banner_picture.png" style="position: absolute; right: 5px; top: 50px; max-width: 28%"/>
<img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_text_image.png"/>
<span class="oe_snippet_thumbnail_title">Text-Image</span>
</div>
<section class="oe_snippet_body">
<div class="container">
@@ -268,8 +276,8 @@
<div t-name="website.snippets.image-text" data-snippet-id='image-text' data-category='structure' data-selector-children='.oe_structure, [data-oe-type=html]'>
<div class='oe_snippet_thumbnail'>
<img src="/website/static/src/img/banner/banner_picture.png" style="position: absolute; left: 5px; top: 50px; max-width: 28%"/>
<span style="position: absolute; top: 50px; right: 5px;">Image-Text</span>
<img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_image_text.png"/>
<span class="oe_snippet_thumbnail_title">Image-Text</span>
</div>
<section class="oe_snippet_body">
<div class="container">
@@ -297,15 +305,8 @@
<div t-name="website.snippets.jumbotron" data-snippet-id='jumbotron' data-category='structure' data-selector-children='.oe_structure, [data-oe-type=html]'>
<div class='oe_snippet_thumbnail'>
<div style="position: absolute; top: 30px; background-color: #eee; width: 100%; padding: 8px 0 6px 4px;">
<div style="color: #000; display: block; text-align: left;">
Jumbotron
<div style="font-size: 9px; line-height: 9px; text-shadow: none;">
Jumbotron Sub-title
<br/><span class="label label-primary">Contact us</span>
</div>
</div>
</div>
<img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_jumbotron.png"/>
<span class="oe_snippet_thumbnail_title">Jumbotron</span>
</div>
<section class="oe_snippet_body jumbotron mt16 mb16">
<div class="container">
@@ -324,21 +325,8 @@
<div t-name="website.snippets.text-block" data-snippet-id='text-block' data-category='structure' data-selector-children='.oe_structure, [data-oe-type=html]'>
<div class='oe_snippet_thumbnail'>
<div style="position: absolute; top: 26px; left: 5px; width: 94%;">
<div style="display: block;">
Text Block
<div style="text-shadow: none;font-size: 9px; line-height: 9px; color: #bbb;margin-bottom: 5px;">
Jumbotron Sub-title
</div>
<div style="text-shadow: none;font-size: 6px; line-height: 6px; text-align: left;">
Organize projects around your own processes. Work
on tasks and issues using the kanban view, schedule
tasks using the gantt chart and control deadlines
in the calendar view. Every project may have it's
own stages allowing teams to optimize their job.
</div>
</div>
</div>
<img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_text_block.png"/>
<span class="oe_snippet_thumbnail_title">Text Block</span>
</div>
<section class="oe_snippet_body mt16 mb16">
<div class="container">
@@ -370,7 +358,10 @@
</div>
<div t-name="website.snippets.title" data-snippet-id='title' data-category='structure' data-selector-children='.oe_structure, [data-oe-type=html]'>
<div class="oe_snippet_thumbnail">Title</div>
<div class="oe_snippet_thumbnail">
<img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_title.png"/>
<span class="oe_snippet_thumbnail_title">Title</span>
</div>
<section class="oe_snippet_body">
<div class="container">
<div class="row">
@@ -385,8 +376,8 @@
<div t-name="website.snippets.hr" data-snippet-id='hr' data-category='structure' data-selector-children='.oe_structure, [data-oe-type=html]'>
<div class="oe_snippet_thumbnail">
<hr style="position: absolute;top: 61px;margin: 0;width: 100%;border-color: #888;"/>
<div style="position: absolute;width: 100%;top: 51px;">Separator</div>
<img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_separator.png"/>
<span class="oe_snippet_thumbnail_title">Separator</span>
</div>
<hr class="oe_snippet_body"/>
</div>
@@ -394,17 +385,8 @@
<div t-name="website.snippets.big-picture" data-snippet-id='big-picture' data-category='structure' data-selector-children='.oe_structure, [data-oe-type=html]'>
<div class='oe_snippet_thumbnail'>
<div style="position: absolute; top: 8px; left: 5px; width: 94%;">
<div style="display: block;">
Big Picture
<img src="/website/static/src/img/big_picture.png" style="max-width: 100%"/>
<div style="text-shadow: none;font-size: 6px; line-height: 6px; margin: 5px 10px">
OpenERP's Point of Sale introduces a super clean
interface with no installation required.
</div>
</div>
</div>
<img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_big_picture.png"/>
<span class="oe_snippet_thumbnail_title">Big Picture</span>
</div>
<section class="oe_snippet_body dark mt16 mb16">
<div class="container">
@@ -436,23 +418,8 @@
<div t-name="website.snippets.three-columns" data-snippet-id='three-columns' data-category='structure' data-selector-children='.oe_structure, [data-oe-type=html]'>
<div class="oe_snippet_thumbnail">
<div style="padding-top: 22px;">
Three Columns
<div class="clearfix" style="font-size: 6px;text-shadow: none;">
<div class="pull-left" style="width: 33%;line-height: 6px;">
<img src="/website/static/src/img/china_thumb.jpg" style="max-width: 90%;"/>
Post job offers and keep track of each application received.
</div>
<div class="pull-left" style="width: 33%;line-height: 6px;">
<img src="/website/static/src/img/desert_thumb.jpg" style="max-width: 90%;"/>
Break down information silos. Share knowledge and best practices amongst all employees.
</div>
<div class="pull-left" style="width: 33%; line-height: 6px;">
<img src="/website/static/src/img/deers_thumb.jpg" style="max-width: 90%;"/>
The agenda of each employee is updated accordingly.
</div>
</div>
</div>
<img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_three_columns.png"/>
<span class="oe_snippet_thumbnail_title">Three Columns</span>
</div>
<section class="oe_snippet_body mt16 mb16">
<div class="container">
@@ -503,7 +470,10 @@
</div>
<div t-name="website.snippets.portfolio" data-snippet-id='portfolio' data-category='business' data-selector-children='.oe_structure, [data-oe-type=html]'>
<div class='oe_snippet_thumbnail'>Portfolio</div>
<div class='oe_snippet_thumbnail'>
<img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_portfolio.png"/>
<span class="oe_snippet_thumbnail_title">Portfolio</span>
</div>
<section class="oe_snippet_body">
<div class="container">
<div class="row">
@@ -533,21 +503,8 @@
<div t-name="website.snippets.image-gallery" data-snippet-id='image-gallery' data-category='business' data-selector-children='.oe_structure, [data-oe-type=html]'>
<div class='oe_snippet_thumbnail'>
<div style="padding-top: 22px;">
Image Gallery
<div class="clearfix">
<div style="float: right; width: 56px;height: 30px;">
<img src="/website/static/src/img/china_thumb.jpg" style="max-width: 24px;"/>
<img src="/website/static/src/img/deers_thumb.jpg" style="max-width: 24px;"/>
<img src="/website/static/src/img/desert_thumb.jpg" style="max-width: 24px;"/>
<img src="/website/static/src/img/china_thumb.jpg" style="max-width: 24px;"/>
</div>
<img src="/website/static/src/img/desert.jpg" style="float-left; width: 50px;height: 31px;margin-top: 4px;"/>
<img src="/website/static/src/img/deers_thumb.jpg" style="float-left; max-width: 24px;"/>
<img src="/website/static/src/img/landscape.jpg" style="float-left; max-width: 50px;"/>
<img src="/website/static/src/img/china_thumb.jpg" style="max-width: 24px;"/>
</div>
</div>
<img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_image_gallery.png"/>
<span class="oe_snippet_thumbnail_title">Image Gallery</span>
</div>
<section class="oe_snippet_body">
<div class="container">
@@ -586,7 +543,10 @@
</div>
<div t-name="website.snippets.pricing" data-snippet-id='pricing' data-category='business' data-selector-children='.oe_structure, [data-oe-type=html]'>
<div class='oe_snippet_thumbnail'>Comparisons</div>
<div class='oe_snippet_thumbnail'>
<img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_comparison.png"/>
<span class="oe_snippet_thumbnail_title">Comparisons</span>
</div>
<section class="oe_snippet_body">
<div class="container">
<div class="row">
@@ -688,7 +648,10 @@
</div>
<div t-name="website.snippets.cta" data-snippet-id='cta' data-category='business' data-selector-children='.oe_structure, [data-oe-type=html]'>
<div class='oe_snippet_thumbnail'>Buttons</div>
<div class='oe_snippet_thumbnail'>
<img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_button.png"/>
<span class="oe_snippet_thumbnail_title">Button</span>
</div>
<section class="oe_snippet_body dark">
<div class="container">
<div class="row">
@@ -702,7 +665,10 @@
</div>
<div t-name="website.snippets.faq" data-snippet-id='faq' data-category='business' data-selector-children='.oe_structure, [data-oe-type=html]'>
<div class='oe_snippet_thumbnail'>FAQ</div>
<div class='oe_snippet_thumbnail'>
<img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_faq.png"/>
<span class="oe_snippet_thumbnail_title">FAQ</span>
</div>
<section class="oe_snippet_body">
<div class="container">
<h2 class="page-header">
@@ -745,7 +711,10 @@
</div>
<div t-name="website.snippets.references" data-snippet-id='references' data-category='business' data-selector-children='.oe_structure, [data-oe-type=html]'>
<div class='oe_snippet_thumbnail'>References</div>
<div class='oe_snippet_thumbnail'>
<img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_references.png"/>
<span class="oe_snippet_thumbnail_title">References</span>
</div>
<section class="oe_snippet_body mb32 mt16">
<div class="container">
<div class="row">
@@ -796,25 +765,11 @@
</div>
<div t-name="website.snippets.parallax" data-snippet-id='parallax' data-category='effect' data-selector-children='.oe_structure, [data-oe-type=html]'>
<div class='oe_snippet_thumbnail'>Parallax</div>
<li class="oe_snippet_options dropdown-submenu">
<a tabindex="-1" href="#">Background</a>
<ul class="dropdown-menu" name="parallax-background">
<li data-value="/website/static/src/img/parallax/parallax_bg.jpg"><a>Parallax</a></li>
<li data-value="/website/static/src/img/banner/aqua.jpg"><a>Aqua</a></li>
<li data-value="/website/static/src/img/banner/baby_blue.jpg"><a>Baby Blue</a></li>
<li data-value="/website/static/src/img/banner/black.jpg"><a>Black</a></li>
<li data-value="/website/static/src/img/banner/color_splash.jpg"><a>Color Splash</a></li>
<li data-value="/website/static/src/img/banner/greenfields.jpg"><a>Greenfields</a></li>
<li data-value="/website/static/src/img/banner/landscape.jpg"><a>Landscape</a></li>
<li data-value="/website/static/src/img/banner/mango.jpg"><a>Mango</a></li>
<li data-value="/website/static/src/img/banner/flower.jpg"><a>Purple</a></li>
<li class="oe_custom_bg"><b></b></li>
</ul>
</li>
<section class="oe_snippet_body parallax_full oe_structure" style="background-image: url(/website/static/src/img/parallax/parallax_bg.jpg)">
<div class='oe_snippet_thumbnail'>
<img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_parallax.png"/>
<span class="oe_snippet_thumbnail_title">Parallax</span>
</div>
<section class="oe_snippet_body parallax_full oe_structure">
<div class="container">
<div class="row">
<div class="col-md-12 mt128 mb32">
@@ -828,7 +783,7 @@
</div>
</div>
</section>
</div>
</templates>
+2 -2
View File
@@ -1,4 +1,4 @@
# -*- coding: utf-8 -*-
import test_views
import test_views, test_converter
checks = [ test_views ]
checks = [ test_views, test_converter, ]
+119
View File
@@ -0,0 +1,119 @@
# -*- coding: utf-8 -*-
from collections import namedtuple
from functools import partial
from xml.dom.minidom import getDOMImplementation
from lxml import etree, html
from openerp.tests import common
from openerp.tools import qweb
import unittest2
renderer = qweb.QWebXml()
impl = getDOMImplementation()
document = impl.createDocument(None, None, None)
Request = namedtuple('Request', 'cr uid registry')
class RegistryProxy(object):
def __init__(self, func):
self.func = func
def __getitem__(self, name):
return self.func(name)
class TestConvertBack(common.TransactionCase):
def setUp(self):
super(TestConvertBack, self).setUp()
self.Converter = self.registry('ir.fields.converter')
def field_rountrip_result(self, field, value, expected):
model = 'website.converter.test'
Model = self.registry(model)
id = Model.create(
self.cr, self.uid, {
field: value
})
[record] = Model.browse(self.cr, self.uid, [id])
e = document.createElement('span')
field_value = 'record.%s' % field
e.setAttribute('t-field', field_value)
rendered = renderer.render_tag_field(
e, {'field': field_value}, '', {
'record': record,
'request': Request(self.cr, self.uid, RegistryProxy( self.registry)),
})
element = html.fromstring(
rendered, parser=html.HTMLParser(encoding='utf-8'))
column = Model._all_columns[field].column
from_html = self.Converter.to_field(
self.cr, self.uid, model, column, 'html')
value_back, warnings = from_html(element)
self.assertEqual(warnings, [])
if isinstance(expected, str):
expected = expected.decode('utf-8')
self.assertEqual(value_back, expected)
def field_roundtrip(self, field, value):
self.field_rountrip_result(field, value, value)
def test_integer(self):
self.field_roundtrip('integer', 42)
def test_float(self):
self.field_roundtrip('float', 42.567890)
def test_numeric(self):
self.field_roundtrip('numeric', 42.77)
def test_char(self):
self.field_roundtrip('char', "foo bar")
self.field_roundtrip('char', "ⒸⓄⓇⒼⒺ")
def test_m2o(self):
Sub = self.registry('website.converter.test.sub')
sub = partial(Sub.create, self.cr, self.uid)
ids = [
sub({'name': "Foo"}),
sub({'name': "Bar"}),
sub({'name': "Baz"}),
]
self.field_rountrip_result(
'many2one',
ids[2],
ids[2])
def test_selection(self):
self.field_roundtrip('selection', 3)
def test_selection_str(self):
self.field_roundtrip('selection_str', 'B')
def test_text(self):
self.field_roundtrip('text', """
You must obey the dance commander
Givin' out the order for fun
You must obey the dance commander
You know that he's the only one
Who gives the orders here,
Alright
Who gives the orders here,
Alright
It would be awesome
If we could dance-a
It would be awesome, yeah
Let's take the chance-a
It would be awesome, yeah
Let's start the show
Because you never know
You never know
You never know until you go
""")
+20 -5
View File
@@ -364,22 +364,37 @@
<template id="publish_management">
<t t-if="editable" t-ignore="true">
<div t-attf-class="dropdown js_publish_management pull-right #{object.id and object.website_published and 'css_publish' or 'css_unpublish'}" t-att-data-id="object.id" t-att-data-object="object._name">
<a t-attf-class="btn btn-sm btn-#{object.id and object.website_published and 'success' or 'default'}" t-att-id="'dopprod-%s' % object.id" role="button" data-toggle="dropdown">Options <span class="caret"></span></a>
<a t-attf-class="btn btn-xs btn-#{object.id and object.website_published and 'success' or 'default'}" t-att-id="'dopprod-%s' % object.id" role="button" data-toggle="dropdown">Options <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu" t-att-aria-labelledby="'dopprod-%s' % object.id">
<t t-raw="0"/>
<li>
<a href="#" class="js_publish_btn css_unpublish">Unpublish</a>
<a href="#" class="js_publish_btn css_publish">Publish</a>
</li>
<li class="divider"/>
<li>
<a t-att-href="'/admin/#model=%s&amp;id=%s' % (object._name, object.id)">Edit</a>
</li>
<t t-if="publish_edit">
<li class="divider"/>
<li>
<a t-att-href="'/admin/#model=%s&amp;id=%s' % (object._name, object.id)">Edit</a>
</li>
</t>
</ul>
</div>
</t>
</template>
<template id="publish_short">
<t t-if="editable" t-ignore="true">
<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">
<span t-attf-class="text-success css_publish glyphicon glyphicon-ok"></span>
<span t-attf-class="text-danger css_unpublish glyphicon glyphicon-remove-circle"></span>
<span t-attf-class="text-muted css_published glyphicon glyphicon-ok"></span>
<span t-attf-class="text-muted css_unpublished glyphicon glyphicon-remove-circle"></span>
</a>
</t>
</template>
<template id="kanban">
<t t-set="step"><t t-esc="step or 0"/></t>
<t t-set="scope"><t t-esc="scope or 0"/></t>
+1 -1
View File
@@ -57,8 +57,8 @@
</group>
<group string="Others Info">
<field name="company_id" groups="base.group_multi_company"/>
<field name="default_lang_id" widget="selection"/>
<field name="language_ids" widget="many2many_tags"/>
<field name="default_lang_id" widget="selection"/>
</group>
</group>
</sheet>
+8 -3
View File
@@ -21,7 +21,7 @@
from openerp.addons.web import http
from openerp.addons.web.http import request
from openerp.addons.website import website
from openerp.addons.website.models import website
from openerp.tools.translate import _
from openerp.tools.safe_eval import safe_eval
@@ -29,7 +29,7 @@ import simplejson
import werkzeug
class website_mail(http.Controller):
class WebsiteBlog(http.Controller):
_category_post_per_page = 6
_post_comment_per_page = 6
@@ -75,7 +75,8 @@ class website_mail(http.Controller):
blog_post_obj = request.registry['blog.post']
tag_obj = request.registry['blog.tag']
category_obj = request.registry['blog.category']
user_obj = request.registry['res.users']
current_user = request.registry['res.users'].browse(cr, uid, uid, context=context)
tag = None
category = None
@@ -103,6 +104,9 @@ class website_mail(http.Controller):
blog_posts = category.blog_post_ids
elif tag:
blog_posts = tag.blog_post_ids
else:
blog_post_ids = blog_post_obj.search(cr, uid, [], context=context)
blog_posts = blog_post_obj.browse(cr, uid, blog_post_ids, context=context)
if blog_posts:
pager = request.website.pager(
@@ -143,6 +147,7 @@ class website_mail(http.Controller):
'blog_posts': blog_posts,
'pager': pager,
'nav_list': nav,
'current_user': current_user,
'unable_editor': post.get('unable_editor')
}
@@ -32,16 +32,27 @@
</div>
</template>
<!-- Options: Blog Post Summary: hide author -->
<template id="view_blog_post_short_author" inherit_option_id="website_blog.view_blog_post_short" name="Hide Authors">
<xpath expr="//span[@class='icon-user']" position="attributes">
<attribute name="class">hidden</attribute>
</xpath>
</template>
<!-- Options: Blog Post Summary: show category -->
<template id="view_blog_post_short_category" inherit_option_id="website_blog.view_blog_post_short" name="Show Blog Name">
<xpath expr="//span[@class='icon-user']" position="after">
<span class="icon-folder-open"> In <span t-field="blog_post.category_id"/> &amp;nbsp;</span>
</xpath>
</template>
<!-- Blog Post Complete -->
<template id="view_blog_post" name="Blog Post">
<div>
<t t-call="website.publish_management"><t t-set="object" t-value="blog_post"/></t>
<t t-call="website.publish_management">
<t t-set="object" t-value="blog_post"/>
<t t-set="publish_edit" t-value="true"/>
</t>
</div><div class="clearfix"/>
<h1 class="text-center" t-field="blog_post.name"/>
@@ -75,9 +86,11 @@
<ul class="media-list">
<li t-foreach="blog_post.website_message_ids" t-as="message" class="media">
<div class="media-body">
<img class="media-object pull-left" t-att-src="'/website/image?model=res.users&amp;field=image_small&amp;id='+str(message.author_id.id)" style="width: 50px; margin-right: 10px;"/>
<img class="media-object pull-left" t-att-src="'/website/image?model=res.partner&amp;field=image_small&amp;id='+str(message.author_id.id)" style="width: 50px; margin-right: 10px;"/>
<div class="media-body">
<t t-call="website.publish_management"><t t-set="object" t-value="message"/></t>
<t t-call="website.publish_short">
<t t-set="object" t-value="message"/>
</t>
<h5 class="media-heading">
<span t-field="message.author_id"/> <small>on <span t-field="message.date"/></small>
</h5>
@@ -87,12 +100,11 @@
</li>
</ul>
<section groups="group_website_blog_reply" class="mb32">
<t t-call="website_mail.follow"><t t-set="object" t-value="blog_post"/></t>
<h4>Leave a Comment</h4>
<form id="comment" t-attf-action="/blog/#{blog_post.category_id.id}/#{blog_post.id}/post#post"
method="POST">
<img class="img pull-left img-rounded" t-att-src="'/website/image?model=res.partner&amp;field=image_small&amp;id='+str(user_id.partner_id.id)" style="width: 50px; margin-right: 10px;"/>
<div class="pull-left" style="width: 75%%">
<div class="pull-left mb32" style="width: 75%%">
<textarea rows="3" class="form-control" placeholder="Write a comment..."></textarea>
<button type="submit" class="btn btn-danger mt8">Post</button>
</div>
@@ -100,12 +112,19 @@
</section>
</template>
<!-- Options: Blog Post: hide author -->
<template id="view_blog_post_author" inherit_option_id="website_blog.view_blog_post" name="Hide Authors">
<xpath expr="//span[@class='icon-user']" position="attributes">
<attribute name="class">hidden</attribute>
</xpath>
</template>
<!-- Options: Blog Post: show category -->
<template id="view_blog_post_show_category" inherit_option_id="website_blog.view_blog_post" name="Show Blog Name">
<xpath expr="//span[@class='icon-user']" position="after">
<span class="icon-folder-open"> In <span t-field="blog_post.category_id"/> &amp;nbsp;</span>
</xpath>
</template>
<!-- Page -->
<template id="index" name="Blogs" page="True">
@@ -135,6 +154,7 @@
</t>
</template>
<!-- Option: right column -->
<template id="blog_right_column" inherit_id="website_blog.index" inherit_option_id="website_blog.index" name="Right Column">
<xpath expr="//div[@class='row']" position="inside">
<div class="col-sm-3 hidden-xs col-lg-offset-1 mb32" id="right_column">
@@ -146,7 +166,7 @@
</xpath>
</template>
<!-- Option: archives -->
<!-- Option: Right Column: archives -->
<template id="blog_history" inherit_id="website_blog.blog_right_column" inherit_option_id="website_blog.blog_right_column" name="Archives">
<xpath expr="//div[@id='right_column']" position="inside">
<section>
@@ -168,6 +188,7 @@
</xpath>
</template>
<!-- Option: Right Column: about us -->
<template id="blog_aboutus" inherit_option_id="website_blog.blog_right_column" inherit_id="website_blog.blog_right_column" name="About" priority="4">
<xpath expr="//div[@id='right_column']" position="inside">
<section class="mb16">
@@ -183,26 +204,36 @@
</xpath>
</template>
<!-- Option: Right Column: follow us -->
<template id="blog_followus" inherit_option_id="website_blog.blog_right_column" inherit_id="website_blog.blog_right_column" name="Follow us" priority="2">
<xpath expr="//div[@id='right_column']" position="inside">
<section class="mb16">
<h4>Follow us</h4>
<p class="text-muted">
Participate on our social stream.
</p>
<t t-call="website_mail.follow"><t t-set="object" t-value="category"/></t>
<h2>
<a t-att-href="website.social_facebook" t-if="website.social_facebook"><i class="icon-facebook-sign"/></a>
<a t-att-href="website.social_twitter" t-if="website.social_twitter"><i class="icon-twitter-sign"/></a>
<a t-att-href="website.social_linkedin" t-if="website.social_linkedin"><i class="icon-linkedin-sign"/></a>
<a t-att-href="website.social_youtube" t-if="website.social_youtube"><i class="icon-youtube-sign"/></a>
<a t-att-href="website.social_googleplus" t-if="website.social_googleplus"><i class="icon-google-plus-sign"/></a>
<a t-att-href="website.social_github" t-if="website.social_github"><i class="icon-github-sign"/></a>
</h2>
<h4>Follow us</h4>
<t t-if="category">
<p class="text-muted">
Be notified of new blog posts in <t t-esc="category.name"/>
</p>
<t t-call="website_mail.follow">
<t t-set="email" t-value="current_user.email"/>
<t t-set="object" t-value="category"/>
</t>
</t>
<p class="text-muted">
Participate on our social stream.
</p>
<h2>
<a t-att-href="website.social_facebook" t-if="website.social_facebook"><i class="icon-facebook-sign"/></a>
<a t-att-href="website.social_twitter" t-if="website.social_twitter"><i class="icon-twitter-sign"/></a>
<a t-att-href="website.social_linkedin" t-if="website.social_linkedin"><i class="icon-linkedin-sign"/></a>
<a t-att-href="website.social_youtube" t-if="website.social_youtube"><i class="icon-youtube-sign"/></a>
<a t-att-href="website.social_googleplus" t-if="website.social_googleplus"><i class="icon-google-plus-sign"/></a>
<a t-att-href="website.social_github" t-if="website.social_github"><i class="icon-github-sign"/></a>
</h2>
</section>
</xpath>
</template>
<!-- Option: Right Column: categories + category in blog post -->
<template id="blog_categories" inherit_option_id="website_blog.blog_right_column" name="Other Blogs" priority="6">
<xpath expr="//div[@id='right_column']" position="inside">
<section class="mb16">
+8 -3
View File
@@ -76,9 +76,14 @@ class BlogPost(osv.Model):
shorten=True,
max_length=self._shorten_max_char,
expand_options={
'oe_expand_href': '/blog/%d/%d' % (page.category_id.id, page.id),
'oe_expand_a_class': 'oe_mail_expand btn btn-info'
}, br=True
'oe_expand_container_tag': 'div',
'oe_expand_container_class': 'oe_mail_expand text-center',
'oe_expand_container_content': '',
'oe_expand_a_href': '/blog/%d/%d' % (page.category_id.id, page.id),
'oe_expand_a_class': 'oe_mail_expand btn btn-info',
'oe_expand_separator_node': 'br',
},
protect_sections=True,
)
except Exception:
body_short = False
+1 -1
View File
@@ -4,7 +4,7 @@ import openerp
from openerp.addons.web import http
from openerp.tools.translate import _
from openerp.addons.web.http import request
from openerp.addons.website import website
from openerp.addons.website.models import website
import urllib
class website_contract(http.Controller):
+1 -1
View File
@@ -2,7 +2,7 @@
from openerp.addons.web import http
from openerp.addons.web.http import request
from openerp.addons.website import website
from openerp.addons.website.models import website
from urllib import quote_plus
@@ -4,7 +4,7 @@ import openerp
from openerp.addons.web import http
from openerp.tools.translate import _
from openerp.addons.web.http import request
from openerp.addons.website import website
from openerp.addons.website.models import website
import urllib
class website_crm_partner_assign(http.Controller):
+1 -1
View File
@@ -24,7 +24,7 @@ from openerp.addons.web import http
from openerp.addons.web.http import request
from openerp.tools.translate import _
from openerp.addons import website_sale
from openerp.addons.website import website
from openerp.addons.website.models import website
from datetime import datetime
from dateutil.relativedelta import relativedelta
+1 -1
View File
@@ -64,7 +64,7 @@ class event(osv.osv):
class sale_order_line(osv.osv):
_inherit = "sale.order.line"
def _recalculate_product_values(self, cr, uid, ids, product_id=None, context=None):
def _recalculate_product_values(self, cr, uid, ids, product_id=0, context=None):
if not ids:
return super(sale_order_line, self)._recalculate_product_values(cr, uid, ids, product_id, context=context)
+6 -11
View File
@@ -13,14 +13,6 @@
</xpath>
</template>
<template id="event_website_sale_mycart" inherit_id="website_sale.mycart">
<xpath expr="//small[@class='text-error']" position="replace">
<t t-if="(not line.event_id or line.event_ticket_id and line.event_ticket_id.price == line.product_id.lst_price)">
<small class="text-error" style="text-decoration: line-through;"><t t-esc="line.product_id.lst_price" /> €</small>
</t>
</xpath>
</template>
<!-- Page -->
<template id="index" name="Events" page="True">
<t t-call="website.layout">
@@ -156,15 +148,18 @@
<thead>
<tr>
<th>Ticket Type</th>
<th>Sales End</th>
<th>Price</th>
<th style="min-width: 100px">Sales End</th>
<th style="min-width: 100px">Price</th>
<th></th>
<th>Quantity</th>
</tr>
</thead>
<tbody>
<tr t-foreach="event_id.event_ticket_ids" t-as="ticket">
<td><span t-field="ticket.name"/></td>
<td>
<div t-field="ticket.name"/>
<div><small t-field="ticket.product_id.description_sale"/></div>
</td>
<td><span t-field="ticket.deadline"/></td>
<td><span t-field="ticket.price"/></td>
<td>
@@ -3,7 +3,7 @@
import openerp
from openerp.addons.web import http
from openerp.addons.web.http import request
from openerp.addons.website import website
from openerp.addons.website.models import website
from datetime import datetime
class google_map(http.Controller):
+1 -1
View File
@@ -2,7 +2,7 @@
from openerp.addons.web import http
from openerp.addons.web.http import request
from openerp.addons.website import website
from openerp.addons.website.models import website
class website_hr(http.Controller):
+3 -3
View File
@@ -22,7 +22,7 @@
from openerp import SUPERUSER_ID
from openerp.addons.web import http
from openerp.addons.web.http import request
from openerp.addons.website import website
from openerp.addons.website.models import website
class WebsiteMail(http.Controller):
@@ -32,10 +32,10 @@ class WebsiteMail(http.Controller):
partner_obj = request.registry['res.partner']
user_obj = request.registry['res.users']
partner_ids = []
if request.context['is_public_user'] and email:
if request.context['is_public_user'] and email and email != u'false': # post contains stringified booleans
partner_ids = partner_obj.search(request.cr, SUPERUSER_ID, [("email", "=", email)], context=request.context)
if not partner_ids:
partner_ids = [partner_obj.create(request.cr, SUPERUSER_ID, {"email": email, "name": email}, request.context)]
partner_ids = [partner_obj.name_create(request.cr, SUPERUSER_ID, email, request.context)]
else:
partner_ids = [user_obj.browse(request.cr, request.uid, request.uid, request.context).partner_id.id]
return partner_ids
+4
View File
@@ -32,6 +32,10 @@ class MailMessage(osv.Model):
),
}
_defaults = {
'website_published': True,
}
def _search(self, cr, uid, args, offset=0, limit=None, order=None,
context=None, count=False, access_rights_uid=None):
""" Override that adds specific access rights of mail.message, to restrict
@@ -12,12 +12,14 @@ $(document).ready(function () {
$(document).on('click', '.js_follow', function (ev) {
ev.preventDefault();
var $data = $(":first", this).parents("[data-follow]");
var $email = $data.first().siblings(".js_follow_email");
var message_is_follower = $data.first().attr("data-follow");
$data.attr("data-follow", message_is_follower == 'off' ? 'on' : 'off');
$.post('/website_mail/follow', {
'id': $(this).data('id'),
'object': $(this).data('object'),
'message_is_follower': message_is_follower,
'email': $email && $email.val() || false,
}, function (result) {
$data.attr("data-follow", + result ? 'on' : 'off');
});
+1 -1
View File
@@ -19,7 +19,7 @@
#
##############################################################################
from openerp.addons.website_blog.tests import test_controllers
from openerp.addons.website_mail.tests import test_controllers
checks = [
test_controllers,
+14 -1
View File
@@ -20,10 +20,23 @@
##############################################################################
from openerp.addons.mail.tests.test_mail_base import TestMailBase
from openerp.addons.website_mail.controllers.main import WebsiteMail
from openerp.tools import mute_logger, email_split
class TestControllers(TestMailBase):
def test_00(self):
def test_00_subscribe(self):
# from openerp.addons.web.http import request
# print request
cr, uid = self.cr, self.uid
# context = {
# 'is_public_user': True,
# }
# email = 'Marcel Dupuis <marcel.dupuis@example.com>'
# website_mail = WebsiteMail()
# pid = website_mail._find_or_create_partner(email, context)
# partner = self.res_partner.browse(cr, uid, pid)
# print partner.name, partner.email
+5 -2
View File
@@ -6,9 +6,12 @@
<a href="#" t-att-data-id="object.id" t-att-data-object="object._name" t-att-data-follow="object.id and object.message_is_follower and 'on' or 'off'" class="pull-right js_follow" t-if="editable" t-ignore="true">
<span t-attf-class="label label-success css_follow">Follow</span>
<span t-attf-class="label label-danger css_unfollow">Unfollow</span>
<span t-attf-class="label label-success css_followed">Followed</span>
<span t-attf-class="label label-danger css_unfollowed">Unfollowed</span>
<span t-attf-class="label label-success css_followed">Following</span>
<span t-attf-class="label label-danger css_unfollowed">Not Following</span>
</a>
<input type="email" name="email" class="js_follow_email css_unfollowed_email"
t-att-value="email"
t-att-placeholder="email or 'Email Address'"/>
</template>
<template id="website.layout" inherit_id="website.layout">
+1 -1
View File
@@ -1,2 +1,2 @@
import controllers
import website_membership
import models
@@ -4,7 +4,7 @@ import openerp
from openerp.addons.web import http
from openerp.tools.translate import _
from openerp.addons.web.http import request
from openerp.addons.website import website
from openerp.addons.website.models import website
import urllib
class website_crm_partner_assign(http.Controller):
@@ -0,0 +1 @@
import res_partner
@@ -2,9 +2,13 @@
from openerp.osv import osv, fields
class res_partner(osv.osv):
class WebsiteResPartner(osv.Model):
_inherit = 'res.partner'
_columns = {
'website_published': fields.boolean(
'Publish', help="Publish on the website"),
'website_description': fields.html('Description for the website'),
'website_short_description': fields.text('Sort description for the website'),
}
+1 -1
View File
@@ -21,7 +21,7 @@
from openerp.addons.web import http
from openerp.addons.web.http import request
from openerp.addons.website import website
from openerp.addons.website.models import website
from openerp.osv import osv
+29 -37
View File
@@ -4,7 +4,7 @@ from openerp import SUPERUSER_ID
from openerp.osv import osv
from openerp.addons.web import http
from openerp.addons.web.http import request
from openerp.addons.website import website
from openerp.addons.website.models import website
import random
def get_order(order_id=None):
@@ -12,19 +12,19 @@ def get_order(order_id=None):
# check if order allready exists
if order_id:
try:
order = order_obj.browse(request.cr, SUPERUSER_ID, order_id, request.context)
order = order_obj.browse(request.cr, SUPERUSER_ID, order_id, context=request.context)
order.pricelist_id
except:
order_id = None
if not order_id:
fields = [k for k, v in order_obj._columns.items()]
order_value = order_obj.default_get(request.cr, SUPERUSER_ID, fields, request.context)
order_value = order_obj.default_get(request.cr, SUPERUSER_ID, fields, context=request.context)
if request.httprequest.session.get('ecommerce_pricelist'):
order_value['pricelist_id'] = request.httprequest.session['ecommerce_pricelist']
order_value['partner_id'] = request.registry.get('res.users').browse(request.cr, SUPERUSER_ID, request.uid, request.context).partner_id.id
order_value['partner_id'] = request.registry.get('res.users').browse(request.cr, SUPERUSER_ID, request.uid, context=request.context).partner_id.id
order_value.update(order_obj.onchange_partner_id(request.cr, SUPERUSER_ID, [], order_value['partner_id'], context=request.context)['value'])
order_id = order_obj.create(request.cr, SUPERUSER_ID, order_value, request.context)
order = order_obj.browse(request.cr, SUPERUSER_ID, order_id, request.context)
order_id = order_obj.create(request.cr, SUPERUSER_ID, order_value, context=request.context)
order = order_obj.browse(request.cr, SUPERUSER_ID, order_id, context=request.context)
request.httprequest.session['ecommerce_order_id'] = order.id
return order_obj.browse(request.cr, SUPERUSER_ID, order_id,
@@ -176,7 +176,7 @@ class Ecommerce(http.Controller):
fill_hole_products = []
# search for checking of access rules and keep order
fill_hole = [id for id in fill_hole if id in product_obj.search(request.cr, request.uid, [("id", 'in', fill_hole)], context=request.context)]
for product in product_obj.browse(request.cr, SUPERUSER_ID, fill_hole, context=request.context):
for product in product_obj.browse(request.cr, request.uid, fill_hole, context=request.context):
fill_hole_products.append(product)
fill_hole_products.reverse()
@@ -200,7 +200,7 @@ class Ecommerce(http.Controller):
request.context['pricelist'] = self.get_pricelist()
# search for checking of access rules and keep order
product_ids = [id for id in product_ids if id in product_obj.search(request.cr, request.uid, [("id", 'in', product_ids)], context=request.context)]
return product_obj.browse(request.cr, SUPERUSER_ID, product_ids, context=request.context)
return product_obj.browse(request.cr, request.uid, product_ids, context=request.context)
@website.route(['/shop/', '/shop/category/<cat_id>/', '/shop/category/<cat_id>/page/<int:page>/', '/shop/page/<int:page>/'], type='http', auth="public", multilang=True)
def category(self, cat_id=0, page=0, **post):
@@ -250,26 +250,24 @@ class Ecommerce(http.Controller):
}
return request.website.render("website_sale.products", values)
@website.route(['/shop/product/<product_id>/'], type='http', auth="public", multilang=True)
@website.route(['/shop/product/<int:product_id>/'], type='http', auth="public", multilang=True)
def product(self, cat_id=0, product_id=0, **post):
if 'promo' in post:
self.change_pricelist(post.get('promo'))
product_id = product_id and int(product_id) or 0
product_obj = request.registry.get('product.template')
category_obj = request.registry.get('product.public.category')
category_ids = category_obj.search(request.cr, request.uid, [(1, '=', 1)], context=request.context)
category_list = category_obj.name_get(request.cr, request.uid, category_ids, request.context)
category_list = category_obj.name_get(request.cr, request.uid, category_ids, context=request.context)
category_list = sorted(category_list, key=lambda category: category[1])
request.context['pricelist'] = self.get_pricelist()
category = None
if post.get('category_id') and int(post.get('category_id')):
category = category_obj.browse(request.cr, request.uid, int(post.get('category_id')), context=request.context)
request.context['pricelist'] = self.get_pricelist()
product = product_obj.browse(request.cr, request.uid, product_id, context=request.context)
values = {
@@ -282,7 +280,7 @@ class Ecommerce(http.Controller):
}
return request.website.render("website_sale.product", values)
@website.route(['/shop/add_product/', '/shop/category/<cat_id>/add_product/'], type='http', auth="public", multilang=True)
@website.route(['/shop/add_product/', '/shop/category/<int:cat_id>/add_product/'], type='http', auth="public", multilang=True)
def add_product(self, cat_id=0, **post):
product_id = request.registry.get('product.product').create(request.cr, request.uid,
{'name': 'New Product', 'public_categ_id': cat_id}, request.context)
@@ -320,13 +318,11 @@ class Ecommerce(http.Controller):
def add_product_to_cart(self, product_id=0, order_line_id=0, number=1, set_number=-1):
order_line_obj = request.registry.get('sale.order.line')
product_id = product_id and int(product_id) or 0
order = get_current_order()
if not order:
order = get_order()
context = dict(request.context, pricelist=self.get_pricelist())
request.context = dict(request.context, pricelist=self.get_pricelist())
quantity = 0
@@ -339,9 +335,9 @@ class Ecommerce(http.Controller):
else:
domain += [('product_id', '=', product_id)]
order_line_ids = order_line_obj.search(request.cr, SUPERUSER_ID, domain, context=context)
order_line_ids = order_line_obj.search(request.cr, SUPERUSER_ID, domain, context=request.context)
if order_line_ids:
order_line = order_line_obj.read(request.cr, SUPERUSER_ID, order_line_ids, [], context=context)[0]
order_line = order_line_obj.read(request.cr, SUPERUSER_ID, order_line_ids, [], context=request.context)[0]
if not product_id:
product_id = order_line['product_id'][0]
if set_number >= 0:
@@ -352,11 +348,11 @@ class Ecommerce(http.Controller):
quantity = 0
else:
fields = [k for k, v in order_line_obj._columns.items()]
values = order_line_obj.default_get(request.cr, SUPERUSER_ID, fields, context=context)
values = order_line_obj.default_get(request.cr, SUPERUSER_ID, fields, context=request.context)
quantity = 1
# change and record value
vals = order_line_obj._recalculate_product_values(request.cr, request.uid, order_line_ids, product_id, context=context)
vals = order_line_obj._recalculate_product_values(request.cr, request.uid, order_line_ids, product_id, context=request.context)
values.update(vals)
values['product_uom_qty'] = quantity
@@ -364,13 +360,13 @@ class Ecommerce(http.Controller):
values['order_id'] = order.id
if order_line_ids:
order_line_obj.write(request.cr, SUPERUSER_ID, order_line_ids, values, context=context)
order_line_obj.write(request.cr, SUPERUSER_ID, order_line_ids, values, context=request.context)
if not quantity:
order_line_obj.unlink(request.cr, SUPERUSER_ID, order_line_ids, context=context)
order_line_obj.unlink(request.cr, SUPERUSER_ID, order_line_ids, context=request.context)
else:
#values['name'] = "website order"
order_line_id = order_line_obj.create(request.cr, SUPERUSER_ID, values, context=context)
order.write({'order_line': [(4, order_line_id)]}, context=context)
order_line_id = order_line_obj.create(request.cr, SUPERUSER_ID, values, context=request.context)
order.write({'order_line': [(4, order_line_id)]}, context=request.context)
return [quantity, order.get_total_quantity()]
@@ -395,6 +391,7 @@ class Ecommerce(http.Controller):
suggested_products.append(suggested_ids.pop(index))
values = {
'int': int,
'get_categories': self.get_categories,
'suggested_products': prod_obj.browse(request.cr, request.uid, suggested_products, request.context),
}
@@ -402,7 +399,7 @@ class Ecommerce(http.Controller):
@website.route(['/shop/<path:path>/add_cart/', '/shop/add_cart/'], type='http', auth="public", multilang=True)
def add_cart(self, path=None, product_id=None, order_line_id=None, remove=None, **kw):
self.add_product_to_cart(product_id=product_id, order_line_id=order_line_id, number=(remove and -1 or 1))
self.add_product_to_cart(product_id=product_id and int(product_id), order_line_id=order_line_id and int(order_line_id), number=(remove and -1 or 1))
return request.redirect("/shop/mycart/")
@website.route(['/shop/add_cart_json/'], type='json', auth="public")
@@ -415,7 +412,7 @@ class Ecommerce(http.Controller):
@website.route(['/shop/checkout/'], type='http', auth="public", multilang=True)
def checkout(self, **post):
classic_fields = ["name", "phone", "fax", "email", "street", "city", "state_id", "zip"]
classic_fields = ["name", "phone", "email", "street", "city", "state_id", "zip"]
rel_fields = ['country_id', 'state_id']
order = get_current_order()
@@ -488,7 +485,6 @@ class Ecommerce(http.Controller):
company_id = partner_obj.create(request.cr, SUPERUSER_ID, {'name': post['company'], 'is_company': True}, request.context)
partner_value = {
'fax': post['fax'],
'phone': post['phone'],
'zip': post['zip'],
'email': post['email'],
@@ -508,7 +504,6 @@ class Ecommerce(http.Controller):
shipping_id = None
if post.get('shipping_different'):
shipping_value = {
'fax': post['shipping_fax'],
'phone': post['shipping_phone'],
'zip': post['shipping_zip'],
'street': post['shipping_street'],
@@ -570,14 +565,14 @@ class Ecommerce(http.Controller):
def change_sequence(self, id, top):
product_obj = request.registry.get('product.template')
if top:
product_obj.set_sequence_top(request.cr, request.uid, [id], request.context)
product_obj.set_sequence_top(request.cr, request.uid, [id], context=request.context)
else:
product_obj.set_sequence_bottom(request.cr, request.uid, [id], request.context)
product_obj.set_sequence_bottom(request.cr, request.uid, [id], context=request.context)
@website.route(['/shop/change_styles/'], type='json', auth="public")
def change_styles(self, id, style_id):
product_obj = request.registry.get('product.template')
product = product_obj.browse(request.cr, request.uid, id, request.context)
product = product_obj.browse(request.cr, request.uid, id, context=request.context)
remove = []
active = False
@@ -587,14 +582,11 @@ class Ecommerce(http.Controller):
active = True
break
style = request.registry.get('website.product.style').browse(request.cr, request.uid, style_id, request.context)
style = request.registry.get('website.product.style').browse(request.cr, request.uid, style_id, context=request.context)
if remove:
print "remove", remove
product.write({'website_style_ids': [(3, rid) for rid in remove]})
if not active:
print "add", style.id
product.write({'website_style_ids': [(4, style.id)]})
return not active
@@ -602,7 +594,7 @@ class Ecommerce(http.Controller):
@website.route(['/shop/change_size/'], type='json', auth="public")
def change_size(self, id, x, y):
product_obj = request.registry.get('product.template')
product = product_obj.browse(request.cr, request.uid, id, request.context)
product = product_obj.browse(request.cr, request.uid, id, context=request.context)
return product.write({'website_size_x': x, 'website_size_y': y})
# vim:expandtab:tabstop=4:softtabstop=4:shiftwidth=4:
@@ -1,4 +1,7 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_product_product_public,product.product.public,product.model_product_product,base.group_public,1,0,0,0
access_product_template_public,product.template.public,product.model_product_template,base.group_public,1,0,0,0
access_point_of_sale_category_public,product.category.public,product.model_product_public_category,base.group_public,1,0,0,0
access_product_category_,product.category,product.model_product_category,base.group_public,1,0,0,0
access_product_category_public,product.category.public,product.model_product_public_category,base.group_public,1,0,0,0
access_product_pricelist_version_public,product.pricelist.version,product.model_product_pricelist_version,base.group_public,1,0,0,0
access_product_product_price_type_public,product.price.type,product.model_product_price_type,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_product_product_public product.product.public product.model_product_product base.group_public 1 0 0 0
3 access_product_template_public product.template.public product.model_product_template base.group_public 1 0 0 0
4 access_point_of_sale_category_public access_product_category_ product.category.public product.category product.model_product_public_category product.model_product_category base.group_public 1 0 0 0
5 access_product_category_public product.category.public product.model_product_public_category base.group_public 1 0 0 0
6 access_product_pricelist_version_public product.pricelist.version product.model_product_pricelist_version base.group_public 1 0 0 0
7 access_product_product_price_type_public product.price.type product.model_product_price_type base.group_public 1 0 0 0
Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

@@ -15,8 +15,11 @@
<div class="oe_span6">
<p class='oe_mt32'>
OpenERP e-Commerce is unlike anything you have ever seen before.
It's at the same time full-featured, integrated with your
management software, fully customizable and super easy.
Get an awesome catalog of products and great product description
pages.
</p><p>
It's full-featured, integrated with your management software,
fully customizable and super easy.
</p>
<div class="oe_centeralign oe_websiteonly">
<a href="http://www.openerp.com/start?app=website_sale" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> online store</a>
@@ -43,7 +46,7 @@
</div>
<div class="oe_span6">
<div class="oe_bg_img oe_centered">
<img class="oe_picture" src="website_sale_product.png">
<img class="oe_picture oe_screenshot" src="website_sale_product.png">
</div>
</div>
</div>
@@ -54,18 +57,18 @@
<h2 class="oe_slogan">Increase Your Revenue Per Order</h2>
<h3 class="oe_slogan">Do you want fries with that?</h3>
<div class="oe_span6">
<img class="oe_picture oe_screenshot" src="">
<img class="oe_picture oe_screenshot" src="suggested.png">
</div>
<div class="oe_span6">
<p class='oe_mt32'>
Use the built-in cross-selling feature helps you offer extra
The built-in cross-selling feature helps you offer extra
products related to what the shopper put in his cart. (e.g.
accessories)
</p><p>
OpenERP's upselling algorythm allows you to show visitors
similar but more expensive products than the one in view, with
incentives like customer ratings. (social validation)
</p><p>
incentives.
</p><p>
The inline editing feature allows you to easily change a price,
launch a promotion or fine tune the description of a product,
in a just a click.
@@ -85,11 +88,11 @@
events related to shopping carts, call-to-actions, etc.
</p><p>
As OpenERP marketing tools (mass mailing, campaigns, etc) are also
linked with Google Analytics, you get a 360° view of your business.
linked with Google Analytics, you get a complete view of your business.
</p>
</div>
<div class="oe_span6">
<img class="oe_picture oe_screenshot" src="">
<img class="oe_picture oe_screenshot" src="analytics.png">
</div>
</div>
</section>
@@ -100,7 +103,7 @@
<h3 class="oe_slogan">Multi-languages Without Pain</h3>
<div class="oe_span6">
<div class="oe_bg_img">
<img class="oe_picture" src="">
<img class="oe_picture oe_screenshot" src="openerp_translation_tool.png">
</div>
</div>
<div class="oe_span6">
@@ -121,22 +124,21 @@
<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>
<h2 class="oe_slogan">Fine Tune Your Catalog</h2>
<h3 class="oe_slogan">Boost Sales by Emphasazing Best Products</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.
Get a full control on how you display your products in
the catalog page: promotional ribbons, related sized of products,
discounts, variants, grid/list view, etc.
</p><p>
The building block approach allows the website to remain clean
after the end-users start creating new contents.
Edit any product inline to make your website evolve with
your customer need.
</p>
</div>
<div class="oe_span6">
<div class="oe_row_img oe_centered">
<img class="oe_picture" src="">
<img class="oe_picture oe_screenshot" src="ribbon.png">
</div>
</div>
</div>
@@ -148,7 +150,7 @@
<h3 class="oe_slogan">SEO tools at your finger tips</h3>
<div class="oe_span6">
<div class="oe_bg_img">
<img class="oe_picture oe_screenshot" src="">
<img class="oe_picture oe_screenshot" src="website_seo.png">
</div>
</div>
<div class="oe_span6">
@@ -178,7 +180,7 @@
</div>
<div class="oe_span6">
<div class="oe_bg_img">
<img class="oe_picture oe_screenshot" src="">
<img class="oe_picture oe_screenshot" src="website_edit.png">
</div>
</div>
</div>
@@ -187,11 +189,11 @@
<section class="oe_container">
<div class="oe_row">
<h2 class="oe_slogan">Manage a Resellers Network</h2>
<h2 class="oe_slogan">Manage a Reseller Network</h2>
<h3 class="oe_slogan">Referencing, Lead Forward, Pricelists</h3>
<div class="oe_span6">
<div class="oe_bg_img">
<img class="oe_picture oe_screenshot" src="">
<img class="oe_picture oe_screenshot" src="reseller.png">
</div>
</div>
<div class="oe_span6">
@@ -228,7 +230,7 @@
</div>
<div class="oe_span6">
<div class="oe_bg_img oe_centered">
<img class="oe_picture" src="">
<img class="oe_picture" src="warehouse_illu_01.png">
</div>
</div>
</div>
@@ -236,6 +238,28 @@
<section class="oe_container">
<div class="oe_row">
<h2 class="oe_slogan">A Clean Checkout Process</h2>
<div class="oe_span6">
<p class='oe_mt32'>
Convert most visitor interests into real orders with a
clean checkout process with a minimal number of steps
and a great useability on every page.
</p><p>
Customize your checkout process to fit your business needs:
payment modes, delivery methods, cross-selling, special conditions, etc.
</p>
</div>
<div class="oe_span6">
<div class="oe_bg_img oe_centered">
<img class="oe_picture oe_screenshot" src="checkout.png">
</div>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row">
<h2 class="oe_slogan">And much more...</h2>
<div class="oe_span4">
@@ -246,6 +270,7 @@
<li>Flexible pricelists</li>
<li>Product multi-variants</li>
<li>Multiple stores</li>
<li>Great checkout process</li>
</ul>
</div>
<div class="oe_span4">
@@ -279,7 +304,7 @@
<a href="/apps/website">
<h3>CMS</h3>
<div class="oe_row_img oe_centered">
<img class="oe_picture oe_screenshot" src="">
<img class="oe_picture oe_screenshot" src="website_home.png">
</div>
</a>
<p>
@@ -301,7 +326,7 @@
<a href="/apps/website_event">
<h3>Online Events</h3>
<div class="oe_row_img oe_centered">
<img class="oe_picture oe_screenshot" src="">
<img class="oe_picture oe_screenshot" src="event_top.png">
</div>
</a>
<p>
Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

@@ -1,5 +1,20 @@
@charset "utf-8";
/* ---- Default Styles Description ---- */
/* ---- Default Styles ---- */
.oe_product {
border: 1px solid rgba(100, 100, 100, 0.2);
}
.oe_product_description {
background: rgba(255, 255, 255, 0.8);
padding: 5px 0 5px 0;
z-index: 5;
}
.oe_subdescription {
line-height: 1.2;
margin-bottom: 4px;
}
.oe_product_image {
position: absolute;
}
@@ -12,8 +27,16 @@
left: 0;
bottom: 0;
right: 0;
z-index: 4;
}
.oe_product .oe_product_cart {
position: relative;
width: 100%;
height: 100%;
}
/* ---- Default Styles Description ---- */
.oe_product .oe_product_image {
position: absolute;
left: 15px;
@@ -30,6 +53,11 @@
border-top: 1px solid #dddddd;
}
.oe_mycart .input-group-addon {
padding-left: 6px;
padding-right: 6px;
}
.oe_shop_top .oe_product_description {
top: 0;
bottom: auto;
@@ -53,28 +81,6 @@
bottom: 0;
}
/* ---- Default Styles ---- */
.oe_product {
border: 1px solid rgba(100, 100, 100, 0.2);
}
.oe_product .oe_product_image img {
max-width: 100%;
max-height: 100%;
z-index: 4;
}
.oe_product_description {
background: rgba(255, 255, 255, 0.8);
padding: 5px 0 5px 0;
z-index: 5;
}
.oe_subdescription {
line-height: 1.2;
margin-bottom: 4px;
}
/* ---- Grid Style ---- */
.style1 .oe_product .oe_product_image {
position: absolute;
@@ -91,12 +97,15 @@
.col-md-12 .oe-height-2 {
height: 150px;
}
.col-md-12 .oe-height-3 {
height: 225px;
}
.col-md-12 .oe-height-4 {
height: 300px;
}
.col-md-12 .oe-height-6 {
height: 450px;
}
.col-md-12 .oe-height-8 {
height: 600px;
}
.col-md-9 .oe-height-1 {
height: 70px;
@@ -104,12 +113,15 @@
.col-md-9 .oe-height-2 {
height: 140px;
}
.col-md-9 .oe-height-3 {
height: 210px;
}
.col-md-9 .oe-height-4 {
height: 280px;
}
.col-md-9 .oe-height-6 {
height: 420px;
}
.col-md-9 .oe-height-8 {
height: 560px;
}
@media (max-width: 728px) {
.oe_product {
@@ -135,12 +147,15 @@
.col-md-12 .oe-height-2 {
height: 190px;
}
.col-md-12 .oe-height-3 {
height: 285px;
}
.col-md-12 .oe-height-4 {
height: 380px;
}
.col-md-12 .oe-height-6 {
height: 570px;
}
.col-md-12 .oe-height-8 {
height: 760px;
}
.col-md-9 .oe-height-1 {
height: 72px;
@@ -148,12 +163,15 @@
.col-md-9 .oe-height-2 {
height: 144px;
}
.col-md-9 .oe-height-3 {
height: 216px;
}
.col-md-9 .oe-height-4 {
height: 288px;
}
.col-md-9 .oe-height-6 {
height: 432px;
}
.col-md-9 .oe-height-8 {
height: 576px;
}
}
@media (min-width: 1200px) {
.col-md-12 .oe-height-1 {
@@ -162,11 +180,14 @@
.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;
height: 500px;
}
.col-md-12 .oe-height-6 {
height: 750px;
}
.col-md-12 .oe-height-8 {
height: 1000px;
}
.col-md-9 .oe-height-1 {
@@ -175,12 +196,15 @@
.col-md-9 .oe-height-2 {
height: 190px;
}
.col-md-9 .oe-height-3 {
height: 285px;
}
.col-md-9 .oe-height-4 {
height: 380px;
}
.col-md-9 .oe-height-6 {
height: 570px;
}
.col-md-9 .oe-height-8 {
height: 760px;
}
}
/* ---- Product list style ---- */
.oe_list_products {
@@ -233,14 +257,17 @@
border: 1px #dddddd solid;
cursor: pointer;
}
#products_grid .css_options .dropdown [name="size"] td.selected, #products_grid .css_options .dropdown [name="size"] td.select {
#products_grid .css_options .dropdown [name="size"] td.selected {
background-color: #b1d4f1;
}
#products_grid .css_options .dropdown [name="size"] table.oe_hover td.selected:not(.select) {
#products_grid .css_options .dropdown [name="size"] table.oe_hover td.selected {
background-color: transparent;
}
#products_grid .css_options .dropdown [name="size"] table.oe_hover td.select {
background-color: #b1d4f1;
}
.cke_editable #products_grid td:hover > .css_options {
.cke_editable #products_grid .oe_product_cart:hover > .css_options {
display: block;
}
@@ -284,3 +311,69 @@
-moz-box-shadow: 0px 0px 3px rgba(0, 0, 0, 0.3);
box-shadow: 0px 0px 3px rgba(0, 0, 0, 0.3);
}
/* Wizard */
ul.wizard {
padding: 0;
margin-top: 20px;
list-style: none outside none;
border: 1px solid #d4d4d4;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.065);
-moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.065);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.065);
}
ul.wizard li {
position: relative;
float: left;
padding: 0 10px 0 20px;
margin: 0;
line-height: 38px;
background: #fbfbfb;
}
ul.wizard li .chevron {
position: absolute;
top: 0;
right: -10px;
z-index: 1;
display: block;
border: 20px solid transparent;
border-right: 0;
border-left: 10px solid #d4d4d4;
}
ul.wizard li .chevron:before {
position: absolute;
top: -20px;
right: 1px;
display: block;
border: 20px solid transparent;
border-right: 0;
border-left: 10px solid #fbfbfb;
content: "";
}
ul.wizard li.text-success {
background: #f3f4f5;
}
ul.wizard li.text-success .chevron:before {
border-left: 10px solid whitesmoke;
}
ul.wizard li.text-primary {
background: #f1f6fc;
}
ul.wizard li.text-primary .chevron:before {
border-left: 10px solid #f1f6fc;
}
ul.wizard li:first-child {
padding-left: 15px;
border-radius: 4px 0 0 4px;
}
@@ -1,6 +1,18 @@
@charset "utf-8"
/* ---- Default Styles Description ---- */
/* ---- Default Styles ---- */
.oe_product
border: 1px solid rgba(100,100,100,0.2)
.oe_product_description
background: rgba(255,255, 255, 0.8)
padding: 5px 0 5px 0
z-index: 5
.oe_subdescription
line-height: 1.2
margin-bottom: 4px
.oe_product_image
position: absolute
@@ -13,6 +25,15 @@
left: 0
bottom: 0
right: 0
z-index: 4
.oe_product
.oe_product_cart
position: relative
width: 100%
height: 100%
/* ---- Default Styles Description ---- */
.oe_product
.oe_product_image
@@ -29,6 +50,11 @@
right: 15px
border-top: 1px solid #dddddd
.oe_mycart
.input-group-addon
padding-left: 6px
padding-right: 6px
.oe_shop_top /* Option 1 */
.oe_product_description
@@ -53,26 +79,6 @@
top: 0
bottom: 0
/* ---- Default Styles ---- */
.oe_product
border: 1px solid rgba(100,100,100,0.2)
.oe_product .oe_product_image img
max-width: 100%
max-height: 100%
z-index: 4
.oe_product_description
background: rgba(255,255, 255, 0.8)
padding: 5px 0 5px 0
z-index: 5
.oe_subdescription
line-height: 1.2
margin-bottom: 4px
/* ---- Grid Style ---- */
.style1
@@ -89,19 +95,23 @@
height: 75px
.oe-height-2
height: 150px
.oe-height-3
height: 225px
.oe-height-4
height: 300px
.oe-height-6
height: 450px
.oe-height-8
height: 600px
.col-md-9
.oe-height-1
height: 70px
.oe-height-2
height: 140px
.oe-height-3
height: 210px
.oe-height-4
height: 280px
.oe-height-6
height: 420px
.oe-height-8
height: 560px
@media (max-width: 728px)
.oe_product
@@ -123,19 +133,23 @@
height: 95px
.oe-height-2
height: 190px
.oe-height-3
height: 285px
.oe-height-4
height: 380px
.oe-height-6
height: 570px
.oe-height-8
height: 760px
.col-md-9
.oe-height-1
height: 72px
.oe-height-2
height: 144px
.oe-height-3
height: 216px
.oe-height-4
height: 288px
.oe-height-6
height: 432px
.oe-height-8
height: 576px
@media (min-width: 1200px)
.col-md-12
@@ -143,19 +157,23 @@
height: 125px
.oe-height-2
height: 250px
.oe-height-3
height: 375px
.oe-height-4
height: 499.9px
height: 500px
.oe-height-6
height: 750px
.oe-height-8
height: 1000px
.col-md-9
.oe-height-1
height: 95px
.oe-height-2
height: 190px
.oe-height-3
height: 285px
.oe-height-4
height: 380px
.oe-height-6
height: 570px
.oe-height-8
height: 760px
/* ---- Product list style ---- */
.oe_list_products
@@ -202,13 +220,15 @@
height: 20px
border: 1px #dddddd solid
cursor: pointer
&.selected, &.select
&.selected
background-color: #B1D4F1
table.oe_hover td.selected:not(.select)
table.oe_hover td.selected
background-color: transparent
table.oe_hover td.select
background-color: #B1D4F1
.cke_editable
#products_grid td:hover > .css_options
#products_grid .oe_product_cart:hover > .css_options
display: block
/* Ribbon for promotionso on products */
@@ -250,3 +270,64 @@
-webkit-box-shadow: 0px 0px 3px rgba(0,0,0,0.3)
-moz-box-shadow: 0px 0px 3px rgba(0,0,0,0.3)
box-shadow: 0px 0px 3px rgba(0,0,0,0.3)
/* Wizard */
ul.wizard
padding: 0
margin-top: 20px
list-style: none outside none
border: 1px solid #d4d4d4
-webkit-border-radius: 4px
-moz-border-radius: 4px
border-radius: 4px
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.065)
-moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.065)
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.065)
ul.wizard li
position: relative
float: left
padding: 0 10px 0 20px
margin: 0
line-height: 38px
background: #fbfbfb
ul.wizard li .chevron
position: absolute
top: 0
right: -10px
z-index: 1
display: block
border: 20px solid transparent
border-right: 0
border-left: 10px solid #d4d4d4
ul.wizard li .chevron:before
position: absolute
top: -20px
right: 1px
display: block
border: 20px solid transparent
border-right: 0
border-left: 10px solid #fbfbfb
content: ""
ul.wizard li.text-success
background: #f3f4f5
ul.wizard li.text-success .chevron:before
border-left: 10px solid #f5f5f5
ul.wizard li.text-primary
background: #f1f6fc
ul.wizard li.text-primary .chevron:before
border-left: 10px solid #f1f6fc
ul.wizard li:first-child
padding-left: 15px
border-radius: 4px 0 0 4px
@@ -36,20 +36,18 @@ $(document).ready(function () {
});
// hack to add and rome from cart with json
$('.oe_website_sale a[href*="/add_cart/"], a[href*="/remove_cart/"]').on('click', function (ev) {
$('.oe_website_sale a[href*="/add_cart/"],.oe_website_sale a[href*="/remove_cart/"]').on('click', function (ev) {
ev.preventDefault();
var $link = $(ev.currentTarget);
var product_id = $link.attr("href").match(/product_id=([0-9]+)/)[1];
if (product_id) {
product_id = +product_id;
}
var product = $link.attr("href").match(/product_id=([0-9]+)/);
var product_id = product ? +product[1] : 0;
openerp.jsonRpc("/shop/add_cart_json/", 'call', {'product_id': product_id, 'order_line_id': $link.data('id'), 'remove': $link.is('[href*="/remove_cart/"]')})
.then(function (data) {
if (!data[0]) {
location.reload();
}
set_my_cart_quantity(data[1]);
$link.parent().find(".js_quantity").val(data[0]);
$link.parents(".input-group:first").find(".js_quantity").val(data[0]);
});
return false;
});
+430 -380
View File
@@ -49,17 +49,7 @@
<li>
<a t-href="/shop/mycart/">
<i class="icon-shopping-cart"></i>
My cart <span t-attf-class="my_cart_quantity badge #{(not website_sale_order or not website_sale_order.get_total_quantity()) and 'hidden' or ''}"
t-esc="website_sale_order and website_sale_order.get_total_quantity() or ''"/>
</a>
</li>
</xpath>
<xpath expr="//footer//ul[@name='products']" position="inside">
<li><a t-href="/shop/">Shop</a></li>
<li>
<a t-href="/shop/mycart/">
<i class="icon-shopping-cart"></i>
My cart <span t-attf-class="my_cart_quantity badge #{(not website_sale_order or not website_sale_order.get_total_quantity()) and 'hidden' or ''}"
My cart <sup t-attf-class="my_cart_quantity label label-primary #{(not website_sale_order or not website_sale_order.get_total_quantity()) and 'hidden' or ''}"
t-esc="website_sale_order and website_sale_order.get_total_quantity() or ''"/>
</a>
</li>
@@ -141,7 +131,6 @@
<div class="col-md-12" id="products_grid">
<table width="100%">
<colgroup>
<col style="width: 1px; margin-right: -1px;" />
<col class="col-md-3" />
<col class="col-md-3" />
<col class="col-md-3" />
@@ -150,65 +139,67 @@
<tbody>
<t t-set="table_products" t-value="get_bin_packing_products(product_ids, product_ids_for_holes, 4)"/>
<tr t-foreach="table_products" t-as="tr_product">
<td class="oe-height-2"></td>
<t t-foreach="tr_product" t-as="td_product">
<t t-if="td_product">
<t t-set="product" t-value="td_product['product']"/>
<td t-att-colspan="td_product['x']"
t-att-rowspan="td_product['y']"
t-attf-class="oe_product #{ td_product['class'] }"
t-att-data-publish="product.website_published and 'on' or 'off'">
t-attf-class="oe_product oe-height-#{td_product['y']*2} #{ td_product['class'] }">
<div class="css_options" t-ignore="true">
<div t-attf-class="dropdown js_options" t-att-data-id="product.id">
<a class="btn btn-default" t-att-id="'dopprod-%s' % product.id" role="button" data-toggle="dropdown">Options <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu" t-att-aria-labelledby="'dopprod-%s' % product.id">
<li class='dropdown-submenu'>
<a tabindex="-1" href="#">Size</a>
<ul class="dropdown-menu" name="size">
<li><a href="#">
<table>
<tr>
<td class="selected"></td>
<td t-att-class="product.website_size_x > 1 and 'selected'"></td>
<td t-att-class="product.website_size_x > 2 and 'selected'"></td>
<td t-att-class="product.website_size_x > 3 and 'selected'"></td>
</tr>
<tr>
<td t-att-class="product.website_size_y > 1 and 'selected'"></td>
<td t-att-class="product.website_size_y > 1 and product.website_size_x > 1 and 'selected'"></td>
<td t-att-class="product.website_size_y > 1 and product.website_size_x > 2 and 'selected'"></td>
<td t-att-class="product.website_size_y > 1 and product.website_size_x > 3 and 'selected'"></td>
</tr>
<tr>
<td t-att-class="product.website_size_y > 2 and 'selected'"></td>
<td t-att-class="product.website_size_y > 2 and product.website_size_x > 1 and 'selected'"></td>
<td t-att-class="product.website_size_y > 2 and product.website_size_x > 2 and 'selected'"></td>
<td t-att-class="product.website_size_y > 2 and product.website_size_x > 3 and 'selected'"></td>
</tr>
<tr>
<td t-att-class="product.website_size_y > 3 and 'selected'"></td>
<td t-att-class="product.website_size_y > 3 and product.website_size_x > 1 and 'selected'"></td>
<td t-att-class="product.website_size_y > 3 and product.website_size_x > 2 and 'selected'"></td>
<td t-att-class="product.website_size_y > 3 and product.website_size_x > 3 and 'selected'"></td>
</tr>
</table>
</a></li>
</ul>
</li>
<li class='dropdown-submenu'>
<a tabindex="-1" href="#">Styles</a>
<ul class="dropdown-menu" name="style">
<t t-foreach="styles" t-as="style">
<li t-att-class="style.id in [s.id for s in product.website_style_ids] and 'active' or ''"><a href="#" t-att-data-id="style.id" t-att-data-class="style.html_class"><t t-esc="style.name"/></a></li>
</t>
</ul>
</li>
</ul>
<div class="oe_product_cart" t-att-data-publish="product.website_published and 'on' or 'off'">
<div class="css_options" t-ignore="true" t-if="editable">
<div t-attf-class="dropdown js_options" t-att-data-id="product.id">
<a class="btn btn-default" t-att-id="'dopprod-%s' % product.id" role="button" data-toggle="dropdown">Options <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu" t-att-aria-labelledby="'dopprod-%s' % product.id">
<li class='dropdown-submenu'>
<a tabindex="-1" href="#">Size</a>
<ul class="dropdown-menu" name="size">
<li><a href="#">
<table>
<tr>
<td class="selected"></td>
<td t-att-class="product.website_size_x > 1 and 'selected'"></td>
<td t-att-class="product.website_size_x > 2 and 'selected'"></td>
<td t-att-class="product.website_size_x > 3 and 'selected'"></td>
</tr>
<tr>
<td t-att-class="product.website_size_y > 1 and 'selected'"></td>
<td t-att-class="product.website_size_y > 1 and product.website_size_x > 1 and 'selected'"></td>
<td t-att-class="product.website_size_y > 1 and product.website_size_x > 2 and 'selected'"></td>
<td t-att-class="product.website_size_y > 1 and product.website_size_x > 3 and 'selected'"></td>
</tr>
<tr>
<td t-att-class="product.website_size_y > 2 and 'selected'"></td>
<td t-att-class="product.website_size_y > 2 and product.website_size_x > 1 and 'selected'"></td>
<td t-att-class="product.website_size_y > 2 and product.website_size_x > 2 and 'selected'"></td>
<td t-att-class="product.website_size_y > 2 and product.website_size_x > 3 and 'selected'"></td>
</tr>
<tr>
<td t-att-class="product.website_size_y > 3 and 'selected'"></td>
<td t-att-class="product.website_size_y > 3 and product.website_size_x > 1 and 'selected'"></td>
<td t-att-class="product.website_size_y > 3 and product.website_size_x > 2 and 'selected'"></td>
<td t-att-class="product.website_size_y > 3 and product.website_size_x > 3 and 'selected'"></td>
</tr>
</table>
</a></li>
</ul>
</li>
<li class='dropdown-submenu'>
<a tabindex="-1" href="#">Styles</a>
<ul class="dropdown-menu" name="style">
<t t-foreach="styles" t-as="style">
<li t-att-class="style.id in [s.id for s in product.website_style_ids] and 'active' or ''"><a href="#" t-att-data-id="style.id" t-att-data-class="style.html_class"><t t-esc="style.name"/></a></li>
</t>
</ul>
</li>
</ul>
</div>
</div>
<t t-call="website_sale.products_cart"/>
</div>
<t t-call="website_sale.products_cart"/>
</td>
</t>
<td t-if="td_product == None"/>
@@ -322,14 +313,16 @@
</label>
<br/>
</t>
<div>
<t t-if="product.product_variant_ids[0].lst_price != product.product_variant_ids[0].price">
<h5 class="text-danger" style="text-decoration: line-through;" title="Price without reduction"><span t-field="product.product_variant_ids[0].lst_price" /> €</h5>
<h4><t t-esc="product.product_variant_ids[0].price" /> €</h4>
</t>
<h4 t-if="product.product_variant_ids[0].lst_price == product.product_variant_ids[0].price">
<b><span t-field="product.product_variant_ids[0].lst_price" /> €</b>
</h4>
<div class="product_price">
<b>
<t t-if="product.product_variant_ids[0].lst_price != product.product_variant_ids[0].price">
<span class="text-danger" style="text-decoration: line-through;">
<t t-esc="product.product_variant_ids[0].lst_price" /> €
</span>&amp;nbsp;
</t>
<h4><b><t t-esc="product.product_variant_ids[0].price" /> €</b></h4>
</b>
</div>
<button class="btn btn-primary btn-lg mt8">Add to Cart</button>
<hr t-if="product.description_sale"/>
@@ -379,19 +372,32 @@
<t t-call="website.layout">
<t t-set="head">
<script type="text/javascript" src="/website_sale/static/src/js/website_sale.js"></script>
<link rel='stylesheet' href='/website_sale/static/src/css/website_sale.css'/>
<t t-raw="head or ''"/>
</t>
<t t-set="title">Your Cart</t>
<div id="wrap">
<div class="container oe_website_sale">
<div class="col-md-12 oe_mycart">
<h1>My Shopping Cart</h1>
<table class='table' id="mycart_products">
<ul class="wizard pull-right">
<li class="text-primary">Review Order<span class="chevron"></span></li>
<li class="text-muted">Shipping &amp; Billing<span class="chevron"></span></li>
<li class="text-muted">Payment<span class="chevron"></span></li>
<li class="text-muted">Confirmation<span class="chevron"></span></li>
</ul>
<h1 class="mb32">Your Cart</h1>
<div class="row">
<div class="col-md-8 oe_mycart">
<div t-if="not website_sale_order or not website_sale_order.order_line" class="well well-lg">
Your cart is empty!
</div>
<table class='table table-striped table-condensed' id="mycart_products" t-if="website_sale_order and website_sale_order.order_line">
<colgroup>
<col width="80"/>
<col/>
<col width="80"/>
<col width="160"/>
<col width="100"/>
<col width="120"/>
</colgroup>
<thead>
<tr>
@@ -400,52 +406,84 @@
<th>Quantity</th>
</tr>
</thead>
<tbody t-if="not website_sale_order or not website_sale_order.order_line">
<tr><td colspan="4"><h3>Your cart is empty</h3></td></tr>
</tbody>
<tbody t-if="website_sale_order and website_sale_order.order_line">
<t t-foreach="website_sale_order.order_line" t-as="line">
<tr>
<td colspan="2" t-if="not line.product_id.product_tmpl_id"></td>
<td t-if="line.product_id.product_tmpl_id">
<a t-href="/shop/product/#{ line.product_id.product_tmpl_id.id }/"><img class="img-rounded" t-att-src="line.product_id.img('image_small')"/></a>
</td>
<td t-if="line.product_id.product_tmpl_id">
<a t-href="/shop/product/#{ line.product_id.product_tmpl_id.id }/"><span t-field="line.name"/></a><br/>
<small t-field="line.product_id.description_sale"/>
</td>
<td>
<t t-if="line.product_id.product_tmpl_id and line.product_id.lst_price != line.price_unit">
<small class="text-error" style="text-decoration: line-through;"><t t-esc="line.product_id.lst_price" /> €</small>
</t>
<span t-field="line.price_unit"></span> €
</td>
<td>
<div class="pull-right">
<input type="text" class="js_quantity input-sm col-md-5" t-att-data-id="line.id" t-att-value="line.product_uom_qty"/>
<a t-href="./remove_cart/?order_line_id=#{ line.id }" t-att-data-id="line.id" class="btn btn-default mb8 btn-sm btn-inverse">-</a>
<a t-href="./add_cart/?order_line_id=#{ line.id }" t-att-data-id="line.id" class="btn btn-default mb8 btn-sm btn-success">+</a>
</div>
</td>
</tr>
</t>
<tbody>
<tr t-foreach="website_sale_order.order_line" t-as="line">
<td colspan="2" t-if="not line.product_id.product_tmpl_id"></td>
<td t-if="line.product_id.product_tmpl_id">
<a t-href="/shop/product/#{ line.product_id.product_tmpl_id.id }/"><img class="img-rounded" t-att-src="line.product_id.img('image_small')"/></a>
</td>
<td t-if="line.product_id.product_tmpl_id">
<div>
<a t-href="/shop/product/#{ line.product_id.product_tmpl_id.id }/">
<strong t-field="line.product_id.name"/>
</a>
</div>
<div class="text-muted" t-field="line.product_id.description_sale"/>
</td>
<td class="text-center">
<div class="text-danger" style="text-decoration: line-through;" t-if="line.product_id.lst_price &gt; line.price_unit">
<t t-esc="line.product_id.lst_price" /> €
</div>
<span t-field="line.price_unit"></span> €
</td>
<td>
<div class="input-group">
<span class="input-group-addon">
<a t-href="./remove_cart/?order_line_id=#{ line.id }" t-att-data-id="line.id" class="mb8">
<span class="icon-minus"/>
</a>
</span>
<input type="text" class="js_quantity form-control"
t-att-data-id="line.id" t-att-value="int(line.product_uom_qty)"/>
<span class="input-group-addon">
<a t-href="./add_cart/?order_line_id=#{ line.id }" t-att-data-id="line.id" class="mb8 float_left">
<span class="icon-plus"/>
</a>
</span>
</div>
</td>
</tr>
</tbody>
</table>
<table class='table table-hover table-condensed' id="mycart_total">
<table class='pull-right mb16' id="mycart_total">
<colgroup>
<col width="80"/>
<col/>
<col width="80"/>
<col width="160"/>
<col width="100"/>
<col width="120"/>
</colgroup>
<thead>
<tr> <th colspan="3">Subtotal </th> <th><t t-esc="website_sale_order and website_sale_order.amount_untaxed or 0"/> €</th></tr>
<tr> <th colspan="3">Taxes </th> <th><t t-esc="website_sale_order and website_sale_order.amount_tax or 0"/> €</th></tr>
<tr> <th colspan="3"><h4>Total</h4></th> <th><h4><t t-esc="website_sale_order and website_sale_order.amount_total or 0"/> €</h4></th></tr>
<tr style="border-top: 1px solid #000">
<th><h3>Total:</h3></th>
<th class="text-right"><h3><t t-esc="website_sale_order and website_sale_order.amount_total or 0"/> €</h3></th>
</tr>
<tr class="text-muted">
<td><abbr title="Taxes may be updated after providing shipping address">Incl. Taxes:</abbr></td>
<td class="text-right"><t t-esc="website_sale_order and website_sale_order.amount_tax or 0"/> €</td>
</tr>
</thead>
</table>
<a t-if="website_sale_order and website_sale_order.order_line" t-href="/shop/checkout/" class="btn btn-success">Proceed To Payment</a>
<div class="clearfix"/>
<a t-href="/shop" class="btn btn-default"><span class="icon-long-arrow-left"/> Continue Shopping</a>
<a t-if="website_sale_order and website_sale_order.order_line" t-href="/shop/checkout/" class="btn btn-primary pull-right mb32">Process Checkout <span class="icon-long-arrow-right"/></a>
<div class="oe_structure"/>
</div>
<div class="col-md-3 col-md-offset-1 text-muted" id="right_column">
<h4>Policies</h4>
<ul class="list-unstyled mb32">
<li><span class="icon-check"/> 30-days money-back guarantee</li>
<li><span class="icon-check"/> Invoice sent by e-Mail</li>
</ul>
<h4>Secure Payment</h4>
<ul class="list-unstyled mb32">
<li><span class="icon-lock"/> Transation 256bit encrypted</li>
<li><span class="icon-check"/> Processed by Ogone</li>
</ul>
</div>
</div>
</div>
<div class="oe_structure"/>
</div>
@@ -474,66 +512,59 @@
<template id="suggested_products_list" inherit_id="website_sale.mycart" inherit_option_id="website_sale.mycart" name="Suggested Products in list view">
<xpath expr="//table[@id='mycart_products']" position="after">
<table t-if="suggested_products" class='table table-hover table-condensed'>
<table t-if="suggested_products" class='table table-striped table-condensed'>
<colgroup>
<col/>
<col width="80"/>
<col width="160"/>
<col/>
<col width="100"/>
<col width="120"/>
</colgroup>
<thead>
<tr>
<th>Suggested products</th>
<th colspan="2">Suggested products</th>
</tr>
</thead>
<tbody>
<t t-foreach="suggested_products" t-as="product">
<tr>
<td>
<a t-href="/shop/product/#{ product.id }/"><span t-field="product.name"/></a><br/>
<small t-field="product.description_sale"/>
</td>
<td>
<span t-field="product.list_price"></span>€
</td>
<td>
<div class="pull-right">
<a t-href="./add_cart/?product_id=#{ product.id }" class="btn btn-sm btn-success">+</a>
</div>
</td>
</tr>
</t>
<tr t-foreach="suggested_products" t-as="product">
<td>
<a t-href="/shop/product/#{ product.product_tmpl_id.id }/">
<img class="img-rounded" t-att-src="product.img('image_small')"/>
</a>
</td>
<td>
<div>
<a t-href="/shop/product/#{ product.product_tmpl_id.id }/">
<strong t-field="product.name"/>
</a>
</div>
<div class="text-muted" t-field="product.description_sale"/>
</td>
<td>
<span t-field="product.lst_price"></span> €
</td>
<td class="text-center">
<a t-href="./add_cart/?product_id=#{ product.id }"><strong>Add to Cart</strong></a>
</td>
</tr>
</tbody>
</table>
</xpath>
</template>
<template id="suggested_products_cell" inherit_option_id="website_sale.mycart" name="Suggested Products in card view">
<xpath expr="//table[@id='mycart_products']" position="after">
<div class="mt16 mb32" t-if="suggested_products">
<h4>Suggested products</h4>
<div class='row mt16'>
<t t-foreach="suggested_products" t-as="product">
<div class='col-md-2 thumbnail'>
<div class='mt16 text-center'>
<a t-href="/shop/product/#{ product.id }/">
<img t-att-src="product.img('image_small')"/>
</a>
<h5>
<a t-href="/shop/product/#{ product.id }/" style="display: block;">
<span t-field="product.name"/>
</a>
</h5>
</div>
</div>
</t>
</div>
</div>
</xpath>
</template>
<template id="reduction_code" inherit_option_id="website_sale.mycart" name="Reduction Code">
<xpath expr="//table[@id='mycart_total']" position="after">
<form t-if="website_sale_order and website_sale_order.order_line" class="well" t-action="/shop/mycart/" method="post">
<input name="promo" class='input' type="text" placeholder="Reduction Code..." t-att-value="website_sale_order.pricelist_id.code or ''"/>
<button class="btn">Apply Code</button>
<xpath expr="//div[@id='right_column']" position="inside">
<h4>Coupon Code</h4>
<p>
Have a coupon code? Fill in this field and apply.
</p>
<form t-if="website_sale_order and website_sale_order.order_line" t-action="/shop/mycart/" method="post" class="mb32">
<div class="input-group">
<input name="promo" class='form-control' type="text" placeholder="code..." t-att-value="website_sale_order.pricelist_id.code or ''"/>
<div class="input-group-btn">
<button class="btn btn-default">Apply</button>
</div>
</div>
</form>
</xpath>
</template>
@@ -545,244 +576,263 @@
<t t-call="website.layout">
<t t-set="head">
<script type="text/javascript" src="/website_sale/static/src/js/website_sale.js"></script>
<link rel='stylesheet' href='/website_sale/static/src/css/website_sale.css'/>
<t t-raw="head or ''"/>
</t>
<t t-set="title">Shop - Checkout</t>
<div id="wrap">
<div class="container oe_website_sale">
<ul class="wizard pull-right">
<li><a href="/shop/mycart" class="text-success">Review Order<span class="chevron"></span></a></li>
<li class="text-primary">Shipping &amp; Billing<span class="chevron"></span></li>
<li class="text-muted">Payment<span class="chevron"></span></li>
<li class="text-muted">Confirmation<span class="chevron"></span></li>
</ul>
<h1>Your Address</h1>
<form t-action="/shop/confirm_order/" method="post">
<div class="row">
<div class="col-md-4">
<table class="table table-condensed">
<thead>
<tr>
<th>Product</th>
<th>Price</th>
<th>Qty.</th>
</tr>
</thead>
<tbody t-if="website_sale_order.order_line">
<t t-foreach="website_sale_order.order_line" t-as="line">
<tr>
<td><t t-esc="line.name"/></td>
<td><t t-esc="line.product_uom_qty"/></td>
<td><t t-esc="line.price_unit"/> €</td>
</tr>
</t>
</tbody>
<tfoot>
<tr><th>Untaxed Amount</th><td></td><td><t t-esc="website_sale_order.amount_untaxed"/> €</td></tr>
<tr><th>Taxes</th><td></td><td><t t-esc="website_sale_order.amount_tax"/> €</td></tr>
<tr><th>Total</th><td></td><td><t t-esc="website_sale_order.amount_total"/> €</td></tr>
</tfoot>
</table>
<div class="col-md-8 oe_mycart">
<h3 class="page-header mt16">Set Billing Information
<small t-if="user_id.id == website.public_user.id"> or
<a t-if="not partner" t-attf-href="/admin#action=redirect&amp;url=#{ request.httprequest.host_url }/shop/checkout/">sign in</a>
</small>
</h3>
<div class="row">
<div t-attf-class="form-group #{error.get('name') and 'has-error' or ''} col-lg-6">
<label for="contact_name">Your Name</label>
<input type="text" name="name" class="form-control" t-att-value="checkout.get('name')"/>
</div>
<div t-attf-class="form-group #{error.get('company') and 'has-error' or ''} col-lg-6">
<label for="company">Your Company</label>
<input type="text" name="company" class="form-control" t-att-value="checkout.get('company')"/>
</div>
<div t-attf-class="form-group #{error.get('email') and 'has-error' or ''} col-lg-6">
<label for="contact_name">Email</label>
<input type="email" name="email" class="form-control" t-att-value="checkout.get('email')"/>
</div>
<div t-attf-class="form-group #{ error.get('phone') and 'has-error' or ''} col-lg-6">
<label for="phone">Telephone</label>
<input type="tel" name="phone" class="form-control" t-att-value="checkout.get('phone')"/>
</div>
<div t-attf-class="form-group #{error.get('street') and 'has-error' or ''} col-lg-6">
<label for="street">Street</label>
<input type="text" name="street" class="form-control" t-att-value="checkout.get('street')"/>
</div>
<div class="clearfix"/>
<div t-attf-class="form-group #{error.get('city') and 'has-error' or ''} col-lg-6">
<label for="city">City</label>
<input type="text" name="city" class="form-control" t-att-value="checkout.get('city')"/>
</div>
<div t-attf-class="form-group #{error.get('zip') and 'has-error' or ''} col-lg-6">
<label for="zip">Zip / Postal Code</label>
<input type="text" name="zip" class="form-control" t-att-value="checkout.get('zip')"/>
</div>
<div t-attf-class="form-group #{error.get('state_id') and 'has-error' or ''} col-lg-6">
<label for="state_id">State / Province</label>
<select name="state_id" class="form-control">
<option value="">select...</option>
<t t-foreach="states or []" t-as="state">
<option t-att-value="state.id" t-att-selected="state.id == checkout.get('state_id')"><t t-esc="state.name"/></option>
</t>
</select>
</div>
<div t-attf-class="form-group #{error.get('country_id') and 'has-error' or ''} col-lg-6">
<label for="contact_name">Country</label>
<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>
</t>
</select>
</div>
<div class="clearfix"/>
<div class="form-group col-lg-6">
<label>
<input t-if="not shipping" type="checkbox" name="shipping_different"/>
<input t-if="shipping" type="checkbox" name="shipping_different" checked="1"/>
Ship to a different address
</label>
</div>
</div>
<div class="js_shipping row mb16" t-att-style="not shipping and 'display:none' or ''">
<h3 class="oe_shipping col-lg-12 mt16">Shipping Information</h3>
<div t-attf-class="form-group #{error.get('shipping_name') and 'has-error' or ''} col-lg-6">
<label for="contact_name">Name (Shipping)</label>
<input type="text" name="shipping_name" class="form-control" t-att-value="checkout.get('shipping_name', '')"/>
</div>
<div t-attf-class="form-group #{error.get('shipping_phone') and 'has-error' or ''} col-lg-6">
<label for="contact_name">Telephone</label>
<input type="tel" name="shipping_phone" class="form-control" t-att-value="checkout.get('shipping_phone', '')"/>
</div>
<div t-attf-class="form-group #{error.get('shipping_street') and 'has-error' or ''} col-lg-6">
<label for="contact_name">Street</label>
<input type="text" name="shipping_street" class="form-control" t-att-value="checkout.get('shipping_street', '')"/>
</div>
<div class="clearfix"/>
<div t-attf-class="form-group #{error.get('shipping_city') and 'has-error' or ''} col-lg-6">
<label for="contact_name">City</label>
<input type="text" name="shipping_city" class="form-control" t-att-value="checkout.get('shipping_city', '')"/>
</div>
<div t-attf-class="form-group #{error.get('shipping_zip') and 'has-error' or ''} col-lg-6">
<label for="contact_name">Zip / Postal Code</label>
<input type="text" name="shipping_zip" class="form-control" t-att-value="checkout.get('shipping_zip', '')"/>
</div>
<div t-attf-class="form-group #{error.get('shipping_state_id') and 'has-error' or ''} col-lg-6">
<label for="contact_name">State / Province</label>
<select name="shipping_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('shipping_state_id')"><t t-esc="state.name"/></option>
</t>
</select>
</div>
<div t-attf-class="form-group #{error.get('shipping_country_id') and 'has-error' or ''} col-lg-6">
<label for="contact_name">Country</label>
<select name="shipping_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('shipping_country_id')"><t t-esc="country.name"/></option>
</t>
</select>
</div>
</div>
<button type="submit" class="btn btn-default btn-primary pull-right mb32">Confirm <span class="icon-long-arrow-right"/></button>
</div>
<div class="col-lg-offset-1 col-lg-3 text-muted">
<h3 class="page-header mt16">Your Order <small><a href="/shop/mycart"><span class="icon-arrow-right"/> change</a></small></h3>
<div class="row">
<div class="col-sm-6 text-right">Subtotal:</div>
<div class="col-sm-6"><t t-esc="website_sale_order.amount_untaxed or 0"/> €</div>
<div class="col-sm-6 text-right">Taxes:</div>
<div class="col-sm-6"><t t-esc="website_sale_order.amount_tax or 0"/> €</div>
<div class="col-sm-6 text-right"><h4>Total To Pay:</h4></div>
<div class="col-sm-6"><h4><t t-esc="website_sale_order.amount_total or 0"/> €</h4></div>
</div>
<form class="col-md-8 form-horizontal" t-action="/shop/confirm_order/" method="post">
<div class=" row">
<a t-if="not partner" t-attf-href="/admin#action=redirect&amp;url=#{ request.httprequest.host_url }/shop/checkout/" class="btn btn-primary">Log me, I have an account</a>
<h3 class="col-md-10">Billing Information</h3>
<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['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['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['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['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['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['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['city']"/>
</div>
</div>
<div t-attf-class="form-group #{error.get('state_id') and 'has-error' or ''}">
<label class="col-lg-3 control-label" for="contact_name">State / Province</label>
<div class="col-lg-4">
<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['state_id']"><t t-esc="state.name"/></option>
</t>
</select>
</div>
</div>
<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['zip']"/>
</div>
</div>
<div t-attf-class="form-group #{error.get('country_id') and 'has-error' or ''}">
<label class="col-lg-3 control-label" for="contact_name">Country</label>
<div class="col-lg-4">
<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['country_id']"><t t-esc="country.name"/></option>
</t>
</select>
</div>
</div>
<div class="form-group checkbox">
<div class="col-lg-7 col-md-offset-3">
<label>
<input t-if="not shipping" type="checkbox" name="shipping_different"/>
<input t-if="shipping" type="checkbox" name="shipping_different" checked="1"/>
Ship to different address
</label>
</div>
</div>
</div>
<div class="js_shipping row" t-att-style="not shipping and 'display:none' or ''">
<h3 class="col-md-12 oe_shipping">Shipping Information</h3>
<div t-attf-class="form-group #{error.get('shipping_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="shipping_name" class="form-control" t-att-value="checkout.get('shipping_name', '')"/>
</div>
</div>
<div t-attf-class="form-group #{error.get('shipping_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="shipping_phone" class="form-control" t-att-value="checkout.get('shipping_phone', '')"/>
</div>
</div>
<div t-attf-class="form-group #{error.get('shipping_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="shipping_fax" class="form-control" t-att-value="checkout.get('shipping_fax', '')"/>
</div>
</div>
<div t-attf-class="form-group #{error.get('shipping_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="shipping_street" class="form-control" t-att-value="checkout.get('shipping_street', '')"/>
</div>
</div>
<div t-attf-class="form-group #{error.get('shipping_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="shipping_city" class="form-control" t-att-value="checkout.get('shipping_city', '')"/>
</div>
</div>
<div t-attf-class="form-group #{error.get('shipping_state_id') and 'has-error' or ''}">
<label class="col-lg-3 control-label" for="contact_name">State / Province</label>
<div class="col-lg-4">
<select name="shipping_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('shipping_state_id')"><t t-esc="state.name"/></option>
</t>
</select>
</div>
</div>
<div t-attf-class="form-group #{error.get('shipping_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="shipping_zip" class="form-control" t-att-value="checkout.get('shipping_zip', '')"/>
</div>
</div>
<div t-attf-class="form-group #{error.get('shipping_country_id') and 'has-error' or ''}">
<label class="col-lg-3 control-label" for="contact_name">Country</label>
<div class="col-lg-4">
<select name="shipping_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('shipping_country_id')"><t t-esc="country.name"/></option>
</t>
</select>
</div>
</div>
</div>
<button type="submit" class="btn btn-default">Confirm</button>
</form>
<button type="submit" class="btn btn-default btn-primary pull-right mt16" t-if="user_id.id != website.public_user.id">
Confirm <span class="icon-long-arrow-right"/>
</button>
</div>
</div>
</form>
</div>
</div>
</t>
</template>
<template id="payment">
<t t-call="website.layout">
<t t-set="head">
<script type="text/javascript" src="/website_sale/static/src/js/website_sale.js"></script>
<t t-raw="head or ''"/>
</t>
<t t-set="title">Shop - Payment</t>
<div id="wrap">
<div class="container oe_website_sale">
<t t-set="head">
<script type="text/javascript" src="/website_sale/static/src/js/website_sale.js"></script>
<link rel='stylesheet' href='/website_sale/static/src/css/website_sale.css'/>
<t t-raw="head or ''"/>
</t>
<t t-set="title">Select Payment Mode</t>
<div id="wrap">
<div class="container oe_website_sale">
<ul class="wizard pull-right">
<li><a href="/shop/mycart" class="text-success">Review Order<span class="chevron"></span></a></li>
<li><a href="/shop/checkout" class="text-success">Shipping &amp; Billing<span class="chevron"></span></a></li>
<li class="text-primary">Payment<span class="chevron"></span></li>
<li class="text-muted">Confirmation<span class="chevron"></span></li>
</ul>
<h1 class="mb32">Validate Order</h1>
<div class="row">
<div class="col-md-4">
<table class="table table-condensed" t-if="order">
<thead>
<tr>
<th>Product</th>
<th>Price</th>
<th>Qty.</th>
</tr>
</thead>
<tbody t-if="website_sale_order.order_line">
<t t-foreach="website_sale_order.order_line" t-as="line">
<tr>
<td><t t-esc="line.name"/></td>
<td><t t-esc="line.product_uom_qty"/></td>
<td><t t-esc="line.price_unit"/> €</td>
</tr>
</t>
</tbody>
<tfoot>
<tr><th>Untaxed Amount</th><td></td><td><t t-esc="website_sale_order.amount_untaxed"/> €</td></tr>
<tr><th>Taxes</th><td></td><td><t t-esc="website_sale_order.amount_tax"/> €</td></tr>
<tr><th>Total</th><td></td><td><t t-esc="website_sale_order.amount_total"/> €</td></tr>
</tfoot>
</table>
</div>
<div class="col-md-8">
<div class="js_payment row">
<h3 class="col-md-12">Click on your payment method</h3>
<div class="col-md-2">
<t t-foreach="payments or []" t-as="payment">
<label>
<input t-att-value="payment.id" type="radio" name="payment_type"/> <t t-esc="payment.name"/>
</label>
</t>
</div>
<t t-foreach="payments or []" t-as="payment">
<div t-att-data-id="payment.id" t-raw="payment._content" class="hidden col-md-6"/>
</t>
<a t-href="/shop/payment_validate/" class="hidden btn btn-default">I validate my payment</a>
</div>
</div>
<div class="col-md-8 oe_mycart">
<table class='table table-striped table-condensed' id="mycart_products" t-if="website_sale_order and website_sale_order.order_line">
<colgroup>
<col width="80"/>
<col/>
<col width="100"/>
<col width="120"/>
</colgroup>
<thead>
<tr>
<th colspan="2">Product</th>
<th>Price</th>
<th>Quantity</th>
</tr>
</thead>
<tbody>
<tr t-foreach="website_sale_order.order_line" t-as="line">
<td colspan="2" t-if="not line.product_id.product_tmpl_id"></td>
<td t-if="line.product_id.product_tmpl_id">
<a t-href="/shop/product/#{ line.product_id.product_tmpl_id.id }/"><img class="img-rounded" t-att-src="line.product_id.img('image_small')"/></a>
</td>
<td t-if="line.product_id.product_tmpl_id">
<strong t-field="line.product_id.name"/>
</td>
<td class="text-center">
<span t-field="line.price_unit"></span> €
</td>
<td>
<div t-esc="line.product_uom_qty"/>
</td>
</tr>
</tbody>
</table>
<table class='pull-right mb16' id="mycart_total">
<colgroup>
<col width="100"/>
<col width="120"/>
</colgroup>
<thead>
<tr style="border-top: 1px solid #000">
<th><h3>Total:</h3></th>
<th class="text-right"><h3><t t-esc="website_sale_order and website_sale_order.amount_total or 0"/> €</h3></th>
</tr>
<tr class="text-muted">
<td><abbr title="Taxes may be updated after providing shipping address">Incl. Taxes:</abbr></td>
<td class="text-right"><t t-esc="website_sale_order and website_sale_order.amount_tax or 0"/> €</td>
</tr>
</thead>
</table>
<div class="clearfix"/>
<div class="oe_structure"/>
</div>
<div class="col-md-3 col-md-offset-1 text-muted" id="right_column">
<h4>Bill To:</h4>
<div t-field="website_sale_order.partner_invoice_id"/>
<div>
<a href="/shop/checkout"><span class="icon-arrow-right"/> Change Address</a>
</div>
<h4 class="mt32">Ship To:</h4>
<div t-field="website_sale_order.partner_shipping_id"/>
<div>
<a href="/shop/checkout"><span class="icon-arrow-right"/> Change Address</a>
</div>
</div>
</div>
<div class="js_payment mb64">
<p>Select your payment method:</p>
<div>
<t t-foreach="payments or []" t-as="payment">
<label>
<input t-att-value="payment.id" type="radio" name="payment_type"/> <t t-esc="payment.name"/>
</label>
</t>
</div>
<t t-foreach="payments or []" t-as="payment">
<div t-att-data-id="payment.id" t-raw="payment._content" class="hidden"/>
</t>
<a t-href="/shop/payment_validate/" class="btn btn-primary mt16">Validate &amp; Pay <span class="icon-long-arrow-right"/></a>
</div>
</div>
<div class="oe_structure"/>
</div>
</div>
</t>
</template>
</data>
+5 -3
View File
@@ -34,13 +34,15 @@ class sale_order(osv.Model):
class sale_order_line(osv.Model):
_inherit = "sale.order.line"
def _recalculate_product_values(self, cr, uid, ids, product_id=None, context=None):
def _recalculate_product_values(self, cr, uid, ids, product_id=0, 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
product_id = product_id and int(product_id) or \
ids and self.browse(cr, uid, ids[0], context=context).product_id.id
return self.product_id_change(
cr, SUPERUSER_ID, [],
cr, SUPERUSER_ID, ids,
pricelist=context.pop('pricelist'),
product=product_id,
partner_id=user_obj.browse(cr, SUPERUSER_ID, uid).partner_id.id,