[MERGE] multilang
bzr revid: fme@openerp.com-20130926165324-2jfo9s8q3u4teor1
This commit is contained in:
commit
e7d55014a4
|
@ -35,7 +35,7 @@ PIL_MIME_MAPPING = {'PNG': 'image/png', 'JPEG': 'image/jpeg', 'GIF': 'image/gif'
|
|||
# Completely arbitrary limits
|
||||
MAX_IMAGE_WIDTH, MAX_IMAGE_HEIGHT = IMAGE_LIMITS = (1024, 768)
|
||||
class Website(openerp.addons.web.controllers.main.Home):
|
||||
@website.route('/', type='http', auth="public")
|
||||
@website.route('/', type='http', auth="public", multilang=True)
|
||||
def index(self, **kw):
|
||||
return self.page("website.homepage")
|
||||
|
||||
|
@ -85,7 +85,7 @@ class Website(openerp.addons.web.controllers.main.Home):
|
|||
return werkzeug.wrappers.Response(url, mimetype='text/plain')
|
||||
return werkzeug.utils.redirect(url)
|
||||
|
||||
@website.route('/website/theme_change', type='http', auth="admin") # FIXME: auth
|
||||
@website.route('/website/theme_change', type='http', auth="admin")
|
||||
def theme_change(self, theme_id=False, **kwargs):
|
||||
imd = request.registry['ir.model.data']
|
||||
view = request.registry['ir.ui.view']
|
||||
|
@ -107,7 +107,7 @@ class Website(openerp.addons.web.controllers.main.Home):
|
|||
|
||||
return request.website.render('website.themes', {'theme_changed': True})
|
||||
|
||||
@website.route('/page/<path:path>', type='http', auth="public")
|
||||
@website.route('/page/<path:path>', type='http', auth="public", multilang=True)
|
||||
def page(self, path, **kwargs):
|
||||
values = {
|
||||
'path': path,
|
||||
|
@ -160,6 +160,51 @@ class Website(openerp.addons.web.controllers.main.Home):
|
|||
})
|
||||
return result
|
||||
|
||||
@website.route('/website/get_view_translations', type='json', auth='admin')
|
||||
def get_view_translations(self, xml_id, lang=None):
|
||||
lang = lang or request.context.get('lang')
|
||||
views = self.customize_template_get(xml_id, optional=False)
|
||||
views_ids = [view.get('id') for view in views if view.get('active')]
|
||||
domain = [('type', '=', 'view'), ('res_id', 'in', views_ids), ('lang', '=', lang)]
|
||||
irt = request.registry.get('ir.translation')
|
||||
return irt.search_read(request.cr, request.uid, domain, ['id', 'res_id', 'value'], context=request.context)
|
||||
|
||||
@website.route('/website/set_translations', type='json', auth='admin')
|
||||
def set_translations(self, data, lang):
|
||||
irt = request.registry.get('ir.translation')
|
||||
for view_id, trans in data.items():
|
||||
view_id = int(view_id)
|
||||
for t in trans:
|
||||
initial_content = t['initial_content'].strip()
|
||||
new_content = t['new_content'].strip()
|
||||
tid = t['translation_id']
|
||||
if not tid:
|
||||
old_trans = irt.search_read(
|
||||
request.cr, request.uid,
|
||||
[
|
||||
('type', '=', 'view'),
|
||||
('res_id', '=', view_id),
|
||||
('lang', '=', lang),
|
||||
('src', '=', initial_content),
|
||||
])
|
||||
if old_trans:
|
||||
tid = old_trans[0]['id']
|
||||
if tid:
|
||||
vals = {'value': new_content}
|
||||
irt.write(request.cr, request.uid, [tid], vals)
|
||||
else:
|
||||
new_trans = {
|
||||
'name': 'website',
|
||||
'res_id': view_id,
|
||||
'lang': lang,
|
||||
'type': 'view',
|
||||
'source': initial_content,
|
||||
'value': new_content,
|
||||
}
|
||||
irt.create(request.cr, request.uid, new_trans)
|
||||
irt._get_source.clear_cache(irt) # FIXME: find why ir.translation does not invalidate
|
||||
return True
|
||||
|
||||
# # FIXME: auth, anybody can upload an attachment if URL known/found
|
||||
@website.route('/website/attach', type='http', auth='admin')
|
||||
def attach(self, func, upload):
|
||||
|
|
|
@ -107,6 +107,31 @@ table.editorbar-panel td.selected {
|
|||
background-color: #b1c9d9;
|
||||
}
|
||||
|
||||
.oe_translate_examples li {
|
||||
margin: 10px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.oe_translatable_text {
|
||||
outline: 1px solid black;
|
||||
}
|
||||
|
||||
.oe_translatable_field {
|
||||
outline: 1px dashed black;
|
||||
}
|
||||
|
||||
.oe_translatable_text.oe_dirty, .oe_translatable_field.oe_dirty {
|
||||
outline-color: red;
|
||||
}
|
||||
|
||||
.oe_translatable_text.oe_dirty:empty {
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.oe_translatable_todo {
|
||||
background: #ffffb6;
|
||||
}
|
||||
|
||||
/* ---- RTE ---- */
|
||||
.oe_editable .btn {
|
||||
-webkit-user-select: auto;
|
||||
|
|
|
@ -93,6 +93,22 @@ table.editorbar-panel
|
|||
td.selected
|
||||
background-color: #b1c9d9
|
||||
|
||||
// ---- TRANSLATIONS ---- {{{
|
||||
.oe_translate_examples li
|
||||
margin: 10px
|
||||
padding: 4px
|
||||
.oe_translatable_text
|
||||
outline: 1px solid black
|
||||
.oe_translatable_field
|
||||
outline: 1px dashed black
|
||||
.oe_translatable_text.oe_dirty, .oe_translatable_field.oe_dirty
|
||||
outline-color: red
|
||||
.oe_translatable_text.oe_dirty:empty
|
||||
padding: 0 10px
|
||||
.oe_translatable_todo
|
||||
background: rgb(255, 255, 182)
|
||||
// }}}
|
||||
|
||||
/* ---- RTE ---- */
|
||||
|
||||
// bootstrap makes .btn elements unselectable -> RTE double-click can't know
|
||||
|
@ -485,3 +501,5 @@ $navbar_height: 51px
|
|||
&.oe_ace_closed
|
||||
width: 0
|
||||
opacity: 0
|
||||
|
||||
// vim:tabstop=4:shiftwidth=4:softtabstop=4:fdm=marker:
|
||||
|
|
|
@ -282,7 +282,7 @@
|
|||
});
|
||||
}).get();
|
||||
return $.when.apply(null, defs).then(function () {
|
||||
window.location.href = window.location.href.replace(/unable_editor(=[^&]*)?|#.*/g, '');
|
||||
website.reload();
|
||||
});
|
||||
},
|
||||
/**
|
||||
|
|
|
@ -37,7 +37,9 @@
|
|||
});
|
||||
return $.when.apply(null, dones);
|
||||
};
|
||||
|
||||
website.reload = function () {
|
||||
window.location.href = window.location.href.replace(/unable_editor(=[^&]*)?|#.*/g, '');
|
||||
};
|
||||
|
||||
var all_ready = null;
|
||||
var dom_ready = website.dom_ready = $.Deferred();
|
||||
|
@ -78,7 +80,7 @@
|
|||
$pagination.last().before(col);
|
||||
});
|
||||
|
||||
var page_start = page - parseInt(Math.floor((scope-1)/2));
|
||||
var page_start = page - parseInt(Math.floor((scope-1)/2), 10);
|
||||
if (page_start < 1 ) page_start = 1;
|
||||
var page_end = page_start + (scope-1);
|
||||
if (page_end > page_count ) page_end = page_count;
|
||||
|
@ -106,10 +108,10 @@
|
|||
*/
|
||||
website.ready = function() {
|
||||
if (!all_ready) {
|
||||
all_ready = dom_ready.then(function () {
|
||||
// TODO: load translations
|
||||
return website.load_templates(templates);
|
||||
});
|
||||
var tpl = website.load_templates(templates);
|
||||
// var session;
|
||||
// var trads = openerp._t.database.load_translations(session, ['website'], website.get_context().lang);
|
||||
all_ready = $.when(dom_ready, tpl);
|
||||
}
|
||||
return all_ready;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,192 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
var website = openerp.website;
|
||||
website.templates.push('/website/static/src/xml/website.translator.xml');
|
||||
var nodialog = 'website_translator_nodialog';
|
||||
|
||||
website.EditorBar.include({
|
||||
start: function () {
|
||||
var self = this;
|
||||
this.initial_content = {};
|
||||
return this._super.apply(this, arguments).then(function () {
|
||||
self.$('button[data-action=edit]').text("Translate");
|
||||
self.$('[data-action=snippet]').hide();
|
||||
self.$('#customize-menu-button').hide();
|
||||
});
|
||||
},
|
||||
edit: function () {
|
||||
var self = this;
|
||||
var mysuper = this._super;
|
||||
if (!localStorage[nodialog]) {
|
||||
var dialog = new website.TranslatorDialog();
|
||||
dialog.appendTo($(document.body));
|
||||
dialog.on('activate', this, function () {
|
||||
localStorage[nodialog] = dialog.$('input[name=do_not_show]').prop('checked') || '';
|
||||
dialog.$el.modal('hide');
|
||||
this.translate();
|
||||
});
|
||||
} else {
|
||||
this.translate().then(function () {
|
||||
// Disable non translatable t-fields
|
||||
$('[data-oe-type][data-oe-translate=0]').removeAttr('data-oe-type');
|
||||
mysuper.call(self);
|
||||
});
|
||||
}
|
||||
},
|
||||
translate: function () {
|
||||
var self = this;
|
||||
this.translations = null;
|
||||
return openerp.jsonRpc('/website/get_view_translations', 'call', {
|
||||
'xml_id': $(document.documentElement).data('view-xmlid'),
|
||||
'lang': website.get_context().lang,
|
||||
}).then(function (translations) {
|
||||
self.translations = translations;
|
||||
self.processTranslatableNodes();
|
||||
});
|
||||
},
|
||||
processTranslatableNodes: function () {
|
||||
var self = this;
|
||||
var $editables = $('[data-oe-model="ir.ui.view"]')
|
||||
.not('link, script')
|
||||
.not('.oe_snippets,.oe_snippet, .oe_snippet *')
|
||||
.not('[data-oe-type]');
|
||||
|
||||
$editables.each(function () {
|
||||
var $node = $(this);
|
||||
var view_id = $node.attr('data-oe-source-id') || $node.attr('data-oe-id');
|
||||
self.transNode(this, view_id|0);
|
||||
});
|
||||
$('.oe_translatable_text').on('paste', function () {
|
||||
var node = $(this);
|
||||
setTimeout(function () {
|
||||
self.sanitizeNode(node);
|
||||
}, 0);
|
||||
});
|
||||
$(document).on('blur keyup paste', '.oe_translatable_text[contenteditable]', function(ev) {
|
||||
var $node = $(this);
|
||||
setTimeout(function () {
|
||||
// Doing stuff next tick because paste and keyup events are
|
||||
// fired before the content is changed
|
||||
if (ev.type == 'paste') {
|
||||
self.sanitizeNode($node[0]);
|
||||
}
|
||||
if (self.getInitialContent($node[0]) !== $node.text()) {
|
||||
$node.addClass('oe_dirty').removeClass('oe_translatable_todo');
|
||||
}
|
||||
}, 0);
|
||||
});
|
||||
},
|
||||
getInitialContent: function (node) {
|
||||
return this.initial_content[node.attributes['data-oe-nodeid'].value];
|
||||
},
|
||||
sanitizeNode: function (node) {
|
||||
node.text(node.text());
|
||||
},
|
||||
isTextNode: function (node) {
|
||||
return node.nodeType === 3 || node.nodeType === 4;
|
||||
},
|
||||
isTranslatable: function (text) {
|
||||
return text && _.str.trim(text) !== '';
|
||||
},
|
||||
markTranslatableNode: function (node, view_id) {
|
||||
// TODO: link nodes with same content
|
||||
node.className += ' oe_translatable_text';
|
||||
node.setAttribute('data-oe-translation-view-id', view_id);
|
||||
var content = node.childNodes[0].data.trim();
|
||||
var trans = this.translations.filter(function (t) {
|
||||
return t.res_id === view_id && t.value === content;
|
||||
});
|
||||
if (trans.length) {
|
||||
node.setAttribute('data-oe-translation-id', trans[0].id);
|
||||
} else {
|
||||
node.className += ' oe_translatable_todo';
|
||||
}
|
||||
node.contentEditable = true;
|
||||
var nid = _.uniqueId();
|
||||
$(node).attr('data-oe-nodeid', nid);
|
||||
this.initial_content[nid] = content;
|
||||
},
|
||||
save: function () {
|
||||
var self = this;
|
||||
var mysuper = this._super;
|
||||
var trans = {};
|
||||
// this._super.apply(this, arguments);
|
||||
$('.oe_translatable_text.oe_dirty').each(function () {
|
||||
var $node = $(this);
|
||||
var data = $node.data();
|
||||
if (!trans[data.oeTranslationViewId]) {
|
||||
trans[data.oeTranslationViewId] = [];
|
||||
}
|
||||
trans[data.oeTranslationViewId].push({
|
||||
initial_content: self.getInitialContent(this),
|
||||
new_content: $node.text(),
|
||||
translation_id: data.oeTranslationId || null
|
||||
});
|
||||
});
|
||||
openerp.jsonRpc('/website/set_translations', 'call', {
|
||||
'data': trans,
|
||||
'lang': website.get_context()['lang'],
|
||||
}).then(function () {
|
||||
mysuper.call(self);
|
||||
}).fail(function () {
|
||||
// TODO: bootstrap alert with error message
|
||||
alert("Could not save translation");
|
||||
});
|
||||
},
|
||||
transNode: function (node, view_id) {
|
||||
// Mostly handling text and cdata nodes here
|
||||
// so avoid jquery usage in this function
|
||||
if (node.attributes['data-oe-type']) {
|
||||
if (node.attributes['data-oe-translate'].value == '1') {
|
||||
node.className += ' oe_translatable_field';
|
||||
}
|
||||
return;
|
||||
} else if (node.childNodes.length === 1
|
||||
&& this.isTextNode(node.childNodes[0])
|
||||
&& !node.getAttribute('data-oe-model')) {
|
||||
this.markTranslatableNode(node, view_id);
|
||||
} else {
|
||||
for (var i = 0, l = node.childNodes.length; i < l; i ++) {
|
||||
var n = node.childNodes[i];
|
||||
if (this.isTextNode(n)) {
|
||||
if (this.isTranslatable(n.data)) {
|
||||
var container = document.createElement('span');
|
||||
node.insertBefore(container, n);
|
||||
container.appendChild(n);
|
||||
this.markTranslatableNode(container, view_id);
|
||||
}
|
||||
} else {
|
||||
this.transNode(n, view_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
website.RTE.include({
|
||||
start: function () {
|
||||
this._super.apply(this, arguments);
|
||||
this.$el.hide();
|
||||
},
|
||||
fetch_editables: function (root) {
|
||||
$(root).click(function (ev) {
|
||||
ev.preventDefault();
|
||||
});
|
||||
return $('[data-oe-translate=1]');
|
||||
}
|
||||
});
|
||||
|
||||
website.TranslatorDialog = openerp.Widget.extend({
|
||||
events: _.extend({}, website.EditorBar.prototype.events, {
|
||||
'hidden.bs.modal': 'destroy',
|
||||
'click button[data-action=activate]': function (ev) {
|
||||
this.trigger('activate');
|
||||
},
|
||||
}),
|
||||
template: 'website.TranslatorDialog',
|
||||
start: function () {
|
||||
this.$el.modal();
|
||||
},
|
||||
});
|
||||
})();
|
|
@ -0,0 +1,53 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<templates id="template" xml:space="preserve">
|
||||
<t t-name="website.TranslatorDialog">
|
||||
<div class="modal fade oe_website_translator" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button title="Close" type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h2 class="modal-title">Translate this page</h2>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<section>
|
||||
<p>
|
||||
You are about to enter the translation mode.
|
||||
</p>
|
||||
<p>
|
||||
In this mode you can not change the structure of the document, you can only translate text.
|
||||
</p>
|
||||
<p>
|
||||
Here are the visuals used in order to help you in your translation flow:
|
||||
<ul class="oe_translate_examples">
|
||||
<li class="oe_translatable_text">
|
||||
Normal translatable content
|
||||
</li>
|
||||
<li class="oe_translatable_field">
|
||||
ERP translatable object data
|
||||
</li>
|
||||
<li class="oe_translatable_todo">
|
||||
Translation TODO
|
||||
</li>
|
||||
</ul>
|
||||
</p>
|
||||
</section>
|
||||
<hr/>
|
||||
<section class="row">
|
||||
<div class="col-md-6">
|
||||
<button type="button" data-action="activate" class="btn btn-primary">Ok</button>
|
||||
or
|
||||
<a data-action="discard" data-dismiss="modal" href="#">Cancel</a>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label>
|
||||
<input type="checkbox" name="do_not_show"/>
|
||||
Do not show this dialog later.
|
||||
</label>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
|
@ -22,7 +22,6 @@
|
|||
<li><a data-action="show-mobile-preview" href="#"><span title="Mobile preview" class="icon-mobile-phone"/></a></li>
|
||||
<li class="divider-vertical"></li>
|
||||
<li><a data-action="promote-current-page" href="#"><span title="Promote page on the web">Promote</span></a></li>
|
||||
<li><a href="#">Translate</a></li>
|
||||
<li class="dropdown">
|
||||
<a id="customize-menu-button" class="dropdown-toggle" data-toggle="dropdown" href="#">Customize <span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" role="menu" id="customize-menu">
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
<!DOCTYPE html>
|
||||
<html t-att-lang="lang.replace('_', '-')"
|
||||
t-att-data-editable="'1' if editable else '0'"
|
||||
t-att-data-translatable="'1' if translatable else '0'"
|
||||
t-att-data-view-xmlid="str(__stack__[0])">
|
||||
<head>
|
||||
<title><t t-esc="title or res_company.name"/></title>
|
||||
|
@ -30,6 +31,7 @@
|
|||
</t>
|
||||
<t t-call="website.theme"/>
|
||||
|
||||
<script type="text/javascript" src="/web/static/lib/es5-shim/es5-shim.min.js"></script>
|
||||
<script type="text/javascript" src="/web/static/lib/underscore/underscore.js"></script>
|
||||
<script type="text/javascript" src="/web/static/lib/underscore.string/lib/underscore.string.js"></script>
|
||||
<script type="text/javascript" src="/web/static/lib/jquery/jquery.js"></script>
|
||||
|
@ -43,7 +45,7 @@
|
|||
<t t-if="editable">
|
||||
<script type="text/javascript" src="/website/static/lib/ckeditor/ckeditor.js"></script>
|
||||
<script type="text/javascript" src="/website/static/lib/ckeditor.sharedspace/plugin.js"></script>
|
||||
<script type="text/javascript" src="/website/static/lib/ace/ace.js"></script>
|
||||
<script t-if="not translatable" type="text/javascript" src="/website/static/lib/ace/ace.js"></script>
|
||||
<script type="text/javascript" src="/website/static/lib/vkbeautify/vkbeautify.0.99.00.beta.js"></script>
|
||||
<script type="text/javascript" src="/web/static/lib/jquery.ui/js/jquery-ui-1.9.1.custom.js"></script>
|
||||
<!-- mutation observers shim backed by mutation events (8 < IE < 11, Safari < 6, FF < 14, Chrome < 17) -->
|
||||
|
@ -53,8 +55,9 @@
|
|||
<script type="text/javascript" src="/website/static/src/js/website.editor.js"></script>
|
||||
<script type="text/javascript" src="/website/static/src/js/website.mobile.js"></script>
|
||||
<script type="text/javascript" src="/website/static/src/js/website.seo.js"></script>
|
||||
<script type="text/javascript" src="/website/static/src/js/website.snippets.js"></script>
|
||||
<script type="text/javascript" src="/website/static/src/js/website.ace.js"></script>
|
||||
<script t-if="not translatable" type="text/javascript" src="/website/static/src/js/website.snippets.js"></script>
|
||||
<script t-if="not translatable" type="text/javascript" src="/website/static/src/js/website.ace.js"></script>
|
||||
<script t-if="translatable" type="text/javascript" src="/website/static/src/js/website.translator.js"></script>
|
||||
</t>
|
||||
|
||||
<t t-raw="head or ''"/>
|
||||
|
@ -71,14 +74,14 @@
|
|||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="/page/website.homepage"><em>Your</em><b>Company</b></a>
|
||||
<a class="navbar-brand" t-href="/page/website.homepage"><em>Your</em><b>Company</b></a>
|
||||
</div>
|
||||
<div class="collapse navbar-collapse navbar-top-collapse">
|
||||
<ul class="nav navbar-nav navbar-right" id="top_menu">
|
||||
<li name="contactus"><a href="/page/website.contactus">Contact us</a></li>
|
||||
<li name="contactus"><a t-href="/page/website.contactus">Contact us</a></li>
|
||||
<li t-if="user_id.id == website.public_user.id"><a href="/admin">Sign in</a></li>
|
||||
<li t-if="user_id.id != website.public_user.id"><a href="/admin"><span t-field="user_id.name"/></a></li>
|
||||
<li t-if="len(website.language_ids) > 1" class="dropdown">
|
||||
<li t-if="request.multilang and len(website.language_ids) > 1" class="dropdown">
|
||||
<!-- TODO: use flags for language selection -->
|
||||
<t t-set="lang_selected" t-value="[lg for lg in website.language_ids if lg.code == lang]"/>
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
|
@ -86,7 +89,7 @@
|
|||
</a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li t-foreach="website.language_ids" t-as="lg">
|
||||
<a href="#" role="menuitem">
|
||||
<a t-att-href="url_for('', lang=lg.code)" role="menuitem">
|
||||
<strong t-att-class="'icon-check' if lg.code == lang
|
||||
else 'icon-check-empty'"></strong>
|
||||
<t t-esc="lg.name"/>
|
||||
|
@ -106,13 +109,13 @@
|
|||
<div class="col-md-3" name="product">
|
||||
<h4>Our products & Services</h4>
|
||||
<ul class="list-unstyled" name="products">
|
||||
<li><a href="/">Home</a></li>
|
||||
<li><a t-href="/">Home</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-3" name="info">
|
||||
<h4 name="info_title">Connect with us</h4>
|
||||
<ul class="list-unstyled">
|
||||
<li><a href="/page/website.contactus">Contact us</a></li>
|
||||
<li><a t-href="/page/website.contactus">Contact us</a></li>
|
||||
</ul>
|
||||
<ul class="list-unstyled">
|
||||
<li><i class="icon-phone"></i> <span t-field="res_company.phone"></span></li>
|
||||
|
@ -127,7 +130,7 @@
|
|||
<div class="col-md-5 col-lg-offset-1" name="about_us">
|
||||
<h4>
|
||||
<span t-field="res_company.name">Your Company</span>
|
||||
<small> - <a href="/page/website.aboutus">About us</a></small>
|
||||
<small> - <a t-href="/page/website.aboutus">About us</a></small>
|
||||
</h4>
|
||||
<p>
|
||||
We are a team of passionated people whose goal is to improve everyone's
|
||||
|
@ -147,7 +150,7 @@
|
|||
<a class="label label-danger" href="https://openerp.com/apps/website">OpenERP</a>
|
||||
</div>
|
||||
<div class="pull-left text-muted">
|
||||
Copyright &copy; <span t-field="res_company.name">Company name</span> - <a href="/sitemap">Sitemap</a>
|
||||
Copyright &copy; <span t-field="res_company.name">Company name</span> - <a t-href="/sitemap">Sitemap</a>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
@ -164,7 +167,7 @@
|
|||
<div class="col-md-4">
|
||||
<h4 class="mt16">Subtitle</h4>
|
||||
<p>
|
||||
<a href="/">Homepage</a>
|
||||
<a t-href="/">Homepage</a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
|
@ -208,7 +211,7 @@
|
|||
<div class="well mt32">
|
||||
<p>This page does not exists, but you can create it as you are administrator of this site.</p>
|
||||
<a class="btn btn-primary" t-att-href="'/pagenew/'+path">Create Page</a>
|
||||
<span class="text-muted">or</span> <a href="/sitemap">Search a Page</a>
|
||||
<span class="text-muted">or</span> <a t-href="/sitemap">Search a Page</a>
|
||||
</div>
|
||||
<div class="text-center text-muted">Edit the content bellow this line to adapt the default "page not found" page.</div>
|
||||
</div>
|
||||
|
@ -223,8 +226,8 @@
|
|||
</p>
|
||||
<p>Maybe you were looking for one of these popular pages ?</p>
|
||||
<ul>
|
||||
<li><a href="/">Homepage</a></li>
|
||||
<li><a href="/">Contact Us</a></li>
|
||||
<li><a t-href="/">Homepage</a></li>
|
||||
<li><a t-href="/page/website.contactus/">Contact Us</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -257,8 +260,8 @@
|
|||
</p>
|
||||
<pre t-if="editable" t-esc="error"/>
|
||||
<ul>
|
||||
<li><a href="/">Homepage</a></li>
|
||||
<li><a href="/">Contact Us</a></li>
|
||||
<li><a t-href="/">Homepage</a></li>
|
||||
<li><a t-href="/page/website.contactus/">Contact Us</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -281,7 +284,7 @@
|
|||
<p>We'll do our best to get back to you as soon as possible.</p>
|
||||
</div>
|
||||
<div class="text-center mt64" name="mail_button">
|
||||
<a t-att-href="'mailto:'+res_company.email" class="btn btn-primary">Send us an email</a>
|
||||
<a t-attf-href="mailto:{{ res_company.email }}" class="btn btn-primary">Send us an email</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
|
|
|
@ -7,22 +7,35 @@ from openerp.osv import osv, fields
|
|||
from openerp.addons.web import http
|
||||
from openerp.addons.web.http import request
|
||||
import urllib
|
||||
from urlparse import urljoin
|
||||
import math
|
||||
import traceback
|
||||
from openerp.tools.safe_eval import safe_eval
|
||||
from openerp.exceptions import AccessError, AccessDenied
|
||||
import werkzeug
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def route(*route_args, **route_kwargs):
|
||||
def route(routes, *route_args, **route_kwargs):
|
||||
def decorator(f):
|
||||
@http.route(*route_args, **route_kwargs)
|
||||
new_routes = routes if isinstance(routes, list) else [routes]
|
||||
f.multilang = route_kwargs.get('multilang', False)
|
||||
if f.multilang:
|
||||
route_kwargs.pop('multilang')
|
||||
for r in list(new_routes):
|
||||
new_routes.append('/<string(length=5):lang_code>' + r)
|
||||
@http.route(new_routes, *route_args, **route_kwargs)
|
||||
@functools.wraps(f, assigned=functools.WRAPPER_ASSIGNMENTS + ('func_name',))
|
||||
def wrap(*args, **kwargs):
|
||||
request.route_lang = None # WIP: decorator will support lang argument
|
||||
request.route_lang = kwargs.get('lang_code', None)
|
||||
if not hasattr(request, 'website'):
|
||||
request.multilang = f.multilang
|
||||
request.website = request.registry['website'].get_current()
|
||||
if request.route_lang:
|
||||
lang_ok = [lg.code for lg in request.website.language_ids if lg.code == request.route_lang]
|
||||
if not lang_ok:
|
||||
return request.not_found()
|
||||
request.website.preprocess_request(*args, **kwargs)
|
||||
return f(*args, **kwargs)
|
||||
return wrap
|
||||
|
@ -36,6 +49,19 @@ def auth_method_public():
|
|||
request.uid = request.session.uid
|
||||
http.auth_methods['public'] = auth_method_public
|
||||
|
||||
def url_for(path, lang=None):
|
||||
if request:
|
||||
path = urljoin(request.httprequest.path, path)
|
||||
langs = request.context.get('langs')
|
||||
if path[0] == '/' and len(langs) > 1:
|
||||
ps = path.split('/')
|
||||
lang = lang or request.context.get('lang')
|
||||
if ps[1] in langs:
|
||||
ps[1] = lang
|
||||
else:
|
||||
ps.insert(1, lang)
|
||||
path = '/'.join(ps)
|
||||
return path
|
||||
|
||||
def urlplus(url, params):
|
||||
if not params:
|
||||
|
@ -77,12 +103,22 @@ class website(osv.osv):
|
|||
return lang
|
||||
|
||||
def preprocess_request(self, cr, uid, ids, *args, **kwargs):
|
||||
def redirect(url):
|
||||
return werkzeug.utils.redirect(url_for(url))
|
||||
request.redirect = redirect
|
||||
|
||||
is_public_user = request.uid == self.get_public_user().id
|
||||
lang = self.get_lang()
|
||||
is_master_lang = lang == request.website.default_lang_id.code
|
||||
request.context.update({
|
||||
'lang': lang,
|
||||
'langs': [lg.code for lg in request.website.language_ids],
|
||||
'multilang': request.multilang,
|
||||
'is_public_user': is_public_user,
|
||||
'editable': not is_public_user, # TODO: check perms
|
||||
'is_master_lang': is_master_lang,
|
||||
'editable': not is_public_user,
|
||||
'translatable': not is_public_user and not is_master_lang and request.multilang,
|
||||
})
|
||||
request.context['lang'] = self.get_lang()
|
||||
|
||||
def get_current(self):
|
||||
# WIP, currently hard coded
|
||||
|
@ -103,13 +139,15 @@ class website(osv.osv):
|
|||
registry=request.registry,
|
||||
json=simplejson,
|
||||
website=request.website,
|
||||
url_for=url_for,
|
||||
res_company=request.website.company_id,
|
||||
user_id=user.browse(cr, openerp.SUPERUSER_ID, uid),
|
||||
)
|
||||
|
||||
context = {
|
||||
'inherit_branding': qweb_context.setdefault('editable', False),
|
||||
}
|
||||
context = request.context.copy()
|
||||
context.update(
|
||||
inherit_branding=qweb_context.setdefault('editable', False),
|
||||
)
|
||||
|
||||
# check if xmlid of the template exists
|
||||
try:
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
</div>
|
||||
<group col="4">
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
<field name="default_lang_id"/>
|
||||
<field name="default_lang_id" widget="selection"/>
|
||||
</group>
|
||||
<group string="Website languages">
|
||||
<field name="language_ids" nolabel="1" mode="tree,form">
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
<div class='navbar'>
|
||||
<div>
|
||||
<t t-call="website.pager">
|
||||
<t t-set="classname">pull-left</t>
|
||||
<t t-set="classname" t-value="'pull-left'"/>
|
||||
</t>
|
||||
<form action="/references/" method="get" class="navbar-search pull-right pagination form-inline">
|
||||
<div class="form-group">
|
||||
|
|
|
@ -8,7 +8,7 @@ from urllib import quote_plus
|
|||
|
||||
class contactus(http.Controller):
|
||||
|
||||
@website.route(['/crm/contactus'], type='http', auth="admin")
|
||||
@website.route(['/crm/contactus'], type='http', auth="admin", multilang=True)
|
||||
def contactus(self, *arg, **post):
|
||||
post['user_id'] = False
|
||||
request.registry['crm.lead'].create(request.cr, request.uid,
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
<template id="contactus_form" name="Contact Form" inherit_id="website.contactus" inherit_option_id="website.contactus">
|
||||
<xpath expr="//div[@name='mail_button']" position="replace">
|
||||
<form action="/crm/contactus" method="post" class="form-horizontal mt32" >
|
||||
<form t-action="/crm/contactus" method="post" class="form-horizontal mt32" >
|
||||
<div class="form-group">
|
||||
<label class="col-md-3 col-sm-4 control-label" for="contact_name">Your Name</label>
|
||||
<div class="col-md-7 col-sm-8">
|
||||
|
|
|
@ -9,7 +9,7 @@ import urllib
|
|||
|
||||
class website_crm_partner_assign(http.Controller):
|
||||
|
||||
@website.route(['/partners/', '/partners/page/<int:page>/'], type='http', auth="public")
|
||||
@website.route(['/partners/', '/partners/page/<int:page>/'], type='http', auth="public", multilang=True)
|
||||
def partners(self, page=0, **post):
|
||||
partner_obj = request.registry['res.partner']
|
||||
|
||||
|
@ -84,7 +84,7 @@ class website_crm_partner_assign(http.Controller):
|
|||
}
|
||||
return request.website.render("website_crm_partner_assign.index", values)
|
||||
|
||||
@website.route(['/partners/<int:ref_id>/'], type='http', auth="public")
|
||||
@website.route(['/partners/<int:ref_id>/'], type='http', auth="public", multilang=True)
|
||||
def partners_ref(self, ref_id=0, **post):
|
||||
partner_obj = request.registry['res.partner']
|
||||
partner_ids = partner_obj.search(
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
<template id="footer_custom" inherit_id="website.layout" name="Custom Footer">
|
||||
<xpath expr="//footer//div[@name='info']/ul" position="inside">
|
||||
<li><a href="/partners/">Partners</a></li>
|
||||
<li><a t-href="/partners/">Partners</a></li>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
|
@ -40,7 +40,7 @@
|
|||
<t t-call="website.pager">
|
||||
<t t-set="classname">pull-left</t>
|
||||
</t>
|
||||
<form action="/partners/" method="get" class="navbar-search pull-right pagination form-inline">
|
||||
<form t-action="/partners/" method="get" class="navbar-search pull-right pagination form-inline">
|
||||
<div class="form-group">
|
||||
<input type="text" name="search" class="search-query col-md-2 mt4 form-control" placeholder="Search" t-att-value="searches.get('search') or '' or ''"/>
|
||||
</div>
|
||||
|
@ -77,11 +77,11 @@
|
|||
</t>
|
||||
<div class="media thumbnail" data-publish="">
|
||||
<t t-call="website.publish_management"><t t-set="object" t-value="partner"/></t>
|
||||
<a class="pull-left" t-attf-href="/partners/#{ partner.id }/">
|
||||
<a class="pull-left" t-href="/partners/#{ partner.id }/">
|
||||
<img class="media-object" t-att-src="partner.img('image_small')"/>
|
||||
</a>
|
||||
<div class="media-body" style="min-height: 64px;">
|
||||
<a class="media-heading" t-attf-href="/partners/#{ partner.id }/"><span t-field="partner.parent_id"/> <span t-field="partner.name"/></a> - <span t-field="partner.grade_id"/>
|
||||
<a class="media-heading" t-href="/partners/#{ partner.id }/"><span t-field="partner.parent_id"/> <span t-field="partner.name"/></a> - <span t-field="partner.grade_id"/>
|
||||
<div t-field="partner.website_short_description"/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -36,7 +36,7 @@ import werkzeug
|
|||
class website_event(http.Controller):
|
||||
_order = 'website_published desc, date_begin desc'
|
||||
|
||||
@website.route(['/event/', '/event/page/<int:page>/'], type='http', auth="public")
|
||||
@website.route(['/event/', '/event/page/<int:page>/'], type='http', auth="public", multilang=True)
|
||||
def events(self, page=1, **searches):
|
||||
cr, uid, context = request.cr, request.uid, request.context
|
||||
event_obj = request.registry['event.event']
|
||||
|
@ -152,7 +152,7 @@ class website_event(http.Controller):
|
|||
|
||||
return request.website.render("website_event.index", values)
|
||||
|
||||
@website.route(['/event/<int:event_id>'], type='http', auth="public")
|
||||
@website.route(['/event/<int:event_id>'], type='http', auth="public", multilang=True)
|
||||
def event(self, event_id=None, **post):
|
||||
event_obj = request.registry['event.event']
|
||||
values = {
|
||||
|
@ -162,7 +162,7 @@ class website_event(http.Controller):
|
|||
}
|
||||
return request.website.render("website_event.event_description_full", values)
|
||||
|
||||
@website.route(['/event/<int:event_id>/add_cart'], type='http', auth="public")
|
||||
@website.route(['/event/<int:event_id>/add_cart'], type='http', auth="public", multilang=True)
|
||||
def add_cart(self, event_id=None, **post):
|
||||
user_obj = request.registry['res.users']
|
||||
order_line_obj = request.registry.get('sale.order.line')
|
||||
|
@ -210,5 +210,5 @@ class website_event(http.Controller):
|
|||
order.write({'order_line': [(4, order_line_id)]}, context=request.context)
|
||||
|
||||
if not _values:
|
||||
return werkzeug.utils.redirect("/event/%s/" % event_id)
|
||||
return werkzeug.utils.redirect("/shop/checkout")
|
||||
return request.redirect("/event/%s/" % event_id)
|
||||
return request.redirect("/shop/checkout")
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
|
||||
<template id="header_footer" inherit_id="website_sale.header_footer">
|
||||
<xpath expr="//header//ul[@id='top_menu']/li" position="before">
|
||||
<li><a href="/event">Events</a></li>
|
||||
<li><a t-href="/event">Events</a></li>
|
||||
</xpath>
|
||||
<xpath expr="//footer//ul[@name='products']/li" position="after">
|
||||
<li><a href="/event">Events</a></li>
|
||||
<li><a t-href="/event">Events</a></li>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
|
@ -36,7 +36,7 @@
|
|||
<li class="nav-header">Date</li>
|
||||
<t t-foreach="dates" t-as="date">
|
||||
<li t-att-class="searches.get('date') == date[0] and 'active' or ''">
|
||||
<a t-attf-href="/event/#{ search_path }&date=#{ date[0] }"><t t-esc="date[1]"/> <small t-if="date[3]">(<t t-esc="date[3]"/>)</small></a>
|
||||
<a t-href="/event/#{ search_path }&date=#{ date[0] }"><t t-esc="date[1]"/> <small t-if="date[3]">(<t t-esc="date[3]"/>)</small></a>
|
||||
</li>
|
||||
</t>
|
||||
</ul>
|
||||
|
@ -74,7 +74,7 @@
|
|||
available.
|
||||
</span>
|
||||
</t>
|
||||
<h4 class="media-heading"><a t-attf-href="/event/#{ event.id }/"><span t-field="event.name"> </span></a></h4>
|
||||
<h4 class="media-heading"><a t-href="/event/#{ event.id }/"><span t-field="event.name"> </span></a></h4>
|
||||
<div>
|
||||
<span t-field="event.type">: </span>
|
||||
<t t-if="event.organizer_id">
|
||||
|
@ -107,7 +107,7 @@
|
|||
<li class="nav-header">Category</li>
|
||||
<t t-foreach="types">
|
||||
<li t-if="type" t-att-class="searches.get('type') == str(type and type[0]) and 'active' or ''">
|
||||
<a t-attf-href="/event/#{ search_path }&type=#{ type[0] }"><t t-esc="type[1]"/> <small>(<t t-esc="type_count"/>)</small></a>
|
||||
<a t-href="/event/#{ search_path }&type=#{ type[0] }"><t t-esc="type[1]"/> <small>(<t t-esc="type_count"/>)</small></a>
|
||||
</li>
|
||||
</t>
|
||||
</ul>
|
||||
|
@ -119,7 +119,7 @@
|
|||
<li class="nav-header">Location</li>
|
||||
<t t-foreach="countries">
|
||||
<li t-if="country_id" t-att-class="searches.get('country') == str(country_id and country_id[0]) and 'active' or ''">
|
||||
<a t-attf-href="/event/#{ search_path }&country=#{ country_id[0] }"><t t-esc="country_id[1]"/><small>(<t t-esc="country_id_count"/>)</small></a>
|
||||
<a t-href="/event/#{ search_path }&country=#{ country_id[0] }"><t t-esc="country_id[1]"/><small>(<t t-esc="country_id_count"/>)</small></a>
|
||||
</li>
|
||||
</t>
|
||||
</ul>
|
||||
|
@ -164,7 +164,7 @@
|
|||
<div class="col-md-8">
|
||||
<t t-if="event_id.event_ticket_ids">
|
||||
<hr/>
|
||||
<form t-attf-action="/event/#{ event_id.id }/add_cart" method="post">
|
||||
<form t-action="/event/#{ event_id.id }/add_cart" method="post">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
|
|
|
@ -6,7 +6,7 @@ from openerp.addons.website import website
|
|||
|
||||
class website_hr(http.Controller):
|
||||
|
||||
@website.route(['/page/website.aboutus'], type='http', auth="public")
|
||||
@website.route(['/page/website.aboutus'], type='http', auth="public", multilang=True)
|
||||
def blog(self, **post):
|
||||
hr_obj = request.registry['hr.employee']
|
||||
employee_ids = hr_obj.search(request.cr, request.uid, [(1, "=", 1)],
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
<template id="footer_custom" inherit_id="website.layout" name="Custom Footer">
|
||||
<xpath expr="//footer//div[@name='info']/ul" position="inside">
|
||||
<li><a href="/blog/%(website_hr.website_mail_job)d/">Jobs</a></li>
|
||||
<li><a t-href="/blog/%(website_hr.website_mail_job)d/">Jobs</a></li>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import urllib
|
|||
|
||||
class website_crm_partner_assign(http.Controller):
|
||||
|
||||
@website.route(['/members/', '/members/page/<int:page>/'], type='http', auth="public")
|
||||
@website.route(['/members/', '/members/page/<int:page>/'], type='http', auth="public", multilang=True)
|
||||
def members(self, page=0, **post):
|
||||
membership_obj = request.registry['membership.membership_line']
|
||||
|
||||
|
@ -56,7 +56,7 @@ class website_crm_partner_assign(http.Controller):
|
|||
}
|
||||
return request.website.render("website_membership.index", values)
|
||||
|
||||
@website.route(['/members/<int:ref_id>/'], type='http', auth="public")
|
||||
@website.route(['/members/<int:ref_id>/'], type='http', auth="public", multilang=True)
|
||||
def partners_ref(self, ref_id=0, **post):
|
||||
partner_obj = request.registry['res.partner']
|
||||
partner_ids = partner_obj.search(request.cr, openerp.SUPERUSER_ID, [('website_published', '=', True), ('id', '=', ref_id)], context=request.context)
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
<template id="footer_custom" inherit_id="website.layout" name="Custom Footer">
|
||||
<xpath expr="//footer//div[@name='info']/ul" position="inside">
|
||||
<li><a href="/members/">Members</a></li>
|
||||
<li><a t-href="/members/">Members</a></li>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
|
@ -41,7 +41,7 @@
|
|||
<t t-call="website.pager">
|
||||
<t t-set="classname">pull-left</t>
|
||||
</t>
|
||||
<form action="/members/" method="get" class="navbar-search pull-right pagination form-inline">
|
||||
<form t-action="/members/" method="get" class="navbar-search pull-right pagination form-inline">
|
||||
<div class="form-group">
|
||||
<input type="text" name="search" class="search-query col-md-2 mt4 form-control" placeholder="Search" t-att-value="searches.get('search') or '' or ''"/>
|
||||
</div>
|
||||
|
@ -68,11 +68,11 @@
|
|||
<t t-set="partner" t-value="membership_line_id.partner"/>
|
||||
<div class="media thumbnail" data-publish="">
|
||||
<t t-call="website.publish_management"><t t-set="object" t-value="partner"/></t>
|
||||
<a class="pull-left" t-attf-href="/members/#{ partner.id }/">
|
||||
<a class="pull-left" t-href="/members/#{ partner.id }/">
|
||||
<img class="media-object" t-att-src="partner.img('image_small')"/>
|
||||
</a>
|
||||
<div class="media-body" style="min-height: 64px;">
|
||||
<a class="media-heading" t-attf-href="/members/#{ partner.id }/"><span t-field="partner.parent_id"/> <span t-field="partner.name"/></a> - <span t-field="membership_line_id.membership_id"/>
|
||||
<a class="media-heading" t-href="/members/#{ partner.id }/"><span t-field="partner.parent_id"/> <span t-field="partner.name"/></a> - <span t-field="membership_line_id.membership_id"/>
|
||||
<div t-field="partner.website_short_description"/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -39,7 +39,7 @@ class Website(osv.Model):
|
|||
|
||||
class website_project(http.Controller):
|
||||
|
||||
@website.route(['/project/<int:project_id>/'], type='http', auth="public")
|
||||
@website.route(['/project/<int:project_id>/'], type='http', auth="public", multilang=True)
|
||||
def project(self, project_id=None, **post):
|
||||
cr, uid, context = request.cr, request.uid, request.context
|
||||
project_obj = request.registry['project.project']
|
||||
|
@ -51,7 +51,7 @@ class website_project(http.Controller):
|
|||
}
|
||||
return request.website.render("website_project.index", render_values)
|
||||
|
||||
@website.route(['/project/task/<int:task_id>'], type='http', auth="public")
|
||||
@website.route(['/project/task/<int:task_id>'], type='http', auth="public", multilang=True)
|
||||
def task(self, task_id=None, **post):
|
||||
cr, uid, context = request.cr, request.uid, request.context
|
||||
task_obj = request.registry['project.task']
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<!-- Layout add nav and footer -->
|
||||
<template id="footer_custom" inherit_id="website.layout" name="Custom Footer">
|
||||
<xpath expr="//footer//ul[@name='products']" position="inside">
|
||||
<li t-foreach="website_project_ids" t-as="project"><a t-attf-href="/project/#{ project.id }/"><t t-esc="project.name"/></a></li>
|
||||
<li t-foreach="website_project_ids" t-as="project"><a t-href="/project/#{ project.id }/"><t t-esc="project.name"/></a></li>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
|||
<!-- Project -->
|
||||
<template id="task_kanban_card" name="TaskKanban">
|
||||
<div class="thumbnail">
|
||||
<a t-attf-href="/project/task/#{object_id.id}/"><span t-field="object_id.name"/></a>
|
||||
<a t-href="/project/task/#{object_id.id}/"><span t-field="object_id.name"/></a>
|
||||
<div>
|
||||
Assigned to <span t-field="object_id.user_id"/>
|
||||
</div>
|
||||
|
|
|
@ -209,7 +209,7 @@ class Ecommerce(http.Controller):
|
|||
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)
|
||||
|
||||
@website.route(['/shop/', '/shop/category/<cat_id>/', '/shop/category/<cat_id>/page/<int:page>/', '/shop/page/<int:page>/'], type='http', auth="public")
|
||||
@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):
|
||||
|
||||
if 'promo' in post:
|
||||
|
@ -250,7 +250,7 @@ class Ecommerce(http.Controller):
|
|||
}
|
||||
return request.website.render("website_sale.products", values)
|
||||
|
||||
@website.route(['/shop/product/<product_id>/'], type='http', auth="public")
|
||||
@website.route(['/shop/product/<product_id>/'], type='http', auth="public", multilang=True)
|
||||
def product(self, cat_id=0, product_id=0, **post):
|
||||
|
||||
if 'promo' in post:
|
||||
|
@ -293,11 +293,11 @@ 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")
|
||||
@website.route(['/shop/add_product/', '/shop/category/<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)
|
||||
return werkzeug.utils.redirect("/shop/product/%s/?unable_editor=1" % product_id)
|
||||
return request.redirect("/shop/product/%s/?unable_editor=1" % product_id)
|
||||
|
||||
def get_pricelist(self):
|
||||
if not request.httprequest.session.get('ecommerce_pricelist'):
|
||||
|
@ -385,7 +385,7 @@ class Ecommerce(http.Controller):
|
|||
|
||||
return [quantity, order.get_total_quantity()]
|
||||
|
||||
@website.route(['/shop/mycart/'], type='http', auth="public")
|
||||
@website.route(['/shop/mycart/'], type='http', auth="public", multilang=True)
|
||||
def mycart(self, **post):
|
||||
order = get_current_order()
|
||||
prod_obj = request.registry.get('product.product')
|
||||
|
@ -411,10 +411,10 @@ class Ecommerce(http.Controller):
|
|||
}
|
||||
return request.website.render("website_sale.mycart", values)
|
||||
|
||||
@website.route(['/shop/<path:path>/add_cart/', '/shop/add_cart/'], type='http', auth="public")
|
||||
def add_cart(self, path=None, product_id=None, order_line_id=None, remove=None):
|
||||
@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))
|
||||
return werkzeug.utils.redirect("/shop/mycart/")
|
||||
return request.redirect("/shop/mycart/")
|
||||
|
||||
@website.route(['/shop/add_cart_json/'], type='json', auth="public")
|
||||
def add_cart_json(self, product_id=None, order_line_id=None, remove=None):
|
||||
|
@ -424,7 +424,7 @@ class Ecommerce(http.Controller):
|
|||
def set_cart_json(self, path=None, product_id=None, order_line_id=None, set_number=0, json=None):
|
||||
return self.add_product_to_cart(product_id=product_id, order_line_id=order_line_id, set_number=set_number)
|
||||
|
||||
@website.route(['/shop/checkout/'], type='http', auth="public")
|
||||
@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"]
|
||||
rel_fields = ['country_id', 'state_id']
|
||||
|
@ -465,7 +465,7 @@ class Ecommerce(http.Controller):
|
|||
|
||||
return request.website.render("website_sale.checkout", values)
|
||||
|
||||
@website.route(['/shop/confirm_order/'], type='http', auth="public")
|
||||
@website.route(['/shop/confirm_order/'], type='http', auth="public", multilang=True)
|
||||
def confirm_order(self, **post):
|
||||
order = get_current_order()
|
||||
|
||||
|
@ -474,10 +474,10 @@ class Ecommerce(http.Controller):
|
|||
user_obj = request.registry.get('res.users')
|
||||
|
||||
if order.state != 'draft':
|
||||
return werkzeug.utils.redirect("/shop/checkout/")
|
||||
return request.redirect("/shop/checkout/")
|
||||
if not order.order_line:
|
||||
error.append("empty_cart")
|
||||
return werkzeug.utils.redirect("/shop/checkout/")
|
||||
return request.redirect("/shop/checkout/")
|
||||
|
||||
# check values
|
||||
request.session['checkout'] = post
|
||||
|
@ -488,7 +488,7 @@ class Ecommerce(http.Controller):
|
|||
if post.get('shipping_different') and key != 'email' and not post.get("shipping_%s" % key):
|
||||
error.append("shipping_%s" % key)
|
||||
if error:
|
||||
return werkzeug.utils.redirect("/shop/checkout/?error=%s&shipping=%s" % (",".join(error), post.get('shipping_different') and 'on' or ''))
|
||||
return request.redirect("/shop/checkout/?error=%s&shipping=%s" % (",".join(error), post.get('shipping_different') and 'on' or ''))
|
||||
|
||||
# search or create company
|
||||
company_id = None
|
||||
|
@ -548,9 +548,9 @@ class Ecommerce(http.Controller):
|
|||
order_value.update(request.registry.get('sale.order').onchange_partner_id(request.cr, SUPERUSER_ID, [], order.partner_id.id, context=request.context)['value'])
|
||||
order.write(order_value)
|
||||
|
||||
return werkzeug.utils.redirect("/shop/payment/")
|
||||
return request.redirect("/shop/payment/")
|
||||
|
||||
@website.route(['/shop/payment/'], type='http', auth="public")
|
||||
@website.route(['/shop/payment/'], type='http', auth="public", multilang=True)
|
||||
def payment(self, **post):
|
||||
order = get_current_order()
|
||||
|
||||
|
@ -571,11 +571,11 @@ class Ecommerce(http.Controller):
|
|||
|
||||
return request.website.render("website_sale.payment", values)
|
||||
|
||||
@website.route(['/shop/payment_validate/'], type='http', auth="public")
|
||||
@website.route(['/shop/payment_validate/'], type='http', auth="public", multilang=True)
|
||||
def payment_validate(self, **post):
|
||||
request.httprequest.session['ecommerce_order_id'] = False
|
||||
request.httprequest.session['ecommerce_pricelist'] = False
|
||||
return werkzeug.utils.redirect("/shop/")
|
||||
return request.redirect("/shop/")
|
||||
|
||||
@website.route(['/shop/change_sequence/'], type='json', auth="public")
|
||||
def change_sequence(self, id, top):
|
||||
|
|
|
@ -45,9 +45,9 @@
|
|||
|
||||
<template id="header_footer" inherit_id="website.layout" name="Custom Footer">
|
||||
<xpath expr="//header//ul[@id='top_menu']/li" position="before">
|
||||
<li><a href="/shop/">Shop</a></li>
|
||||
<li><a t-href="/shop/">Shop</a></li>
|
||||
<li>
|
||||
<a href="/shop/mycart/">
|
||||
<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 ''"/>
|
||||
|
@ -55,9 +55,9 @@
|
|||
</li>
|
||||
</xpath>
|
||||
<xpath expr="//footer//ul[@name='products']" position="inside">
|
||||
<li><a href="/shop/">Shop</a></li>
|
||||
<li><a t-href="/shop/">Shop</a></li>
|
||||
<li>
|
||||
<a href="/shop/mycart/">
|
||||
<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 ''"/>
|
||||
|
@ -69,7 +69,7 @@
|
|||
|
||||
<template id="categories_recursive">
|
||||
<li t-att-class="category.id == category_id and 'active' or ''">
|
||||
<a t-att-class="category.id not in categ[1] and 'unpublish' or ''" t-attf-href="/shop/category/#{ category.id }/" t-field="category.name"></a>
|
||||
<a t-att-class="category.id not in categ[1] and 'unpublish' or ''" t-href="/shop/category/#{ category.id }/" t-field="category.name"></a>
|
||||
<ul t-if="category.child_id" class="nav nav-pills nav-stacked nav-hierarchy">
|
||||
<t t-foreach="category.child_id" t-as="category">
|
||||
<t t-if="category.id in categ[1] or editable">
|
||||
|
@ -84,7 +84,7 @@
|
|||
|
||||
<template id="products_cart">
|
||||
<div class="oe_product_description">
|
||||
<a t-attf-href="/shop/product/#{ product.id }/?#{ search and ('search=%s' % search) or ''}#{ category_id and ('&category_id=%s' % category_id) or ''}">
|
||||
<a t-href="/shop/product/#{ product.id }/?#{ search and ('search=%s' % search) or ''}#{ category_id and ('&category_id=%s' % category_id) or ''}">
|
||||
<b t-field="product.name"/>
|
||||
</a>
|
||||
<!-- This should be an option -->
|
||||
|
@ -104,7 +104,7 @@
|
|||
</div>
|
||||
|
||||
<div class="oe_product_image text-center">
|
||||
<a t-attf-href="/shop/product/#{ product.id }/?#{ search and ('search=%s' % search) or ''}#{ category_id and ('&category_id=%s' % category_id) or ''}">
|
||||
<a t-href="/shop/product/#{ product.id }/?#{ search and ('search=%s' % search) or ''}#{ category_id and ('&category_id=%s' % category_id) or ''}">
|
||||
<img class="img" t-att-src="product.img('image')"/>
|
||||
</a>
|
||||
</div>
|
||||
|
@ -125,9 +125,9 @@
|
|||
<div class="col-sm-4">
|
||||
<h1>Our Products</h1>
|
||||
</div><div class="col-sm-4 pagination text-center">
|
||||
<a t-if="editable" t-attf-href="/shop/#{ category_id and ('category/%s/' % category_id) or ''}add_product/" class="btn btn-default">New Product</a>
|
||||
<a t-if="editable" t-href="/shop/#{ category_id and ('category/%s/' % category_id) or ''}add_product/" class="btn btn-default">New Product</a>
|
||||
</div><div class="col-sm-4">
|
||||
<form t-attf-action="/shop/#{ category_id and ('category/%s/' % category_id) or ''}" method="get" class="pull-right pagination">
|
||||
<form t-action="/shop/#{ category_id and ('category/%s/' % category_id) or ''}" method="get" class="pull-right pagination">
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon"><span class="glyphicon glyphicon-search"/></span>
|
||||
<input type="text" name="search" class="search-query form-control" placeholder="Search..." t-att-value="search or ''"/>
|
||||
|
@ -193,7 +193,7 @@
|
|||
|
||||
<template id="add_to_basket" inherit_option_id="website_sale.products_cart" name="Add to Cart">
|
||||
<xpath expr="//div[@class='product_price']" position="inside">
|
||||
<a t-attf-href="./add_cart/?product_id=#{ product.id }">
|
||||
<a t-href="./add_cart/?product_id=#{ product.id }">
|
||||
<span class="icon-shopping-cart"/>
|
||||
</a>
|
||||
</xpath>
|
||||
|
@ -229,8 +229,8 @@
|
|||
<div class="row">
|
||||
<div class="col-sm-5">
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="/shop">Products</a></li>
|
||||
<li t-if="category"><a t-att-href="'/shop/category/%s' % (category_id,)"><span t-field="category.name"/></a></li>
|
||||
<li><a t-href="/shop">Products</a></li>
|
||||
<li t-if="category"><a t-href="'/shop/category/%s' % (category_id,)"><span t-field="category.name"/></a></li>
|
||||
<li class="active" t-field="product.name">Product Name</li>
|
||||
</ol>
|
||||
</div><div class="col-sm-3">
|
||||
|
@ -253,7 +253,7 @@
|
|||
</li>
|
||||
</t>
|
||||
</div><div class="col-sm-3 col-sm-offset-1">
|
||||
<form t-attf-action="/shop/#{ category_id and ('category/%s/' % category_id) or ''}" method="get" class="pull-right">
|
||||
<form t-action="/shop/#{ category_id and ('category/%s/' % category_id) or ''}" method="get" class="pull-right">
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon"><span class="glyphicon glyphicon-search"/></span>
|
||||
<input type="text" name="search" class="search-query form-control" placeholder="Search..." t-att-value="search or ''"/>
|
||||
|
@ -270,7 +270,7 @@
|
|||
</div><div class="col-sm-5 col-md-5 col-lg-4 col-lg-offset-1">
|
||||
<h1 t-field="product.name">Product Name</h1>
|
||||
|
||||
<form action="./add_cart/">
|
||||
<form t-action="./add_cart/">
|
||||
<input type="hidden" t-if="len(product.product_variant_ids) <= 1" name="product_id" t-att-value="product.id"/>
|
||||
<t t-if="len(product.product_variant_ids) > 1">
|
||||
<label label-default="label-default" class="radio" t-foreach="product.product_variant_ids" t-as="product">
|
||||
|
@ -319,7 +319,7 @@
|
|||
<div class='mt16 text-center'>
|
||||
<img t-att-src="product.img('image_small')"/>
|
||||
<h5>
|
||||
<a t-attf-href="/shop/product/#{ product.id }/"
|
||||
<a t-href="/shop/product/#{ product.id }/"
|
||||
style="display: block">
|
||||
<span t-field='product.name'
|
||||
style="display: block"/>
|
||||
|
@ -368,10 +368,10 @@
|
|||
<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-attf-href="/shop/product/#{ line.product_id.product_tmpl_id.id }/"><img class="img-rounded" t-att-src="line.product_id.img('image_small')"/></a>
|
||||
<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-attf-href="/shop/product/#{ line.product_id.product_tmpl_id.id }/"><span t-field="line.name"/></a><br/>
|
||||
<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>
|
||||
|
@ -383,8 +383,8 @@
|
|||
<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-attf-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-attf-href="./add_cart/?order_line_id=#{ line.id }" t-att-data-id="line.id" class="btn btn-default mb8 btn-sm btn-success">+</a>
|
||||
<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>
|
||||
|
@ -404,7 +404,7 @@
|
|||
<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>
|
||||
</thead>
|
||||
</table>
|
||||
<a t-if="website_sale_order and website_sale_order.order_line" href="/shop/checkout/" class="btn btn-success">Proceed To Payment</a>
|
||||
<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>
|
||||
</div>
|
||||
<div class="oe_structure"/>
|
||||
|
@ -418,7 +418,7 @@
|
|||
<xpath expr="//div[@id='products_grid']" position="before">
|
||||
<div class="col-md-3">
|
||||
<ul class="nav nav-pills nav-stacked mt16">
|
||||
<li t-att-class=" '' if category_id else 'active' "><a href="/shop/">All Products</a></li>
|
||||
<li t-att-class=" '' if category_id else 'active' "><a t-href="/shop/">All Products</a></li>
|
||||
<t t-set="categ" t-value="get_categories()"/>
|
||||
<t t-foreach="categ[0]" t-as="category">
|
||||
<t t-call="website_sale.categories_recursive"/>
|
||||
|
@ -449,7 +449,7 @@
|
|||
<t t-foreach="suggested_products" t-as="product">
|
||||
<tr>
|
||||
<td>
|
||||
<a t-attf-href="/shop/product/#{ product.id }/"><span t-field="product.name"/></a><br/>
|
||||
<a t-href="/shop/product/#{ product.id }/"><span t-field="product.name"/></a><br/>
|
||||
<small t-field="product.description_sale"/>
|
||||
</td>
|
||||
<td>
|
||||
|
@ -457,7 +457,7 @@
|
|||
</td>
|
||||
<td>
|
||||
<div class="pull-right">
|
||||
<a t-attf-href="./add_cart/?product_id=#{ product.id }" class="btn btn-sm btn-success">+</a>
|
||||
<a t-href="./add_cart/?product_id=#{ product.id }" class="btn btn-sm btn-success">+</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -474,11 +474,11 @@
|
|||
<t t-foreach="suggested_products" t-as="product">
|
||||
<div class='col-md-2 thumbnail'>
|
||||
<div class='mt16 text-center'>
|
||||
<a t-attf-href="/shop/product/#{ product.id }/">
|
||||
<a t-href="/shop/product/#{ product.id }/">
|
||||
<img t-att-src="product.img('image_small')"/>
|
||||
</a>
|
||||
<h5>
|
||||
<a t-attf-href="/shop/product/#{ product.id }/" style="display: block;">
|
||||
<a t-href="/shop/product/#{ product.id }/" style="display: block;">
|
||||
<span t-field="product.name"/>
|
||||
</a>
|
||||
</h5>
|
||||
|
@ -491,7 +491,7 @@
|
|||
</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" action="/shop/mycart/" method="post">
|
||||
<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>
|
||||
</form>
|
||||
|
@ -536,7 +536,7 @@
|
|||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
<form class="col-md-8 form-horizontal" action="/shop/confirm_order/" method="post">
|
||||
<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>
|
||||
|
@ -737,7 +737,7 @@
|
|||
<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 href="/shop/payment_validate/" class="hidden btn btn-default">I validate my payment</a>
|
||||
<a t-href="/shop/payment_validate/" class="hidden btn btn-default">I validate my payment</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue