[IMP] restaurant: a module that extends the point of sale with restaurant features

This commit is contained in:
Frederic van der Essen
2014-08-05 14:09:48 +02:00
parent bfd66f351b
commit 09bf85ae02
14 changed files with 957 additions and 0 deletions
+25
View File
@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import restaurant
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+55
View File
@@ -0,0 +1,55 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
{
'name': 'Restaurant',
'version': '1.0',
'category': 'Point of Sale',
'sequence': 6,
'summary': 'Restaurant extensions for the Point of Sale ',
'description': """
=======================
This module adds several restaurant features to the Point of Sale:
- Bill Printing: Allows you to print a receipt before the order is paid
- Bill Splitting: Allows you to split an order into different orders
- Kitchen Order Printing: allows you to print orders updates to kitchen or bar printers
""",
'author': 'OpenERP SA',
'depends': ['point_of_sale'],
'data': [
'restaurant_view.xml',
'security/ir.model.access.csv',
'views/templates.xml',
],
'qweb':[
'static/src/xml/multiprint.xml',
'static/src/xml/splitbill.xml',
'static/src/xml/printbill.xml',
],
'installable': True,
'auto_install': False,
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+55
View File
@@ -0,0 +1,55 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import logging
import openerp
from openerp import tools
from openerp.osv import fields, osv
from openerp.tools.translate import _
_logger = logging.getLogger(__name__)
class restaurant_printer(osv.osv):
_name = 'restaurant.printer'
_columns = {
'name' : fields.char('Printer Name', size=32, required=True, help='An internal identification of the printer'),
'proxy_ip': fields.char('Proxy IP Address', size=32, help="The IP Address or hostname of the Printer's hardware proxy"),
'product_categories_ids': fields.many2many('pos.category','printer_category_rel', 'printer_id','category_id',string='Printed Product Categories'),
}
_defaults = {
'name' : 'Printer',
}
class pos_config(osv.osv):
_inherit = 'pos.config'
_columns = {
'iface_splitbill': fields.boolean('Bill Splitting', help='Enables Bill Splitting in the Point of Sale'),
'iface_printbill': fields.boolean('Bill Printing', help='Allows to print the Bill before payment'),
'printer_ids': fields.many2many('restaurant.printer','pos_config_printer_rel', 'config_id','printer_id',string='Order Printers'),
}
_defaults = {
'iface_splitbill': False,
'iface_printbill': False,
}
+74
View File
@@ -0,0 +1,74 @@
<?xml version="1.0"?>
<openerp>
<data>
<record model="ir.ui.view" id="view_restaurant_printer_form">
<field name="name">Order Printer</field>
<field name="model">restaurant.printer</field>
<field name="arch" type="xml">
<form string="POS Printer" version="7.0">
<group col="2">
<field name="name" />
<field name="proxy_ip" />
<field name="product_categories_ids" />
</group>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="action_restaurant_printer_form">
<field name="name">Order Printers</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">restaurant.printer</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to add a Restaurant Order Printer.
</p><p>
Order Printers are used by restaurants and bars to print the
order updates in the kitchen/bar when the waiter updates the order.
</p><p>
Each Order Printer has an IP Address that defines the PosBox/Hardware
Proxy where the printer can be found, and a list of product categories.
An Order Printer will only print updates for prodcuts belonging to one of
its categories.
</p>
</field>
</record>
<record model="ir.ui.view" id="view_restaurant_printer">
<field name="name">Order Printers</field>
<field name="model">restaurant.printer</field>
<field name="arch" type="xml">
<tree string="Restaurant Order Printers">
<field name="name" />
<field name="proxy_ip" />
<field name="product_categories_ids" />
</tree>
</field>
</record>
<menuitem
parent="point_of_sale.menu_point_config_product"
action="action_restaurant_printer_form"
id="menu_restaurant_printer_all"
sequence="30"
groups="point_of_sale.group_pos_manager"/>
<record model="ir.ui.view" id="view_pos_config_form">
<field name="name">pos.config.form.view.inherit</field>
<field name="model">pos.config</field>
<field name="inherit_id" ref="point_of_sale.view_pos_config_form"></field>
<field name="arch" type="xml">
<sheet position='inside'>
<group string="Bar &amp; Restaurant" >
<field name="iface_splitbill" />
<field name="iface_printbill" />
<field name="printer_ids" />
</group>
</sheet>
</field>
</record>
</data>
</openerp>
@@ -0,0 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_restaurant_printer,restaurant.printer.user,model_restaurant_printer,point_of_sale.group_pos_user,1,0,0,0
access_restaurant_printer_manager,restaurant.printer.manager,model_restaurant_printer,point_of_sale.group_pos_manager,1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_restaurant_printer restaurant.printer.user model_restaurant_printer point_of_sale.group_pos_user 1 0 0 0
3 access_restaurant_printer_manager restaurant.printer.manager model_restaurant_printer point_of_sale.group_pos_manager 1 0 0 0
@@ -0,0 +1,2 @@
/* --- Restaurant Specific CSS --- */
+11
View File
@@ -0,0 +1,11 @@
openerp.restaurant = function(instance){
var module = instance.point_of_sale;
openerp_restaurant_multiprint(instance,module);
openerp_restaurant_splitbill(instance,module);
openerp_restaurant_printbill(instance,module);
};
@@ -0,0 +1,215 @@
function openerp_restaurant_multiprint(instance,module){
var QWeb = instance.web.qweb;
var _t = instance.web._t;
module.Printer = instance.web.Class.extend(openerp.PropertiesMixin,{
init: function(parent,options){
openerp.PropertiesMixin.init.call(this,parent);
var self = this;
options = options || {};
var url = options.url || 'http://localhost:8069';
this.connection = new instance.web.Session(undefined,url, { use_cors: true});
this.host = url;
this.receipt_queue = [];
},
print: function(receipt){
var self = this;
if(receipt){
this.receipt_queue.push(receipt);
}
var aborted = false;
function send_printing_job(){
if(self.receipt_queue.length > 0){
var r = self.receipt_queue.shift();
self.connection.rpc('/hw_proxy/print_xml_receipt',{receipt: r},{timeout: 5000})
.then(function(){
send_printing_job();
},function(){
self.receipt_queue.unshift(r);
});
}
}
send_printing_job();
},
});
module.PosModel.prototype.models.push({
model: 'restaurant.printer',
fields: ['name','proxy_ip','product_categories_ids'],
domain: null,
loaded: function(self,printers){
var active_printers = {};
for (var i = 0; i < self.config.printer_ids.length; i++) {
active_printers[self.config.printer_ids[i]] = true;
}
self.printers = [];
for(var i = 0; i < printers.length; i++){
if(active_printers[printers[i].id]){
var printer = new module.Printer(self,{url:'http://'+printers[i].proxy_ip+':8069'});
printer.config = printers[i];
self.printers.push(printer);
}
}
},
});
module.Order = module.Order.extend({
lineResume: function(){
var resume = {};
this.get('orderLines').each(function(item){
var line = item.export_as_JSON();
if( typeof resume[line.product_id] === 'undefined'){
resume[line.product_id] = line.qty;
}else{
resume[line.product_id] += line.qty;
}
});
return resume;
},
saveChanges: function(){
this.old_resume = this.lineResume();
},
computeChanges: function(categories){
var current = this.lineResume();
var old = this.old_resume || {};
var json = this.export_as_JSON();
var add = [];
var rem = [];
for( product in current){
if (typeof old[product] === 'undefined'){
add.push({
'id': product,
'name': this.pos.db.get_product_by_id(product).name,
'quantity': current[product],
});
}else if( old[product] < current[product]){
add.push({
'id': product,
'name': this.pos.db.get_product_by_id(product).name,
'quantity': current[product] - old[product],
});
}else if( old[product] > current[product]){
rem.push({
'id': product,
'name': this.pos.db.get_product_by_id(product).name,
'quantity': old[product] - current[product],
});
}
}
for( product in old){
if(typeof current[product] === 'undefined'){
rem.push({
'id': product,
'name': this.pos.db.get_product_by_id(product).name,
'quantity': old[product],
});
}
}
if(categories && categories.length > 0){
// filter the added and removed orders to only contains
// products that belong to one of the categories supplied as a parameter
var self = this;
function product_in_category(product_id){
var cat = self.pos.db.get_product_by_id(product_id).pos_categ_id[0];
while(cat){
for(var i = 0; i < categories.length; i++){
if(cat === categories[i]){
return true;
}
}
cat = self.pos.db.get_category_parent_id(cat);
}
return false;
}
var _add = [];
var _rem = [];
for(var i = 0; i < add.length; i++){
if(product_in_category(add[i].id)){
_add.push(add[i]);
}
}
add = _add;
for(var i = 0; i < rem.length; i++){
if(product_in_category(rem[i].id)){
_rem.push(rem[i]);
}
}
rem = _rem;
}
return {
'new': add,
'cancelled': rem,
'table': json.table || 'unknown table',
'name': json.name || 'unknown order',
};
},
printChanges: function(){
var printers = this.pos.printers;
for(var i = 0; i < printers.length; i++){
var changes = this.computeChanges(printers[i].config.product_categories_ids);
if ( changes['new'].length > 0 || changes['cancelled'].length > 0){
var receipt = QWeb.render('OrderChangeReceipt',{changes:changes, widget:this});
printers[i].print(receipt);
}
}
},
hasChangesToPrint: function(){
var printers = this.pos.printers;
for(var i = 0; i < printers.length; i++){
var changes = this.computeChanges(printers[i].config.product_categories_ids);
if ( changes['new'].length > 0 || changes['cancelled'].length > 0){
return true;
}
}
return false;
},
});
module.PosWidget.include({
build_widgets: function(){
var self = this;
this._super();
if(this.pos.printers.length){
var submitorder = $(QWeb.render('SubmitOrderButton'));
submitorder.click(function(){
var order = self.pos.get('selectedOrder');
if(order.hasChangesToPrint()){
order.printChanges();
order.saveChanges();
self.pos_widget.order_widget.update_summary();
}
});
submitorder.appendTo(this.$('.control-buttons'));
this.$('.control-buttons').removeClass('oe_hidden');
}
},
});
module.OrderWidget.include({
update_summary: function(){
this._super();
var order = this.pos.get('selectedOrder');
if(order.hasChangesToPrint()){
this.pos_widget.$('.order-submit').addClass('highlight');
}else{
this.pos_widget.$('.order-submit').removeClass('highlight');
}
},
});
}
@@ -0,0 +1,28 @@
function openerp_restaurant_printbill(instance,module){
var QWeb = instance.web.qweb;
var _t = instance.web._t;
module.PosWidget.include({
build_widgets: function(){
var self = this;
this._super();
if(this.pos.config.iface_printbill){
var printbill = $(QWeb.render('PrintBillButton'));
printbill.click(function(){
var order = self.pos.get('selectedOrder');
if(order.get('orderLines').models.length > 0){
var receipt = order.export_for_printing();
self.pos.proxy.print_receipt(QWeb.render('BillReceipt',{
receipt: receipt, widget: self,
}));
}
});
printbill.appendTo(this.$('.control-buttons'));
this.$('.control-buttons').removeClass('oe_hidden');
}
},
});
}
@@ -0,0 +1,180 @@
function openerp_restaurant_splitbill(instance, module){
var QWeb = instance.web.qweb;
var _t = instance.web._t;
module.SplitbillScreenWidget = module.ScreenWidget.extend({
template: 'SplitbillScreenWidget',
show_leftpane: false,
previous_screen: 'products',
renderElement: function(){
var self = this;
this._super();
var order = this.pos.get('selectedOrder');
if(!order){
return;
}
var orderlines = order.get('orderLines').models;
for(var i = 0; i < orderlines.length; i++){
var line = orderlines[i];
linewidget = $(QWeb.render('SplitOrderline',{
widget:this,
line:line,
selected: false,
quantity: 0,
id: line.id,
}));
linewidget.data('id',line.id);
this.$('.orderlines').append(linewidget);
}
this.$('.back').click(function(){
self.pos_widget.screen_selector.set_current_screen(self.previous_screen);
});
},
lineselect: function($el,order,neworder,splitlines,line_id){
var split = splitlines[line_id] || {'quantity': 0, line: null};
var line = order.getOrderline(line_id);
if( !line.get_unit().groupable ){
if( split.quantity !== line.get_quantity()){
split.quantity = line.get_quantity();
}else{
split.quantity = 0;
}
}else{
if( split.quantity < line.get_quantity()){
split.quantity += line.get_unit().rounding;
if(split.quantity > line.get_quantity()){
split.quantity = line.get_quantity();
}
}else{
split.quantity = 0;
}
}
if( split.quantity ){
if ( !split.line ){
split.line = line.clone();
neworder.addOrderline(split.line);
}
split.line.set_quantity(split.quantity);
}else if( split.line ) {
neworder.removeOrderline(split.line);
split.line = null;
}
splitlines[line_id] = split;
$el.replaceWith($(QWeb.render('SplitOrderline',{
widget: this,
line: line,
selected: split.quantity !== 0,
quantity: split.quantity,
id: line_id,
})));
this.$('.order-info .subtotal').text(this.format_currency(neworder.getSubtotal()));
},
pay: function($el,order,neworder,splitlines,cashregister_id){
var orderlines = order.get('orderLines').models;
var empty = true;
var full = true;
for(var i = 0; i < orderlines.length; i++){
var id = orderlines[i].id;
var split = splitlines[id];
if(!split){
full = false;
}else{
if(split.quantity){
empty = false;
if(split.quantity !== orderlines[i].get_quantity()){
full = false;
}
}
}
}
if(empty){
return;
}
for(var i = 0; i < this.pos.cashregisters.length; i++){
if(this.pos.cashregisters[i].id === cashregister_id){
var cashregister = this.pos.cashregisters[i];
break;
}
}
if(full){
order.addPaymentline(cashregister);
this.pos_widget.screen_selector.set_current_screen('payment');
}else{
for(var id in splitlines){
var split = splitlines[id];
var line = order.getOrderline(parseInt(id));
line.set_quantity(line.get_quantity() - split.quantity);
if(Math.abs(line.get_quantity()) < 0.00001){
order.removeOrderline(line);
}
delete splitlines[id];
}
neworder.addPaymentline(cashregister);
neworder.set_screen_data('screen','payment');
this.pos.get('orders').add(neworder);
this.pos.set('selectedOrder',neworder);
}
},
show: function(){
var self = this;
this._super();
this.renderElement();
var order = this.pos.get('selectedOrder');
var neworder = new module.Order({
pos: this.pos,
temporary: true,
});
neworder.set('client',order.get('client'));
var splitlines = {};
this.$('.orderlines').on('click','.orderline',function(){
var id = parseInt($(this).data('id'));
var $el = $(this);
self.lineselect($el,order,neworder,splitlines,id);
});
this.$('.paymentmethod').click(function(){
var id = parseInt($(this).data('id'));
var $el = $(this);
self.pay($el,order,neworder,splitlines,id);
});
},
});
module.PosWidget.include({
build_widgets: function(){
var self = this;
this._super();
if(this.pos.config.iface_splitbill){
this.splitbill_screen = new module.SplitbillScreenWidget(this,{});
this.splitbill_screen.appendTo(this.$('.screens'));
this.screen_selector.add_screen('splitbill',this.splitbill_screen);
var splitbill = $(QWeb.render('SplitbillButton'));
splitbill.click(function(){
if(self.pos.get('selectedOrder').get('orderLines').models.length > 0){
self.pos_widget.screen_selector.set_current_screen('splitbill');
}
});
splitbill.appendTo(this.$('.control-buttons'));
this.$('.control-buttons').removeClass('oe_hidden');
}
},
});
}
@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="SubmitOrderButton">
<span class="control-button order-submit">
<i class="fa fa-cutlery"></i>
Order
</span>
</t>
<t t-name="OrderChangeReceipt">
<receipt
align='center'
width='40'
size='double-height'
line-ratio='0.6'
value-decimals='3'
value-thousands-separator=''
value-autoint='on'
>
<div><t t-esc="changes.name" /></div>
<br />
<br />
<t t-if="changes.cancelled.length > 0">
<div color='red'>
<div bold='on' size='double'>CANCELLED</div>
<br />
<br />
<t t-foreach="changes.cancelled" t-as="change">
<line>
<left><t t-esc="change.name" /></left>
<right><value><t t-esc="change.quantity" /></value></right>
</line>
</t>
<br />
<br />
</div>
</t>
<t t-if="changes.new.length > 0">
<div bold='on' size='double'>NEW</div>
<br />
<br />
<t t-foreach="changes.new" t-as="change">
<line>
<left><t t-esc="change.name" /></left>
<right><value><t t-esc="change.quantity" /></value></right>
</line>
</t>
<br />
<br />
</t>
</receipt>
</t>
</templates>
@@ -0,0 +1,143 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="PrintBillButton">
<span class="control-button order-printbill">
<i class="fa fa-print"></i>
Bill
</span>
</t>
<t t-name="BillReceipt">
<receipt align='center' width='40' value-thousands-separator='' >
<t t-if='receipt.company.logo'>
<img t-att-src='receipt.company.logo' />
<br/>
</t>
<t t-if='!receipt.company.logo'>
<h1><t t-esc='receipt.company.name' /></h1>
<br/>
</t>
<div font='b'>
<t t-if='receipt.shop.name'>
<div><t t-esc='receipt.shop.name' /></div>
</t>
<t t-if='receipt.company.contact_address'>
<div><t t-esc='receipt.company.contact_address' /></div>
</t>
<t t-if='receipt.company.phone'>
<div>Tel:<t t-esc='receipt.company.phone' /></div>
</t>
<t t-if='receipt.company.vat'>
<div>VAT:<t t-esc='receipt.company.vat' /></div>
</t>
<t t-if='receipt.company.email'>
<div><t t-esc='receipt.company.email' /></div>
</t>
<t t-if='receipt.company.website'>
<div><t t-esc='receipt.company.website' /></div>
</t>
<t t-if='receipt.header'>
<div><t t-esc='receipt.header' /></div>
</t>
<t t-if='receipt.cashier'>
<div>--------------------------------</div>
<div>Served by <t t-esc='receipt.cashier' /></div>
</t>
</div>
<br /><br />
<!-- Orderlines -->
<div line-ratio='0.6'>
<t t-foreach='receipt.orderlines' t-as='line'>
<t t-set='simple' t-value='line.discount === 0 and line.unit_name === "Unit(s)" and line.quantity === 1' />
<t t-if='simple'>
<line>
<left><t t-esc='line.product_name' /></left>
<right><value><t t-esc='line.price_display' /></value></right>
</line>
</t>
<t t-if='!simple'>
<line><left><t t-esc='line.product_name' /></left></line>
<t t-if='line.discount !== 0'>
<line indent='1'><left>Discount: <t t-esc='line.discount' />%</left></line>
</t>
<line indent='1'>
<left>
<value value-decimals='3' value-autoint='on'>
<t t-esc='line.quantity' />
</value>
<t t-if='line.unit_name !== "Unit(s)"'>
<t t-esc='line.unit_name' />
</t>
x
<value value-decimals='2'>
<t t-esc='line.price' />
</value>
</left>
<right>
<value><t t-esc='line.price_display' /></value>
</right>
</line>
</t>
</t>
</div>
<!-- Subtotal -->
<t t-set='taxincluded' t-value='Math.abs(receipt.subtotal - receipt.total_with_tax) &lt;= 0.000001' />
<t t-if='!taxincluded'>
<line><right>--------</right></line>
<line><left>Subtotal</left><right> <value><t t-esc="receipt.subtotal" /></value></right></line>
<t t-foreach='receipt.tax_details' t-as='tax'>
<line>
<left><t t-esc='tax.name' /></left>
<right><value><t t-esc='tax.amount' /></value></right>
</line>
</t>
</t>
<!-- Total -->
<line><right>--------</right></line>
<line size='double-height'>
<left><pre> TOTAL</pre></left>
<right><value><t t-esc='receipt.total_with_tax' /></value></right>
</line>
<br/><br/>
<!-- Extra Payment Info -->
<t t-if='receipt.total_discount'>
<line>
<left>Discounts</left>
<right><value><t t-esc='receipt.total_discount'/></value></right>
</line>
</t>
<t t-if='taxincluded'>
<t t-foreach='receipt.tax_details' t-as='tax'>
<line>
<left><t t-esc='tax.name' /></left>
<right><value><t t-esc='tax.amount' /></value></right>
</line>
</t>
</t>
<!-- Footer -->
<t t-if='receipt.footer'>
<br/>
<pre><t t-esc='receipt.footer' /></pre>
<br/>
<br/>
</t>
<br/>
<div font='b'>
<div><t t-esc='receipt.name' /></div>
<div><t t-esc='receipt.date.localestring' /></div>
</div>
</receipt>
</t>
</templates>
@@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="SplitbillButton">
<span class="control-button order-split">
<i class="fa fa-copy"></i>
Split
</span>
</t>
<t t-name="SplitOrderline">
<li t-attf-class="orderline #{ selected ? 'selected' : ''} #{ quantity !== line.get_quantity() ? 'partially' : '' }"
t-att-data-id="id">
<span class="product-name">
<t t-esc="line.get_product().name"/>
</span>
<span class="price">
<t t-esc="widget.format_currency(line.get_display_price())"/>
</span>
<ul class="info-list">
<t t-if="line.get_quantity_str() !== '1'">
<li class="info">
<t t-if='selected and line.get_unit().groupable'>
<em class='big'>
<t t-esc='quantity' />
</em>
/
<t t-esc="line.get_quantity_str()" />
</t>
<t t-if='!(selected and line.get_unit().groupable)'>
<em>
<t t-esc="line.get_quantity_str()" />
</em>
</t>
<t t-esc="line.get_unit().name" />
at
<t t-esc="widget.format_currency(line.get_unit_price())" />
/
<t t-esc="line.get_unit().name" />
</li>
</t>
<t t-if="line.get_discount_str() !== '0'">
<li class="info">
With a
<em>
<t t-esc="line.get_discount_str()" />%
</em>
discount
</li>
</t>
</ul>
</li>
</t>
<t t-name="SplitbillScreenWidget">
<div class='splitbill-screen screen'>
<div class='screen-content'>
<div class='top-content'>
<span class='button back'>
<i class='fa fa-angle-double-left'></i>
Back
</span>
<h1>Bill Splitting</h1>
</div>
<div class='left-content touch-scrollable scrollable-y'>
<div class='order'>
<ul class='orderlines'>
</ul>
</div>
</div>
<div class='right-content touch-scrollable scrollable-y'>
<div class='order-info'>
<span class='subtotal'><t t-esc='widget.format_currency(0.0)'/></span>
</div>
<div class='paymentmethods'>
<t t-foreach="widget.pos.cashregisters" t-as="cashregister">
<div class='button paymentmethod' t-att-data-id="cashregister.id">
<t t-esc='cashregister.journal.name' />
</div>
</t>
</div>
</div>
</div>
</div>
</t>
</templates>
+23
View File
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- vim:fdn=3:
-->
<openerp>
<data>
<template id="index" inherit_id='point_of_sale.index' name="Restaurant Index">&lt;!DOCTYPE html&gt;
<xpath expr="//link[@id='pos-stylesheet']" position="after">
<link rel="stylesheet" href="/restaurant/static/src/css/restaurant.css" />
</xpath>
</template>
<template id="assets_frontend" inherit_id="web.assets_common">
<xpath expr="." position="inside">
<script type="text/javascript" src="/restaurant/static/src/js/multiprint.js"></script>
<script type="text/javascript" src="/restaurant/static/src/js/splitbill.js"></script>
<script type="text/javascript" src="/restaurant/static/src/js/printbill.js"></script>
<script type="text/javascript" src="/restaurant/static/src/js/main.js"></script>
</xpath>
</template>
</data>
</openerp>