parse_result.id = ean.substring(0,7);
parse_result.value = Number(ean.substring(7,12))/100.0;
parse_result.unit = 'euro';
- } else if (prefix2 in this.price_prefix_set){
+ } else if (prefix2 in this.weight_prefix_set){
parse_result.type = 'weight';
parse_result.prefix = prefix2;
parse_result.id = ean.substring(0,7);
return parse_result;
},
- simulate : function(type){
-
- var parse_result = {
- ean: '01238534932',
- type: type,
- prefix: '012',
- id: '392',
- value: 42,
- unit: 'Kg',
- };
-
- if(parse_result.type in {'unit':'', 'weight':'', 'price':''}){ //ean is associated to a product
- console.log('calling product callback');
- if(this.action_callback['product']){
- console.log('found product callback');
- this.action_callback['product'](parse_result);
- }
- }else{
- console.log('calling callback:',parse_result.type);
- if(this.action_callback[parse_result.type]){
- console.log('found product callback');
- this.action_callback[parse_result.type](parse_result);
- }
- }
- },
-
// starts catching keyboard events and tries to interpret codebar
// calling the callbacks when needed.
connect: function(){
this.session = session;
this.categories = {};
this.barcode_reader = new module.BarcodeReader({'pos': this});
+ window.barcode_reader = this.barcode_reader;
this.proxy = new module.ProxyDevice({'pos': this});
this.set({
'nbr_pending_operations': 0,
quantity: (this.get('quantity')) + weight,
});
},
+ set_discount: function(discount){
+ this.set({'discount': discount});
+ },
getPriceWithoutTax: function() {
return this.getAllPrices().priceWithoutTax;
},
});
this.pos = attributes.pos; //TODO put that in set and remember to use 'get' to read it ...
this.bind('change:validated', this.validatedChanged);
+ this.last_orderline = undefined;
return this;
},
events: {
generateUniqueId: function() {
return new Date().getTime();
},
+
addProduct: function(product) {
var existing;
existing = (this.get('orderLines')).get(product.id);
if (existing != null) {
+ this.last_orderline = existing;
if(existing.get('weighted')){
existing.incrementWeight(product.attributes.weight);
}else{
var attr = product.toJSON();
attr.pos = this.pos;
var line = new module.Orderline(attr);
+ this.last_orderline = line;
this.get('orderLines').add(line);
line.bind('killme', function() {
this.get('orderLines').remove(line);
var bufferContent, params;
bufferContent = this.get('buffer');
if (bufferContent && !isNaN(bufferContent)) {
- this.trigger('setValue', parseFloat(bufferContent));
+ this.trigger('set_value', parseFloat(bufferContent));
}
},
});
var self = this;
this.$element.find('.button').off('click').click(function(){
- self.pos.screen_selector.close_popup();
+ self.pos_widget.screen_selector.close_popup();
self.pos.proxy.help_canceled();
});
},
var self = this;
this.$element.find('.receipt').off('click').click(function(){
console.log('receipt!'); //TODO
- self.pos.screen_selector.set_current_screen('scan');
+ self.pos_widget.screen_selector.set_current_screen('scan');
});
this.$element.find('.invoice').off('click').click(function(){
console.log('invoice!'); //TODO
- self.pos.screen_selector.set_current_screen('scan');
+ self.pos_widget.screen_selector.set_current_screen('scan');
});
},
});
'cashier': function(ean){
clearInterval(this.intervalID);
self.pos.proxy.cashier_mode_activated();
- self.pos.screen_selector.set_user_mode('cashier');
+ self.pos_widget.screen_selector.set_user_mode('cashier');
},
});
},
this.pos_widget.set_leftpane_visible(true);
this.pos_widget.set_cashier_controls_visible(false);
this.pos_widget.action_bar.set_total_visible(true);
- this.pos_widget.action_bar.set_help_visible(true,function(){self.pos.screen_selector.show_popup('help');});
+ this.pos_widget.action_bar.set_help_visible(true,function(){self.pos_widget.screen_selector.show_popup('help');});
this.pos_widget.action_bar.set_logout_visible(false);
self.pos.proxy.weighting_start();
var weight = self.pos.proxy.weighting_read_kg();
if(weight > 0.001){
clearInterval(this.intervalID);
- self.pos.screen_selector.set_current_screen('scale_product');
+ self.pos_widget.screen_selector.set_current_screen('scale_product');
}
},500);
click: function(){
clearInterval(this.intervalID);
self.pos.proxy.weighting_end();
- self.pos.screen_selector.set_current_screen('scan');
+ self.pos_widget.screen_selector.set_current_screen('scan');
}
}
);
this.pos.barcode_reader.set_action_callbacks({
'cashier': function(ean){
self.pos.proxy.cashier_mode_activated();
- self.pos.screen_selector.set_user_mode('cashier');
+ self.pos_widget.screen_selector.set_user_mode('cashier');
},
'product': function(ean){
if(self.pos_widget.scan_product(ean)){
self.pos.proxy.scan_item_success();
- self.pos.screen_selector.set_current_screen('scan');
+ self.pos_widget.screen_selector.set_current_screen('scan');
}else{
- self.pos.screen_selector.show_popup('error');
+ self.pos_widget.screen_selector.show_popup('error');
}
},
});
this.product_list_widget = new module.ProductListWidget(null,{
pos:this.pos,
+ pos_widget:this.pos_widget,
weight: this.pos.proxy.weighting_read_kg(),
});
this.product_list_widget.replace($('.placeholder-ProductListWidget'));
show: function(){
this._super();
var self = this;
- if(this.pos.screen_selector.get_user_mode() === 'client'){
+ if(this.pos_widget.screen_selector.get_user_mode() === 'client'){
this.pos_widget.set_numpad_visible(false);
this.pos_widget.set_leftpane_visible(true);
this.pos_widget.set_cashier_controls_visible(false);
this.pos_widget.action_bar.set_total_visible(true);
- this.pos_widget.action_bar.set_help_visible(true,function(){self.pos.screen_selector.show_popup('help');});
+ this.pos_widget.action_bar.set_help_visible(true,function(){self.pos_widget.screen_selector.show_popup('help');});
this.pos_widget.action_bar.set_logout_visible(false);
+ this.pos_widget.onscreen_keyboard.connect();
- this.pos_widget.orderView.setNumpadState(this.pos_widget.numpadView.state);
+ this.product_categories_widget.reset_category();
+
+ this.pos_widget.order_widget.set_numpad_state(this.pos_widget.numpad.state);
this.pos_widget.action_bar.add_new_button(
{
label: 'back',
icon: '/point_of_sale/static/src/img/icons/png48/go-previous.png',
click: function(){
- self.pos.screen_selector.set_current_screen('scan');
+ self.pos_widget.screen_selector.set_current_screen('scan');
}
}
);
this.pos.barcode_reader.set_action_callbacks({
'cashier': function(ean){
self.pos.proxy.cashier_mode_activated();
- self.pos.screen_selector.set_user_mode('cashier');
+ self.pos_widget.screen_selector.set_user_mode('cashier');
},
'product': function(ean){
if(self.pos_widget.scan_product(ean)){
self.pos.proxy.scan_item_success();
- self.pos.screen_selector.set_current_screen('scan');
+ self.pos_widget.screen_selector.set_current_screen('scan');
}else{
- self.pos.screen_selector.show_popup('error');
+ self.pos_widget.screen_selector.show_popup('error');
}
},
});
this.pos_widget.set_cashier_controls_visible(true);
this.pos_widget.action_bar.set_total_visible(true);
this.pos_widget.action_bar.set_help_visible(false);
+ this.pos_widget.onscreen_keyboard.connect();
- this.pos_widget.orderView.setNumpadState(this.pos_widget.numpadView.state);
+ this.pos_widget.order_widget.set_numpad_state(this.pos_widget.numpad.state);
this.pos_widget.action_bar.add_new_button(
{
label: 'back',
icon: '/point_of_sale/static/src/img/icons/png48/go-previous.png',
click: function(){
- self.pos.screen_selector.set_current_screen('products');
+ self.pos_widget.screen_selector.set_current_screen('products');
}
}
);
},
hide: function(){
this._super();
- this.pos_widget.orderView.setNumpadState(null);
- this.pos_widget.payment_screen.setNumpadState(null);
+ this.pos_widget.order_widget.set_numpad_state(null);
+ this.pos_widget.payment_screen.set_numpad_state(null);
clearInterval(this.intervalID);
this.pos.proxy.weighting_end();
},
this.pos_widget.set_leftpane_visible(true);
this.pos_widget.set_cashier_controls_visible(false);
this.pos_widget.action_bar.set_total_visible(true);
- this.pos_widget.action_bar.set_help_visible(true,function(){self.pos.screen_selector.show_popup('help');});
+ this.pos_widget.action_bar.set_help_visible(true,function(){self.pos_widget.screen_selector.show_popup('help');});
this.pos_widget.action_bar.set_logout_visible(false);
this.pos.proxy.payment_request(this.pos.get('selectedOrder').getTotal(),'card','info'); //TODO TOTAL
self.pos.push_order(currentOrder.exportAsJSON()).then(function() {
currentOrder.destroy();
self.pos.proxy.transaction_end();
- self.pos.screen_selector.set_current_screen('welcome');
+ self.pos_widget.screen_selector.set_current_screen('welcome');
});
}else if(payment === 'payment_rejected'){
clearInterval(this.intervalID);
click: function(){ //TODO Go to ask for weighting screen
clearInterval(this.intervalID);
self.pos.proxy.payment_canceled();
- self.pos.screen_selector.set_current_screen('scan');
+ self.pos_widget.screen_selector.set_current_screen('scan');
}
}
);
'cashier': function(ean){
clearInterval(this.intervalID);
self.pos.proxy.cashier_mode_activated();
- self.pos.screen_selector.set_user_mode('cashier');
+ self.pos_widget.screen_selector.set_user_mode('cashier');
},
});
},
this.pos_widget.set_leftpane_visible(false);
this.pos_widget.set_cashier_controls_visible(false);
this.pos_widget.action_bar.set_total_visible(false);
- this.pos_widget.action_bar.set_help_visible(true,function(){self.pos.screen_selector.show_popup('help');});
+ this.pos_widget.action_bar.set_help_visible(true,function(){self.pos_widget.screen_selector.show_popup('help');});
this.pos_widget.action_bar.set_logout_visible(false);
this.pos_widget.action_bar.add_new_button(
{
label:'scan',
click: function(){
- self.pos.screen_selector.set_current_screen('scan');
+ self.pos_widget.screen_selector.set_current_screen('scan');
}
},{
label: 'weight',
icon: '/point_of_sale/static/src/img/icons/png48/scale.png',
- click: function(){ //TODO Go to ask for weighting screen
- self.pos.screen_selector.set_current_screen('scale_invite');
+ click: function(){
+ self.pos_widget.screen_selector.set_current_screen('scale_invite');
}
}
);
self.pos.proxy.transaction_start();
if(self.pos_widget.scan_product(ean)){
self.pos.proxy.scan_item_success();
- self.pos.screen_selector.set_current_screen('scan');
+ self.pos_widget.screen_selector.set_current_screen('scan');
}else{
- self.pos.screen_selector.show_popup('error');
+ self.pos_widget.screen_selector.show_popup('error');
}
},
'cashier': function(ean){
- //TODO 'switch to cashier mode'
self.pos.proxy.cashier_mode_activated();
- self.pos.screen_selector.set_user_mode('cashier');
+ self.pos_widget.screen_selector.set_user_mode('cashier');
},
'client': function(ean){
self.pos.proxy.transaction_start();
//TODO 'log the client'
- self.pos.screen_selector.show_popup('receipt');
+ self.pos_widget.screen_selector.show_popup('receipt');
},
'discount': function(ean){
- // TODO : what to do in this case ????
+ var currentOrder = self.pos.get('selectedOrder');
+ var last_orderline = currentOrder.last_orderline;
+ if(last_orderline){
+ last_orderline.set_discount(ean.value)
+ }
},
});
},
this.pos_widget.set_leftpane_visible(true);
this.pos_widget.set_cashier_controls_visible(false);
this.pos_widget.action_bar.set_total_visible(true);
- this.pos_widget.action_bar.set_help_visible(true,function(){self.pos.screen_selector.show_popup('help');});
+ this.pos_widget.action_bar.set_help_visible(true,function(){self.pos_widget.screen_selector.show_popup('help');});
this.pos_widget.action_bar.set_logout_visible(false);
this.pos_widget.action_bar.add_new_button(
label: 'weight',
icon: '/point_of_sale/static/src/img/icons/png48/scale.png',
click: function(){ //TODO Go to ask for weighting screen
- self.pos.screen_selector.set_current_screen('scale_invite');
+ self.pos_widget.screen_selector.set_current_screen('scale_invite');
}
},{
label: 'pay',
icon: '/point_of_sale/static/src/img/icons/png48/go-next.png',
click: function(){
- self.pos.screen_selector.set_current_screen('client_payment'); //TODO what stuff ?
+ self.pos_widget.screen_selector.set_current_screen('client_payment'); //TODO what stuff ?
}
}
);
if(self.pos_widget.scan_product(ean)){
self.pos.proxy.scan_item_success();
}else{
- self.pos.screen_selector.show_popup('error');
+ self.pos_widget.screen_selector.show_popup('error');
}
},
'cashier': function(ean){
self.pos.proxy.cashier_mode_activated();
- self.pos.screen_selector.set_user_mode('cashier');
+ self.pos_widget.screen_selector.set_user_mode('cashier');
},
'discount': function(ean){
- // TODO : handle the discount
+ var currentOrder = self.pos.get('selectedOrder');
+ var last_orderline = currentOrder.last_orderline;
+ if(last_orderline){
+ last_orderline.set_discount(ean.value)
+ }
},
});
},
this.product_list_widget = new module.ProductListWidget(null,{
pos:this.pos,
+ pos_widget:this.pos_widget,
});
this.product_list_widget.replace($('.placeholder-ProductListWidget'));
},
this.pos_widget.action_bar.set_total_visible(true);
this.pos_widget.action_bar.set_help_visible(false);
this.pos_widget.action_bar.set_logout_visible(true, function(){
- self.pos.screen_selector.set_user_mode('client');
+ self.pos_widget.screen_selector.set_user_mode('client');
});
+ this.product_categories_widget.reset_category();
+ this.pos_widget.onscreen_keyboard.connect();
- this.pos_widget.orderView.setNumpadState(this.pos_widget.numpadView.state);
+ this.pos_widget.order_widget.set_numpad_state(this.pos_widget.numpad.state);
this.pos_widget.action_bar.add_new_button(
{
label: 'weight',
icon: '/point_of_sale/static/src/img/icons/png48/scale.png',
click: function(){
- self.pos.screen_selector.set_current_screen('scale_product');
+ self.pos_widget.screen_selector.set_current_screen('scale_product');
}
}
);
if(self.pos_widget.scan_product(ean)){
self.pos.proxy.scan_item_success();
}else{
- self.pos.screen_selector.show_popup('error');
+ self.pos_widget.screen_selector.show_popup('error');
}
},
'cashier': function(ean){
self.pos.proxy.cashier_mode_activated();
- self.pos.screen_selector.set_user_mode('cashier');
+ self.pos_widget.screen_selector.set_user_mode('cashier');
},
'discount': function(ean){
- // TODO : handle the discount
+ var currentOrder = self.pos.get('selectedOrder');
+ var last_orderline = currentOrder.last_orderline;
+ if(last_orderline){
+ last_orderline.set_discount(ean.value)
+ }
},
});
},
hide: function(){
this._super();
- this.pos_widget.orderView.setNumpadState(null);
- this.pos_widget.payment_screen.setNumpadState(null);
+ this.pos_widget.order_widget.set_numpad_state(null);
+ this.pos_widget.payment_screen.set_numpad_state(null);
},
});
this.shop_obj = this.pos.get('shop');
},
start: function() {
- this.pos.bind('change:selectedOrder', this.changeSelectedOrder, this);
- this.changeSelectedOrder();
+ this.pos.bind('change:selectedOrder', this.change_selected_order, this);
+ this.change_selected_order();
$('button#pos-finish-order', this.$element).click(_.bind(this.finishOrder, this));
$('button#print-the-ticket', this.$element).click(_.bind(this.print, this));
},
this.pos_widget.action_bar.set_total_visible(true);
this.pos_widget.action_bar.set_help_visible(false);
this.pos_widget.action_bar.set_logout_visible(true, function(){
- self.pos.screen_selector.set_user_mode('client');
+ self.pos_widget.screen_selector.set_user_mode('client');
});
},
print: function() {
finishOrder: function() {
this.pos.get('selectedOrder').destroy();
},
- changeSelectedOrder: function() {
+ change_selected_order: function() {
if (this.currentOrderLines)
this.currentOrderLines.unbind();
this.currentOrderLines = (this.pos.get('selectedOrder')).get('orderLines');
init: function(parent, options) {
this._super(parent,options);
this.model = options.model;
- this.pos.bind('change:selectedOrder', this.changeSelectedOrder, this);
+ this.pos.bind('change:selectedOrder', this.change_selected_order, this);
this.bindPaymentLineEvents();
- this.bindOrderLineEvents();
+ this.bind_orderline_events();
},
show: function(){
this._super();
this.pos_widget.action_bar.set_total_visible(true);
this.pos_widget.action_bar.set_help_visible(false);
this.pos_widget.action_bar.set_logout_visible(true, function(){
- self.pos.screen_selector.set_user_mode('client');
+ self.pos_widget.screen_selector.set_user_mode('client');
});
- this.setNumpadState(this.pos_widget.numpadView.state);
+ this.set_numpad_state(this.pos_widget.numpad.state);
},
hide: function(){
this._super();
- this.pos_widget.orderView.setNumpadState(null);
- this.pos_widget.payment_screen.setNumpadState(null);
+ this.pos_widget.order_widget.set_numpad_state(null);
+ this.pos_widget.payment_screen.set_numpad_state(null);
},
paymentLineList: function() {
return this.$element.find('#paymentlines');
},
back: function() {
- this.pos.screen_selector.set_current_screen('products');
+ this.pos_widget.screen_selector.set_current_screen('products');
},
validateCurrentOrder: function() {
var callback, currentOrder;
this.currentPaymentLines.bind('remove', this.renderElement, this);
this.currentPaymentLines.bind('all', this.updatePaymentSummary, this);
},
- bindOrderLineEvents: function() {
+ bind_orderline_events: function() {
this.currentOrderLines = (this.pos.get('selectedOrder')).get('orderLines');
this.currentOrderLines.bind('all', this.updatePaymentSummary, this);
},
- changeSelectedOrder: function() {
+ change_selected_order: function() {
this.currentPaymentLines.unbind();
this.bindPaymentLineEvents();
this.currentOrderLines.unbind();
- this.bindOrderLineEvents();
+ this.bind_orderline_events();
this.renderElement();
},
addPaymentLine: function(newPaymentLine) {
remaining = remainingAmount > 0 ? 0 : (-remainingAmount).toFixed(2);
$('#payment-remaining').html(remaining);
},
- setNumpadState: function(numpadState) {
+ set_numpad_state: function(numpadState) {
if (this.numpadState) {
- this.numpadState.unbind('setValue', this.setValue);
+ this.numpadState.unbind('set_value', this.set_value);
this.numpadState.unbind('change:mode', this.setNumpadMode);
}
this.numpadState = numpadState;
if (this.numpadState) {
- this.numpadState.bind('setValue', this.setValue, this);
+ this.numpadState.bind('set_value', this.set_value, this);
this.numpadState.bind('change:mode', this.setNumpadMode, this);
this.numpadState.reset();
this.setNumpadMode();
setNumpadMode: function() {
this.numpadState.set({mode: 'payment'});
},
- setValue: function(val) {
+ set_value: function(val) {
this.currentPaymentLines.last().set({amount: val});
},
});
};
};
- module.NumpadWidget = instance.web.OldWidget.extend({
+ // This is a base class for all Widgets in the POS. It exposes relevant data to the
+ // templates :
+ // - widget.currency : { symbol: '$' | '€' | ..., position: 'before' | 'after }
+ // - widget.format_currency(amount) : this method returns a formatted string based on the
+ // symbol, the position, and the amount of money.
+ // if the PoS is not fully loaded when you instanciate the widget, the currency might not
+ // yet have been initialized. Use __build_currency_template() to recompute with correct values
+ // before rendering.
+
+ module.PosBaseWidget = instance.web.Widget.extend({
+ init:function(parent,options){
+ this._super(parent);
+ options = options || {};
+ this.pos = options.pos;
+ this.build_currency_template();
+ },
+ build_currency_template: function(){
+
+ if(this.pos && this.pos.get('currency')){
+ this.currency = this.pos.get('currency');
+ }else{
+ this.currency = {symbol: '$', position: 'after'};
+ }
+
+ this.format_currency = function(amount){
+ if(this.currency.position === 'after'){
+ return Math.round(amount*100)/100 + ' ' + this.currency.symbol;
+ }else{
+ return this.currency.symbol + ' ' + Math.round(amount*100)/100;
+ }
+ }
+
+ },
+ });
+
+ module.NumpadWidget = instance.web.Widget.extend({
+ template:'NumpadWidget',
init: function(parent, options) {
this._super(parent);
this.state = new module.NumpadState();
/*
Gives access to the payment methods (aka. 'cash registers')
*/
- module.PaypadWidget = instance.web.OldWidget.extend({
+ module.PaypadWidget = instance.web.Widget.extend({
+ template: 'PaypadWidget',
init: function(parent, options) {
this._super(parent);
this.pos = options.pos;
+ this.pos_widget = options.pos_widget;
},
start: function() {
this.$element.find('button').click(_.bind(this.performPayment, this));
return;
var accountJournal, accountJournalCollection, accountJournalId;
/* set correct view */
- this.pos.screen_selector.set_current_screen('payment');
+ this.pos_widget.screen_selector.set_current_screen('payment');
accountJournalId = event.currentTarget.attributes['account-journal-id'].nodeValue;
accountRegisterCollection = this.pos.get('accountJournals');
renderElement: function() {
this.$element.empty();
return (this.pos.get('accountJournals')).each(_.bind(function(accountJournal) {
- var button = new module.PaymentButtonWidget();
+ var button = new module.PaymentButtonWidget(this,{
+ pos:this.pos,
+ });
button.model = accountJournal;
button.appendTo(this.$element);
}, this));
}
});
- module.PaymentButtonWidget = instance.web.OldWidget.extend({
- template_fct: qweb_template('pos-payment-button-template'),
+ module.PaymentButtonWidget = module.PosBaseWidget.extend({
+ template: 'PaymentButtonWidget',
renderElement: function() {
- this.$element.html(this.template_fct({
- id: this.model.get('id'),
- name: this.model.get('name')
- }));
- return this;
- }
+ this.id = this.model.get('id');
+ this.name = this.model.get('name');
+ this._super();
+ },
});
// ---------- "Shopping Carts" ----------
- module.OrderlineWidget = instance.web.OldWidget.extend({
- tagName: 'tr',
- template_fct: qweb_template('pos-orderline-template'),
+ module.OrderlineWidget = module.PosBaseWidget.extend({
+ template: 'OrderlineWidget',
init: function(parent, options) {
- this._super(parent);
+ this._super(parent,options);
this.model = options.model;
this.model.bind('change', _.bind( function() {
this.refresh();
this.select();
},
renderElement: function() {
- this.$element.html(this.template_fct(this.model.toJSON()));
+ this._super();
this.select();
},
refresh: function() {
on_selected: function() {},
});
- module.OrderWidget = instance.web.OldWidget.extend({
+ module.OrderWidget = module.PosBaseWidget.extend({
+ template:'OrderWidget',
init: function(parent, options) {
- this._super(parent);
- this.pos = options.pos;
+ this._super(parent,options);
this.pos_widget = options.pos_widget;
- this.setNumpadState(options.numpadState);
- this.pos.bind('change:selectedOrder', this.changeSelectedOrder, this);
- this.bindOrderLineEvents();
+ console.log('OrderWidget init:',options)
+ this.set_numpad_state(options.numpadState);
+ this.pos.bind('change:selectedOrder', this.change_selected_order, this);
+ this.bind_orderline_events();
},
- setNumpadState: function(numpadState) {
+ set_numpad_state: function(numpadState) {
if (this.numpadState) {
- this.numpadState.unbind('setValue', this.setValue);
+ this.numpadState.unbind('set_value', this.set_value);
}
this.numpadState = numpadState;
if (this.numpadState) {
- this.numpadState.bind('setValue', this.setValue, this);
+ this.numpadState.bind('set_value', this.set_value, this);
this.numpadState.reset();
}
},
- setValue: function(val) {
+ set_value: function(val) {
var param = {};
param[this.numpadState.get('mode')] = val;
var order = this.pos.get('selectedOrder');
this.pos.get('selectedOrder').destroy();
}
},
- changeSelectedOrder: function() {
+ change_selected_order: function() {
this.currentOrderLines.unbind();
- this.bindOrderLineEvents();
+ this.bind_orderline_events();
this.renderElement();
},
- bindOrderLineEvents: function() {
+ bind_orderline_events: function() {
this.currentOrderLines = (this.pos.get('selectedOrder')).get('orderLines');
- this.currentOrderLines.bind('add', this.addLine, this);
+ this.currentOrderLines.bind('add', this.add_line, this);
this.currentOrderLines.bind('remove', this.renderElement, this);
},
- addLine: function(newLine) {
+ add_line: function(newLine) {
var line = new module.OrderlineWidget(null, {
model: newLine,
+ pos: this.pos,
order: this.pos.get('selectedOrder')
});
- line.on_selected.add(_.bind(this.selectedLine, this));
- this.selectedLine();
- line.appendTo(this.$element);
- this.updateSummary();
+ line.on_selected.add(_.bind(this.selected_line, this));
+ this.selected_line();
+ line.appendTo(this.$element.find('#current-order-content'));
+ this.update_summary();
},
- selectedLine: function() {
+ selected_line: function() {
var reset = false;
if (this.currentSelected !== this.pos.get('selectedOrder').selected) {
reset = true;
this.currentSelected = this.pos.get('selectedOrder').selected;
if (reset && this.numpadState)
this.numpadState.reset();
- this.updateSummary();
+ this.update_summary();
},
renderElement: function() {
- this.$element.empty();
+ this._super();
+ var $content = this.$element.find('#current-order-content');
+ $content.empty();
this.currentOrderLines.each(_.bind( function(orderLine) {
var line = new module.OrderlineWidget(null, {
model: orderLine,
order: this.pos.get('selectedOrder')
});
- line.on_selected.add(_.bind(this.selectedLine, this));
- line.appendTo(this.$element);
+ line.on_selected.add(_.bind(this.selected_line, this));
+ line.appendTo($content);
}, this));
- this.updateSummary();
+ this.update_summary();
},
- updateSummary: function() {
+ update_summary: function() {
var currentOrder, tax, total, totalTaxExcluded;
currentOrder = this.pos.get('selectedOrder');
total = currentOrder.getTotal();
// ---------- Product Screen ----------
- module.ProductWidget = instance.web.Widget.extend({
- tagName:'li',
- template_fct: qweb_template('ProductWidget'),
+ module.ProductWidget = module.PosBaseWidget.extend({
+ template: 'ProductWidget',
init: function(parent, options) {
- this._super(parent);
+ this._super(parent,options);
this.model = options.model;
- this.pos = options.pos;
+ this.pos_widget = options.pos_widget; //FIXME ...
this.model.attributes.weight = options.weight || undefined;
this.next_screen = options.next_screen || undefined;
},
this.next_screen = screen;
},
renderElement: function() {
+ this._super();
var self = this;
- this.$element.addClass("product");
- this.$element.html(this.template_fct(this.model.toJSON()));
$("a", this.$element).click(function(e){
self.addToOrder(e);
if(self.next_screen){
- self.pos.screen_selector.set_current_screen(self.next_screen); //FIXME There ought to be a better way to do this ...
+ self.pos_widget.screen_selector.set_current_screen(self.next_screen); //FIXME There ought to be a better way to do this ...
}
});
},
init: function(parent, options) {
this._super(parent);
this.model = options.model;
+ console.log('PaymentlineWidget.model:',this.model);
this.model.bind('change', this.changedAmount, this);
},
on_delete: function() {},
},
start: function() {
this.search_and_categories();
- this.$element.find(".oe-pos-categories-list a").click(_.bind(this.changeCategory, this));
},
template_fct: qweb_template('ProductCategoriesWidget'),
template:'ProductCategoriesWidget',
return _results;
})()
}));
+ this.$element.find(".oe-pos-categories-list a").click(_.bind(this.change_category, this));
+ },
+ reset_category: function(){
+ this.on_change_category(0);
},
- changeCategory: function(a) {
+ change_category: function(a) {
var id = $(a.target).data("category-id");
this.on_change_category(id);
},
this.model = options.model;
this.pos = options.pos;
this.pos.get('products').bind('reset', this.renderElement, this);
+ this.pos_widget = options.pos_widget,
this.product_list = [];
this.weight = options.weight;
this.next_screen = options.next_screen || false;
model: product,
pos: self.pos,
weight: self.weight,
+ pos_widget: self.pos_widget, //FIXME ARGH
})
self.product_list.push(product);
return product;
},
});
-
-
-// ---------- PopUp Widgets ----------
-
- module.PopUp = instance.web.Widget.extend({
- close: function(){},
- });
-
- module.HelpPopUp = module.PopUp.extend({
- });
-
- module.ErrorPopUp = module.PopUp.extend({
- });
-
- module.TicketOrInvoicePopUp = module.PopUp.extend({
- });
-
// ---------- OnScreen Keyboard Widget ----------
// A Widget that displays an onscreen keyboard.
this.numlock = false;
},
+ connect : function(){
+ $(this.input_selector).focus(function(){self.show();});
+ },
+
// Write a character to the input zone
writeCharacter: function(character){
var $input = $(this.input_selector);
// ---------- Main Point of Sale Widget ----------
+ // this is used to notify the user that data is being synchronized on the network
module.SynchNotification = instance.web.OldWidget.extend({
template: "pos-synch-notification",
init: function() {
on_synch: function() {}
});
- module.PosWidget = instance.web.OldWidget.extend({
+ // The PosWidget is the main widget that contains all other widgets in the PointOfSale.
+ // It is mainly composed of :
+ // - a header, containing the list of orders
+ // - a leftpane, containing the list of bought products (orderlines)
+ // - a rightpane, containing the screens (see pos_screens.js)
+ // - an actionbar on the bottom, containing various action buttons
+ // - popups
+ // - an onscreen keyboard
+ // a screen_selector which controls the switching between screens and the showing/closing of popups
+
+ module.PosWidget = module.PosBaseWidget.extend({
+ template: 'PosWidget',
init: function() {
- this._super.apply(this, arguments);
+ console.log('PosArguments:',arguments);
+ this._super(arguments[0],{});
this.pos = new module.PosModel(this.session);
this.numpad_visible = true;
this.leftpane_visible = true;
this.leftpane_width = '440px';
this.cashier_controls_visible = true;
},
+
start: function() {
var self = this;
return self.pos.ready.then(_.bind(function() {
+ this.build_currency_template();
this.renderElement();
this.synch_notification = new module.SynchNotification(this);
this.synch_notification.replace($('.oe_pos_synch-notification', this.$element));
this.$element.find("#loggedas button").click(function() {
self.try_close();
});
+
+ $('button#neworder-button', this.$element).click(_.bind(this.create_new_order, this));
+
+ //when a new order is created, add an order button widget
+ (this.pos.get('orders')).bind('add', function(new_order){
+ var new_order_button = new module.OrderButtonWidget(null, {
+ order: new_order,
+ pos: this.pos
+ });
+ new_order_button.appendTo($('#orders'));
+ new_order_button.selectOrder();
+ }, this);
+
+ (this.pos.get('orders')).add(new module.Order({'pos':this.pos}));
- this.buildWidgets();
+ this.build_widgets();
instance.webclient.set_content_full_screen(true);
}, this));
},
- render: function() {
- return qweb_template("POSWidget")();
- },
- buildWidgets: function() {
- $('button#neworder-button', this.$element).click(_.bind(this.createNewOrder, this));
- (this.pos.get('orders')).bind('add', this.orderAdded, this);
- (this.pos.get('orders')).add(new module.Order({'pos':this.pos}));
-
+ build_widgets: function() {
this.search_product_screen = new module.SearchProductScreenWidget(this,{
pos: this.pos,
});
this.error_popup.appendTo($('.point-of-sale'));
- this.paypadView = new module.PaypadWidget(null, {
- pos: this.pos
+ this.action_bar = new module.ActionBarWidget(this);
+ this.action_bar.appendTo($(".point-of-sale #content"));
+
+ this.paypad = new module.PaypadWidget(this, {
+ pos: this.pos,
+ pos_widget: this,
});
- this.paypadView.$element = $('#paypad');
- this.paypadView.renderElement();
- this.paypadView.start();
- this.numpadView = new module.NumpadWidget(null);
- this.numpadView.$element = $('#numpad');
- this.numpadView.start();
- this.orderView = new module.OrderWidget(null, {
+ this.paypad.replace($('placeholder-PaypadWidget'));
+
+ this.numpad = new module.NumpadWidget(this);
+ this.numpad.replace($('#placeholder-NumpadWidget'));
+
+ this.order_widget = new module.OrderWidget(this, {
pos: this.pos,
pos_widget: this,
});
- this.orderView.$element = $('#current-order-content');
- this.orderView.start();
+ this.order_widget.replace($('#placeholder-OrderWidget'));
- this.action_bar = new module.ActionBarWidget(null);
- this.action_bar.appendTo($(".point-of-sale #content"));
+ //this.orderView.$element = $('#current-order-content');
+ //this.orderView.start();
- this.onscreen_keyboard = new module.OnscreenKeyboardWidget(null, {
+ this.onscreen_keyboard = new module.OnscreenKeyboardWidget(this, {
'keyboard_model': 'simple'
});
this.onscreen_keyboard.appendTo($(".point-of-sale #content"));
- this.pos.screen_selector = new module.ScreenSelector({
+ this.screen_selector = new module.ScreenSelector({
pos: this.pos,
screen_set:{
'products': this.search_product_screen,
default_cashier_screen: 'products',
default_mode: 'client',
});
- window.screen_selector = this.pos.screen_selector;
+ window.screen_selector = this.screen_selector;
this.pos.barcode_reader.connect();
var scannedProductModel = undefined;
if (parsed_ean.type === 'price') {
- var itemCode = parse_result.id;
- var scannedPackaging = _.detect(allPackages, function(pack) { return pack.ean !== undefined && pack.ean.substring(0,7) === itemCode;});
- if (scannedPackaging !== undefined) {
+ var itemCode = parsed_ean.id;
+ console.log('price! id:',itemCode);
+ var scannedPackaging = _.detect(allPackages, function(pack) {
+ return pack.ean && pack.ean.substring(0,7) === itemCode;
+ });
+ if (scannedPackaging) {
+ console.log('found matching package, finding matching product...');
scannedProductModel = _.detect(allProducts, function(pc) { return pc.id === scannedPackaging.product_id[0];});
+ }else{
+ console.log('matching package not found, finding matching product...');
+ scannedProductModel = _.detect(allProducts, function(pc) { return pc.ean13 && (pc.ean13.substring(0,7) === parsed_ean.id);});
+ }
+ if(scannedProductModel){
scannedProductModel.list_price = parsed_ean.value;
}
} else if (parsed_ean.type === 'weight') {
var weight = parsed_ean.value;
var itemCode = parsed_ean.id;
- var scannedPackaging = _.detect(allPackages, function(pack) { return pack.ean !== undefined && pack.ean.substring(0,7) === itemCode;});
- if (scannedPackaging !== undefined) {
+ var scannedPackaging = _.detect(allPackages, function(pack) {
+ return pack.ean && pack.ean.substring(0,7) === itemCode;
+ });
+ if (scannedPackaging){
+ console.log('found matching package, finding matching product...');
scannedProductModel = _.detect(allProducts, function(pc) { return pc.id === scannedPackaging.product_id[0];});
+ }else{
+ console.log('matching package not found, finding matching product...');
+ scannedProductModel = _.detect(allProducts, function(pc) { return pc.ean13 && (pc.ean13.substring(0,7) === parsed_ean.id);});
+ }
+ if(scannedProductModel){
scannedProductModel.list_price *= weight;
scannedProductModel.name += ' - ' + weight + ' Kg.';
}
}
return scannedProductModel;
},
- createNewOrder: function() {
- var newOrder;
- newOrder = new module.Order({'pos': this.pos});
- (this.pos.get('orders')).add(newOrder);
- this.pos.set({
- selectedOrder: newOrder
- });
- },
- orderAdded: function(newOrder) {
- var newOrderButton;
- newOrderButton = new module.OrderButtonWidget(null, {
- order: newOrder,
- pos: this.pos
- });
- newOrderButton.appendTo($('#orders'));
- newOrderButton.selectOrder();
+ // creates a new order, and add it to the list of orders.
+ create_new_order: function() {
+ var new_order;
+ new_order = new module.Order({'pos': this.pos});
+ this.pos.get('orders').add(new_order);
+ this.pos.set({ selectedOrder: new_order });
},
changed_pending_operations: function () {
var self = this;
this.synch_notification.on_change_nbr_pending(self.pos.get('nbr_pending_operations').length);
},
+ // shows or hide the numpad and related controls like the paypad.
set_numpad_visible: function(visible){
if(visible != this.numpad_visible){
this.numpad_visible = visible;
}
}
},
+ //shows or hide the leftpane (contains the list of orderlines, the numpad, the paypad, etc.)
set_leftpane_visible: function(visible){
if(visible != this.leftpane_visible){
this.leftpane_visible = visible;
}
}
},
+ //shows or hide the controls in the PosWidget that are specific to the cashier ( Orders, close button, etc. )
set_cashier_controls_visible: function(visible){
if(visible != this.cashier_controls_visible){
this.cashier_controls_visible = visible;
<!-- vim:fdl=1:
-->
<templates id="template" xml:space="preserve">
- <t t-name="POSWidget">
+ <t t-name="PosWidget">
<div class="point-of-sale">
<div id="topheader">
<div id="branding">
<div id="content">
<div id="leftpane">
- <div id="current-order">
- <table>
- <thead>
- <tr>
- <td>Product</td>
- <td>Price</td>
- <td>Disc (%)</td>
- <td>Qty</td>
- <td>Total</td>
- </tr>
- </thead>
- <tbody id="current-order-content"></tbody>
- </table>
- </div>
+ <div id="placeholder-OrderWidget"></div>
<footer>
+
<ul id="amounts">
<li>
Subtotal:
- <t t-if="currency.position == 'before'" t-esc="currency.symbol"/> <span id="subtotal">0</span> <t t-if="currency.position == 'after'" t-esc="currency.symbol"/>
+ <t t-if="widget.currency.position === 'before'" t-esc="widget.currency.symbol"/>
+ <span id="subtotal">0</span>
+ <t t-if="widget.currency.position === 'after'" t-esc="widget.currency.symbol"/>
</li>
+
<li>
Tax:
- <t t-if="currency.position == 'before'" t-esc="currency.symbol"/> <span id="tax">0</span> <t t-if="currency.position == 'after'" t-esc="currency.symbol"/>
+ <t t-if="widget.currency.position === 'before'" t-esc="widget.currency.symbol"/>
+ <span id="tax">0</span>
+ <t t-if="widget.currency.position === 'after'" t-esc="widget.currency.symbol"/>
</li>
+
<li>
Total:
- <t t-if="currency.position == 'before'" t-esc="currency.symbol"/> <span id="total">0</span> <t t-if="currency.position == 'after'" t-esc="currency.symbol"/>
+ <t t-if="widget.currency.position === 'before'" t-esc="widget.currency.symbol"/>
+ <span id="total">0</span>
+ <t t-if="widget.currency.position === 'after'" t-esc="widget.currency.symbol"/>
</li>
</ul>
- <div id="paypad"></div>
- <div id="numpad">
- <button class="input-button number-char">1</button>
- <button class="input-button number-char">2</button>
- <button class="input-button number-char">3</button>
- <button class="mode-button" data-mode='quantity'>Qty</button>
- <br />
- <button class="input-button number-char">4</button>
- <button class="input-button number-char">5</button>
- <button class="input-button number-char">6</button>
- <button class="mode-button" data-mode='discount'>Disc</button>
- <br />
- <button class="input-button number-char">7</button>
- <button class="input-button number-char">8</button>
- <button class="input-button number-char">9</button>
- <button class="mode-button" data-mode='list_price'>Price</button>
- <br />
- <button class="input-button" id="numpad-minus" >+/-</button>
- <button class="input-button number-char">0</button>
- <button class="input-button number-char">.</button>
- <button class="input-button" id="numpad-backspace">
- <img src="/point_of_sale/static/src/img/backspace.png" width="24" height="21" />
- </button>
- <br />
- </div>
+
+ <div id="placeholder-PaypadWidget"></div>
+ <div id="placeholder-NumpadWidget"></div>
+
</footer>
</div>
<div id="rightpane">
- <!-- <div id="products-screen" class="step-screen selected-step">
- <div id="products-screen-categories"/>
- <ol id="products-screen-ol" class="product-list"></ol>
- </div> -->
- <!-- <div id="payment-screen" class="step-screen" style="display:none"> ... </div> -->
- <!-- <span id="receipt-screen"></span> -->
</div>
</div>
</div>
</t>
+ <t t-name="OrderWidget">
+ <div id="current-order">
+ <table>
+ <thead>
+ <tr>
+ <td>Product</td>
+ <td>Price</td>
+ <td>Disc (%)</td>
+ <td>Qty</td>
+ <td>Total</td>
+ </tr>
+ </thead>
+ <tbody id="current-order-content"></tbody>
+ </table>
+ </div>
+ </t>
<t t-name="pos-synch-notification">
<span>
<a t-if="widget.nbr_pending > 0" href="javascript:void(0)" class="oe_pos_synch-notification-button">
<t t-name="pos-close-warning">
<div>There are pending operations that could not be saved into the database, are you sure you want to exit?</div>
</t>
+ <t t-name="PaypadWidget">
+ <div id="paypad">
+ </div>
+ </t>
+ <t t-name="NumpadWidget">
+ <div id="numpad">
+ <button class="input-button number-char">1</button>
+ <button class="input-button number-char">2</button>
+ <button class="input-button number-char">3</button>
+ <button class="mode-button" data-mode='quantity'>Qty</button>
+ <br />
+ <button class="input-button number-char">4</button>
+ <button class="input-button number-char">5</button>
+ <button class="input-button number-char">6</button>
+ <button class="mode-button" data-mode='discount'>Disc</button>
+ <br />
+ <button class="input-button number-char">7</button>
+ <button class="input-button number-char">8</button>
+ <button class="input-button number-char">9</button>
+ <button class="mode-button" data-mode='list_price'>Price</button>
+ <br />
+ <button class="input-button" id="numpad-minus" >+/-</button>
+ <button class="input-button number-char">0</button>
+ <button class="input-button number-char">.</button>
+ <button class="input-button" id="numpad-backspace">
+ <img src="/point_of_sale/static/src/img/backspace.png" width="24" height="21" />
+ </button>
+ <br />
+ </div>
+ </t>
<!-- ************ SEARCH PRODUCT SCREEN ************ -->
<t t-name="ReceiptPopupWidget">
<div class="modal-dialog">
<div class="popup popup-help">
- <p class="message">Welcome Mr. FooBar <br /> Choose your type of receipt:</p>
+ <p class="message">Welcome Mr. John Smith <br /> Choose your type of receipt:</p>
<div class = "button big-left receipt">
Ticket
</div>
<t t-name="ErrorPopupWidget">
<div class="modal-dialog">
<div class="popup popup-help">
- <p class="message">An unexpected error has occured.<br /> A technician is on the way</p>
+ <p class="message">The scanned product was not recognized<br /> Please wait, a cashier is on the way</p>
</div>
</div>
</t>
<t t-name="ProductWidget">
- <a href="#">
- <div class="product-img">
-
- <img t-att-src="'data:image/gif;base64,'+ product_image_small" />
- <t t-if="!weight">
- <span class="price-tag">
- <t t-esc="format_amount(list_price)"/>
- </span>
+ <li class='product'>
+ <a href="#">
+ <div class="product-img">
+
+ <img t-att-src="'data:image/gif;base64,'+ widget.model.get('product_image_small')" />
+ <t t-if="!widget.model.get('weight')">
+ <span class="price-tag">
+ <t t-esc="widget.format_currency(widget.model.get('list_price'))"/>
+ </span>
+ </t>
+ <t t-if="widget.model.get('weight')">
+ <span class="price-tag">
+ <t t-esc="widget.format_currency(widget.model.get('list_price'))+'/Kg'"/>
+ </span>
+ <span class="price-subtag">
+ <t t-esc="widget.format_currency(widget.model.get('list_price') * widget.model.get('weight'))"/>
+ </span>
+ </t>
+ </div>
+ <div class="product-name">
+ <t t-esc="widget.model.get('name')"/>
+ </div>
+ </a>
+ </li>
+ </t>
+ <t t-name="OrderlineWidget">
+ <tr>
+ <td>
+ <t t-esc="name"/>
+ </td>
+ <td>
+ <t t-esc="widget.format_currency(widget.model.get('list_price'))"/>
+ </td>
+ <td>
+ <t t-js="c">
+ console.log(c);
</t>
- <t t-if="weight">
- <span class="price-tag">
- <t t-esc="format_amount(list_price)+'/Kg'"/>
- </span>
- <span class="price-subtag">
- <t t-esc="format_amount(list_price *weight)"/>
- </span>
+ <t t-esc="widget.model.get('discount').toFixed(2)"/>
+ </td>
+ <td>
+ <t t-if="widget.model.get('weighted')">
+ <t t-esc="Math.round(widget.model.get('quantity')*100)/100+' Kg'"/>
</t>
- </div>
- <div class="product-name">
- <t t-esc="name"/>
- </div>
- </a>
- </t>
- <t t-name="pos-orderline-template">
- <td>
- <t t-esc="name"/>
- </td>
- <td>
- <t t-esc="format_amount(list_price.toFixed(2))"/>
- </td>
- <td>
- <t t-esc="discount.toFixed(2)"/>
- </td>
- <td>
- <t t-if="weighted">
- <t t-esc="Math.round(quantity*100)/100+' Kg'"/>
- </t>
- <t t-if="!weighted">
- <t t-esc="Math.round(quantity*100)/100"/>
- </t>
- </td>
- <td>
- <t t-esc="format_amount((list_price * (1 - discount/100) * quantity).toFixed(2))"/>
- </td>
+ <t t-if="!widget.model.get('weighted')">
+ <t t-esc="Math.round(widget.model.get('quantity')*100)/100"/>
+ </t>
+ </td>
+ <td>
+ <t t-esc="widget.format_currency(widget.model.get('list_price') * (1 - widget.model.get('discount')/100) * widget.model.get('quantity'))"/>
+ </td>
+ </tr>
</t>
+
<t t-name="pos-paymentline-template">
<td class="paymentline-type">
<t t-esc="name"/>
<a href='javascript:void(0)' class='delete-payment-line'><img src="/point_of_sale/static/src/img/search_reset.gif" /></a>
</td>
</t>
- <t t-name="pos-payment-button-template">
- <button class="payment-button" t-att-account-journal-id="id">
- <t t-esc="name"/>
+
+ <t t-name="PaymentButtonWidget">
+ <button class="payment-button" t-att-account-journal-id="widget.id">
+ <t t-esc="widget.name"/>
</button>
<br />
</t>
+
<t t-name="pos-order-selector-button-template">
<button class="select-order"><t t-esc="widget.order.get('creationDate').toString('t')"/></button>
</t>