.point-of-sale .pos-right-align {
text-align: right;
}
+.point-of-sale .pos-center-align {
+ text-align: center;
+}
.point-of-sale .pos-right-align input {
text-align: right;
border: 1px solid #cecbcb;
}
@media print {
+ .point-of-sale{
+ background: white !important;
+ }
.point-of-sale #topheader, .point-of-sale #leftpane {
display: none !important;
}
.pos-actionbar {
display: none !important;
}
- .pos-sale-ticket {
- margin: 0;
- }
.debug-widget{
display: none !important;
}
background: transparent !important;
}
.point-of-sale .pos-sale-ticket{
+ margin: 0;
margin-left: auto !important;
margin-right: auto !important;
- border: solid 1px black !important;
+ border: none !important;
+ font-size: 13px !important;
+ width: 266px !important;
}
}
// what happens when a product is scanned :
// it will add the product to the order and go to barcode_product_screen. Or show barcode_product_error_popup if
// there's an error.
- barcode_product_action: function(ean){
+ barcode_product_action: function(code){
var self = this;
- if(self.pos.scan_product(ean)){
- self.pos.proxy.scan_item_success(ean);
+ if(self.pos.scan_product(code)){
+ self.pos.proxy.scan_item_success(code);
if(self.barcode_product_screen){
self.pos_widget.screen_selector.set_current_screen(self.barcode_product_screen);
}
}else{
- self.pos.proxy.scan_item_error_unrecognized(ean);
+ self.pos.proxy.scan_item_error_unrecognized(code);
if(self.barcode_product_error_popup && self.pos_widget.screen_selector.get_user_mode() !== 'cashier'){
self.pos_widget.screen_selector.show_popup(self.barcode_product_error_popup);
}
}
},
-
+
// what happens when a cashier id barcode is scanned.
// the default behavior is the following :
// - if there's a user with a matching ean, put it as the active 'cashier', go to cashier mode, and return true
// - else : do nothing and return false. You probably want to extend this to show and appropriate error popup...
- barcode_cashier_action: function(ean){
+ barcode_cashier_action: function(code){
var users = this.pos.get('user_list');
for(var i = 0, len = users.length; i < len; i++){
- if(users[i].ean13 === ean.ean){
+ if(users[i].ean13 === code.code){
this.pos.set('cashier',users[i]);
this.pos_widget.username.refresh();
this.pos.proxy.cashier_mode_activated();
return true;
}
}
- this.pos.proxy.scan_item_error_unrecognized(ean);
+ this.pos.proxy.scan_item_error_unrecognized(code);
return false;
},
// the default behavior is the following :
// - if there's a user with a matching ean, put it as the active 'client' and return true
// - else : return false.
- barcode_client_action: function(ean){
+ barcode_client_action: function(code){
var partners = this.pos.get('partner_list');
for(var i = 0, len = partners.length; i < len; i++){
- if(partners[i].ean13 === ean.ean){
+ if(partners[i].ean13 === code.code){
this.pos.get('selectedOrder').set_client(partners[i]);
this.pos_widget.username.refresh();
- this.pos.proxy.scan_item_success(ean);
+ this.pos.proxy.scan_item_success(code);
return true;
}
}
- this.pos.proxy.scan_item_error_unrecognized(ean);
+ this.pos.proxy.scan_item_error_unrecognized(code);
return false;
//TODO start the transaction
},
// what happens when a discount barcode is scanned : the default behavior
// is to set the discount on the last order.
- barcode_discount_action: function(ean){
- this.pos.proxy.scan_item_success(ean);
+ barcode_discount_action: function(code){
+ this.pos.proxy.scan_item_success(code);
var last_orderline = this.pos.get('selectedOrder').getLastOrderline();
if(last_orderline){
- last_orderline.set_discount(ean.value)
+ last_orderline.set_discount(code.value)
}
},
this.pos_widget.username.set_user_mode(this.pos_widget.screen_selector.get_user_mode());
this.pos.barcode_reader.set_action_callback({
- 'cashier': self.barcode_cashier_action ? function(ean){ self.barcode_cashier_action(ean); } : undefined ,
- 'product': self.barcode_product_action ? function(ean){ self.barcode_product_action(ean); } : undefined ,
- 'client' : self.barcode_client_action ? function(ean){ self.barcode_client_action(ean); } : undefined ,
- 'discount': self.barcode_discount_action ? function(ean){ self.barcode_discount_action(ean); } : undefined,
+ 'cashier': self.barcode_cashier_action ? function(code){ self.barcode_cashier_action(code); } : undefined ,
+ 'product': self.barcode_product_action ? function(code){ self.barcode_product_action(code); } : undefined ,
+ 'client' : self.barcode_client_action ? function(code){ self.barcode_client_action(code); } : undefined ,
+ 'discount': self.barcode_discount_action ? function(code){ self.barcode_discount_action(code); } : undefined,
});
},
this.pos.barcode_reader.save_callbacks();
this.pos.barcode_reader.reset_action_callbacks();
this.pos.barcode_reader.set_action_callback({
- 'cashier': function(ean){
+ 'cashier': function(code){
clearInterval(this.intervalID);
self.pos.proxy.cashier_mode_activated();
self.pos_widget.screen_selector.set_user_mode('cashier');
show_numpad: false,
show_leftpane: false,
- barcode_product_action: function(ean){
+ barcode_product_action: function(code){
this.pos.proxy.transaction_start();
- this._super(ean);
+ this._super(code);
},
- barcode_client_action: function(ean){
+ barcode_client_action: function(code){
this.pos.proxy.transaction_start();
- this._super(ean);
+ this._super(code);
$('.goodbye-message').addClass('oe_hidden');
this.pos_widget.screen_selector.show_popup('choose-receipt');
},
this._super();
var self = this;
- if(this.pos.iface_cashdrawer){
- this.pos.proxy.open_cashbox();
+ if( this.pos.iface_cashdrawer && this.pos.get('selectedOrder').get('paymentLines').find( function(pl){ return pl.cashregister.get('journal').type === 'cash'; })){
+ this.pos.proxy.open_cashbox();
}
this.set_numpad_state(this.pos_widget.numpad.state);
label: _t('Back'),
icon: '/point_of_sale/static/src/img/icons/png48/go-previous.png',
click: function(){
+ _.each(self.paymentlinewidgets, function(widget){
+ if( widget.payment_line.get_amount() === 0 ){
+ widget.payment_line.destroy();
+ }
+ });
self.pos_widget.screen_selector.set_current_screen(self.back_screen);
},
});
});
}
+ if( this.pos.iface_cashdrawer ){
+ this.add_action_button({
+ label: _t('Cash'),
+ name: 'cashbox',
+ icon: '/point_of_sale/static/src/img/open-cashbox.png',
+ click: function(){
+ self.pos.proxy.open_cashbox();
+ },
+ });
+ }
+
this.updatePaymentSummary();
this.line_refocus();
},
var self = this;
this._super();
this.$el.click(function(){
- self.order.selectLine(this.model);
+ self.order.selectLine(self.model);
self.trigger('order_line_selected');
});
if(this.model.is_selected()){
var cat = self.pos.db.get_category_by_id(id);
self.set_category(cat);
self.renderElement();
- self.search_and_categories(cat);
});
});
// breadcrumb click actions
var category = self.pos.db.get_category_by_id(id);
self.set_category(category);
self.renderElement();
- self.search_and_categories(category);
});
+
+ this.search_and_categories();
+
if(this.pos.iface_vkeyboard && this.pos_widget.onscreen_keyboard){
this.pos_widget.onscreen_keyboard.connect(this.$('.searchbox input'));
}
- this.search_and_categories();
},
set_product_type: function(type){ // 'all' | 'weightable'
reset_category: function(){
this.set_category();
this.renderElement();
- this.search_and_categories();
+ },
+
+ // empties the content of the search box
+ clear_search: function(){
+ var products = this.pos.db.get_product_by_category(this.category.id);
+ this.pos.get('products').reset(products);
+ this.$('.searchbox input').val('').focus();
+ this.$('.search-clear').fadeOut();
},
// filters the products, and sets up the search callbacks
var products = this.pos.db.get_product_by_category(this.category.id);
self.pos.get('products').reset(products);
+
+ var searchtimeout = null;
// filter the products according to the search string
- this.$('.searchbox input').keyup(function(){
- query = $(this).val().toLowerCase();
- if(query){
- var products = self.pos.db.search_product_in_category(self.category.id, query);
- self.pos.get('products').reset(products);
- self.$('.search-clear').fadeIn();
- }else{
- var products = self.pos.db.get_product_by_category(self.category.id);
- self.pos.get('products').reset(products);
- self.$('.search-clear').fadeOut();
- }
- });
+ this.$('.searchbox input').keyup(function(event){
+ clearTimeout(searchtimeout);
- this.$('.searchbox input').click(function(){}); //Why ???
+ var query = $(this).val().toLowerCase();
+
+ searchtimeout = setTimeout(function(){
+ if(query){
+ if(event.which === 13){
+ if( self.pos.get('products').size() === 1 ){
+ self.pos.get('selectedOrder').addProduct(self.pos.get('products').at(0));
+ self.clear_search();
+ }
+ }else{
+ var products = self.pos.db.search_product_in_category(self.category.id, query);
+ self.pos.get('products').reset(products);
+ self.$('.search-clear').fadeIn();
+ }
+ }else{
+ var products = self.pos.db.get_product_by_category(self.category.id);
+ self.pos.get('products').reset(products);
+ self.$('.search-clear').fadeOut();
+ }
+ },200);
+ });
//reset the search when clicking on reset
this.$('.search-clear').click(function(){
- var products = self.pos.db.get_product_by_category(self.category.id);
- self.pos.get('products').reset(products);
- self.$('.searchbox input').val('').focus();
- self.$('.search-clear').fadeOut();
+ self.clear_search();
});
},
});
var self = this;
this._super();
if(this.action){
- this.$el.click(function(){ self.action(); });
+ this.$el.click(function(){
+ self.action();
+ });
}
},
show: function(){ this.$el.removeClass('oe_hidden'); },
this.$('.button.custom_ean').click(function(){
var ean = self.pos.barcode_reader.sanitize_ean(self.$('input.ean').val() || '0');
self.$('input.ean').val(ean);
- self.pos.barcode_reader.on_ean(ean);
+ self.pos.barcode_reader.scan('ean13',ean);
+ });
+ this.$('.button.reference').click(function(){
+ self.pos.barcode_reader.scan('reference',self.$('input.ean').val());
});
_.each(this.eans, function(ean, name){
self.$('.button.'+name).click(function(){
self.$('input.ean').val(ean);
- self.pos.barcode_reader.on_ean(ean);
+ self.pos.barcode_reader.scan('ean13',ean);
});
});
_.each(this.events, function(name){
},
close: function() {
var self = this;
- return new instance.web.Model("ir.model.data").get_func("search_read")([['name', '=', 'action_client_pos_menu']], ['res_id']).pipe(
- _.bind(function(res) {
- return this.rpc('/web/action/load', {'action_id': res[0]['res_id']}).pipe(_.bind(function(result) {
- var action = result;
- action.context = _.extend(action.context || {}, {'cancel_action': {type: 'ir.actions.client', tag: 'reload'}});
- //self.destroy();
- this.do_action(action);
- }, this));
- }, this));
+
+ function close(){
+ return new instance.web.Model("ir.model.data").get_func("search_read")([['name', '=', 'action_client_pos_menu']], ['res_id']).pipe(
+ _.bind(function(res) {
+ return this.rpc('/web/action/load', {'action_id': res[0]['res_id']}).pipe(_.bind(function(result) {
+ var action = result;
+ action.context = _.extend(action.context || {}, {'cancel_action': {type: 'ir.actions.client', tag: 'reload'}});
+ //self.destroy();
+ this.do_action(action);
+ }, this));
+ }, self));
+ }
+
+ var draft_order = _.find( self.pos.get('orders').models, function(order){
+ return order.get('orderLines').length !== 0 && order.get('paymentLines').length === 0;
+ });
+ if(draft_order){
+ if (confirm(_t("Pending orders will be lost.\nAre you sure you want to leave this session?"))) {
+ return close();
+ }
+ }else{
+ return close();
+ }
},
destroy: function() {
this.pos.destroy();
</div>
<div id="rightheader">
<div id="order-selector">
- <button class="neworder-button square">➕</button>
- <button class="deleteorder-button square">➖</button>
+ <button class="neworder-button square"><img src='/point_of_sale/static/src/img/plus.png' /></button>
+ <button class="deleteorder-button square"><img src='/point_of_sale/static/src/img/minus.png' /></button>
<ol id="orders"></ol>
</div>
<!-- here goes header buttons -->
<li class="button lemon_price">1.54€ Lemon</li>
<li class="button unknown_product">Unknown Product</li>
<li class="button invalid_ean">Invalid Ean</li>
+ <li class="button reference">Reference</li>
</ul>
<p class="category">Hardware Status</p>
<t t-name="PosTicket">
<div class="pos-sale-ticket">
- <div class="pos-right-align"><t t-esc="new Date().toString(Date.CultureInfo.formatPatterns.shortDate + ' ' +
+ <div class="pos-center-align"><t t-esc="new Date().toString(Date.CultureInfo.formatPatterns.shortDate + ' ' +
Date.CultureInfo.formatPatterns.longTime)"/> <t t-esc="widget.currentOrder.attributes.name"/></div>
<br />
<t t-esc="widget.company.name"/><br />