[MERGE] Merge lp:~openerp-dev/openobject-addons/trunk-website-al.
bzr revid: bth@tinyerp.com-20131001051453-h242lpkpdlxqmqig
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
import controllers
|
||||
import res_config
|
||||
|
||||
import website
|
||||
import view
|
||||
import models
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import ir_fields
|
||||
import res_config
|
||||
import view
|
||||
import website
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -911,6 +911,7 @@
|
||||
while (node && !$(node).hasClass('oe_editable')) {
|
||||
node = node.parentNode;
|
||||
}
|
||||
$(m.target).trigger('node_changed');
|
||||
return node;
|
||||
})
|
||||
.compact()
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -573,7 +573,6 @@
|
||||
onBlurEdit : function () {},
|
||||
});
|
||||
|
||||
|
||||
website.snippet.editorRegistry = {};
|
||||
website.snippet.Editor = openerp.Class.extend({
|
||||
init: function (parent, dom) {
|
||||
@@ -785,6 +784,8 @@
|
||||
*/
|
||||
onFocus : function () {
|
||||
this.$overlay.addClass('oe_active');
|
||||
if (this.$background_img)
|
||||
this.$background_img.prependTo(this.$target);
|
||||
},
|
||||
|
||||
/* onFocus
|
||||
@@ -792,6 +793,75 @@
|
||||
*/
|
||||
onBlur : function () {
|
||||
this.$overlay.removeClass('oe_active');
|
||||
if (this.$background_img)
|
||||
this.$background_img.detach();
|
||||
},
|
||||
|
||||
/*
|
||||
* active the cke rte editor for change image url
|
||||
*/
|
||||
active_change_image: function ($image) {
|
||||
var self = this;
|
||||
// cke select image with mousedown on image
|
||||
var $image = $($image);
|
||||
var image = $image[0];
|
||||
var event = document.createEvent( 'HTMLEvents' );
|
||||
event.initEvent( 'mousedown', true, true );
|
||||
image.dispatchEvent( event );
|
||||
|
||||
// hack to active editor with doubleclick on editor
|
||||
var dblclick = null;
|
||||
$image.on("dblclick", function (evt) {
|
||||
evt.preventDefault();
|
||||
dblclick = new CKEDITOR.dom.event(evt.originalEvent);
|
||||
return;
|
||||
});
|
||||
var event = document.createEvent( 'HTMLEvents' );
|
||||
event.initEvent( 'dblclick', true, true );
|
||||
image.dispatchEvent( event );
|
||||
},
|
||||
|
||||
change_background: function (bg, ul_options) {
|
||||
var self = this;
|
||||
var $ul = this.$editor.find(ul_options);
|
||||
var bg_value = $(bg).css("background-image").replace(/url\(|\)/g, "");
|
||||
|
||||
// must add an image in the DOM for rte editor
|
||||
this.$background_img = $("<img src='"+bg_value+"'/>").css({position: "absolute", zIndex: -10, left:-1000000, top:-1000000});
|
||||
this.$background_img.prependTo(this.$target);
|
||||
this.$background_img.on("node_changed", function () {
|
||||
$(bg).css("background-image", "url(" + $(this).attr('src') + ")");
|
||||
});
|
||||
|
||||
// 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 {
|
||||
self.active_change_image(self.$background_img);
|
||||
}
|
||||
})
|
||||
.on('mouseover', function (event) {
|
||||
if ($(this).data("value")) {
|
||||
var src = $(this).data("value");
|
||||
self.$background_img.attr('src', src);
|
||||
}
|
||||
})
|
||||
.on('mouseout', function (event) {
|
||||
var src = $ul.find('li.active').data("value");
|
||||
self.$background_img.attr('src', src);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -991,7 +1061,7 @@
|
||||
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.change_size();
|
||||
},
|
||||
@@ -1022,40 +1092,9 @@
|
||||
}
|
||||
},
|
||||
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 +1163,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"]');
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@
|
||||
<li data-value="/website/static/src/img/banner/velour.jpg"><a>Velour</a></li>
|
||||
<li data-value="/website/static/src/img/banner/wood.jpg"><a>Wood</a></li>
|
||||
<li data-value="/website/static/src/img/banner/yellow_green.jpg"><a>Yellow Green</a></li>
|
||||
<li class="oe_custom_bg"><b></b></li>
|
||||
<li class="oe_custom_bg"><a><b>Enter your image</b></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class='oe_snippet_options dropdown-submenu'>
|
||||
@@ -169,8 +169,7 @@
|
||||
<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>
|
||||
@@ -810,7 +809,7 @@
|
||||
<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>
|
||||
<li class="oe_custom_bg"><a><b>Enter your image</b></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import test_views
|
||||
import test_views, test_converter
|
||||
|
||||
checks = [ test_views ]
|
||||
checks = [ test_views, test_converter, ]
|
||||
|
||||
@@ -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
|
||||
""")
|
||||
@@ -361,22 +361,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&id=%s' % (object._name, object.id)">Edit</a>
|
||||
<a href="#" class="js_publish_btn css_unpublish"><small>Unpublish</small></a>
|
||||
<a href="#" class="js_publish_btn css_publish"><small>Publish</small></a>
|
||||
</li>
|
||||
<t t-if="publish_edit">
|
||||
<li class="divider"/>
|
||||
<li>
|
||||
<a t-att-href="'/admin/#model=%s&id=%s' % (object._name, object.id)"><small>Edit</small></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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"/> &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&field=image_small&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&field=image_small&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&field=image_small&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"/> &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">
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -395,6 +395,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),
|
||||
}
|
||||
@@ -415,7 +416,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 +489,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 +508,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'],
|
||||
|
||||
@@ -30,6 +30,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;
|
||||
@@ -128,6 +133,7 @@
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.col-md-12 .oe-height-1 {
|
||||
height: 95px;
|
||||
@@ -155,6 +161,7 @@
|
||||
height: 288px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.col-md-12 .oe-height-1 {
|
||||
height: 125px;
|
||||
@@ -182,6 +189,7 @@
|
||||
height: 380px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- Product list style ---- */
|
||||
.oe_list_products {
|
||||
border: none;
|
||||
@@ -284,3 +292,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 #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;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,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
|
||||
@@ -250,3 +255,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
|
||||
|
||||
|
||||
@@ -379,19 +379,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 & 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 +413,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">
|
||||
<span t-field="line.price_unit"></span> €
|
||||
<div class="text-danger" style="text-decoration: line-through;" t-if="line.product_id.lst_price > line.price_unit">
|
||||
<t t-esc="line.product_id.lst_price" /> €
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon">
|
||||
<a t-href="./add_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="./remove_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 +519,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 +583,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 & 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&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['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['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['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['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['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['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['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['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['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&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 & 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 & Pay <span class="icon-long-arrow-right"/></a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="oe_structure"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</t>
|
||||
</template>
|
||||
</data>
|
||||
|
||||
Reference in New Issue
Block a user