[POS] Split the pos code into files
bzr revid: fva@openerp.com-20120424162546-3w604gxmfb0ezt47
This commit is contained in:
parent
8a9ce7b98e
commit
4efe726fdf
|
@ -82,7 +82,12 @@ Main features :
|
|||
'application': True,
|
||||
'certificate' : '001156338024966477869',
|
||||
# Web client
|
||||
'js': ['static/lib/backbone/backbone-0.5.3.js', 'static/src/js/pos.js'],
|
||||
'js': [
|
||||
'static/lib/backbone/backbone-0.5.3.js',
|
||||
'static/src/js/pos_models.js',
|
||||
'static/src/js/pos_widgets.js',
|
||||
'static/src/js/pos_main.js'
|
||||
],
|
||||
'css': ['static/src/css/pos.css'],
|
||||
'qweb': ['static/src/xml/pos.xml'],
|
||||
}
|
||||
|
|
|
@ -30,10 +30,8 @@ openerp.point_of_sale = function(instance) {
|
|||
}));
|
||||
};
|
||||
};
|
||||
|
||||
var _t = instance.web._t;
|
||||
|
||||
var LocalStorageDAO = instance.web.Class.extend({
|
||||
namespace.LocalStorageDAO = instance.web.Class.extend({
|
||||
add_operation: function(operation) {
|
||||
var self = this;
|
||||
return $.async_when().pipe(function() {
|
||||
|
@ -79,11 +77,11 @@ openerp.point_of_sale = function(instance) {
|
|||
/*
|
||||
Gets all the necessary data from the OpenERP web client (instance, shop data etc.)
|
||||
*/
|
||||
var PosModel = Backbone.Model.extend({
|
||||
namespace.PosModel = Backbone.Model.extend({
|
||||
initialize: function(session, attributes) {
|
||||
Backbone.Model.prototype.initialize.call(this, attributes);
|
||||
var self = this;
|
||||
this.dao = new LocalStorageDAO();
|
||||
this.dao = new namespace.LocalStorageDAO();
|
||||
this.ready = $.Deferred();
|
||||
this.flush_mutex = new $.Mutex();
|
||||
this.build_tree = _.bind(this.build_tree, this);
|
||||
|
@ -257,25 +255,18 @@ openerp.point_of_sale = function(instance) {
|
|||
---
|
||||
*/
|
||||
|
||||
var CashRegister = Backbone.Model.extend({
|
||||
namespace.CashRegister = Backbone.Model.extend({
|
||||
});
|
||||
|
||||
var CashRegisterCollection = Backbone.Collection.extend({
|
||||
model: CashRegister,
|
||||
namespace.CashRegisterCollection = Backbone.Collection.extend({
|
||||
model: namespace.CashRegister,
|
||||
});
|
||||
|
||||
var Product = Backbone.Model.extend({
|
||||
namespace.Product = Backbone.Model.extend({
|
||||
});
|
||||
|
||||
var ProductCollection = Backbone.Collection.extend({
|
||||
model: Product,
|
||||
});
|
||||
|
||||
var Category = Backbone.Model.extend({
|
||||
});
|
||||
|
||||
var CategoryCollection = Backbone.Collection.extend({
|
||||
model: Category,
|
||||
namespace.ProductCollection = Backbone.Collection.extend({
|
||||
model: namespace.Product,
|
||||
});
|
||||
|
||||
/*
|
||||
|
@ -284,7 +275,7 @@ openerp.point_of_sale = function(instance) {
|
|||
To add more of the same product, just update the quantity accordingly.
|
||||
The Order also contains payment information.
|
||||
*/
|
||||
var Orderline = Backbone.Model.extend({
|
||||
namespace.Orderline = Backbone.Model.extend({
|
||||
defaults: {
|
||||
quantity: 1,
|
||||
list_price: 0,
|
||||
|
@ -365,12 +356,12 @@ openerp.point_of_sale = function(instance) {
|
|||
},
|
||||
});
|
||||
|
||||
var OrderlineCollection = Backbone.Collection.extend({
|
||||
model: Orderline,
|
||||
namespace.OrderlineCollection = Backbone.Collection.extend({
|
||||
model: namespace.Orderline,
|
||||
});
|
||||
|
||||
// Every PaymentLine has all the attributes of the corresponding CashRegister.
|
||||
var Paymentline = Backbone.Model.extend({
|
||||
namespace.Paymentline = Backbone.Model.extend({
|
||||
defaults: {
|
||||
amount: 0,
|
||||
},
|
||||
|
@ -391,11 +382,11 @@ openerp.point_of_sale = function(instance) {
|
|||
},
|
||||
});
|
||||
|
||||
var PaymentlineCollection = Backbone.Collection.extend({
|
||||
model: Paymentline,
|
||||
namespace.PaymentlineCollection = Backbone.Collection.extend({
|
||||
model: namespace.Paymentline,
|
||||
});
|
||||
|
||||
var Order = Backbone.Model.extend({
|
||||
namespace.Order = Backbone.Model.extend({
|
||||
defaults:{
|
||||
validated: false,
|
||||
step: 'products',
|
||||
|
@ -403,9 +394,9 @@ openerp.point_of_sale = function(instance) {
|
|||
initialize: function(attributes){
|
||||
Backbone.Model.prototype.initialize.apply(this, arguments);
|
||||
this.set({
|
||||
creationDate: new Date,
|
||||
orderLines: new OrderlineCollection,
|
||||
paymentLines: new PaymentlineCollection,
|
||||
creationDate: new Date(),
|
||||
orderLines: new namespace.OrderlineCollection(),
|
||||
paymentLines: new namespace.PaymentlineCollection(),
|
||||
name: "Order " + this.generateUniqueId(),
|
||||
});
|
||||
this.posmodel = attributes.posmodel; //TODO put that in set and remember to use 'get' to read it ...
|
||||
|
@ -431,7 +422,7 @@ openerp.point_of_sale = function(instance) {
|
|||
} else {
|
||||
var attr = product.toJSON();
|
||||
attr.posmodel = this.posmodel;
|
||||
var line = new Orderline(attr);
|
||||
var line = new namespace.Orderline(attr);
|
||||
this.get('orderLines').add(line);
|
||||
line.bind('killme', function() {
|
||||
this.get('orderLines').remove(line);
|
||||
|
@ -440,7 +431,7 @@ openerp.point_of_sale = function(instance) {
|
|||
},
|
||||
addPaymentLine: function(cashRegister) {
|
||||
var newPaymentline;
|
||||
newPaymentline = new Paymentline(cashRegister);
|
||||
newPaymentline = new namespace.Paymentline(cashRegister);
|
||||
/* TODO: Should be 0 for cash-like accounts */
|
||||
newPaymentline.set({
|
||||
amount: this.getDueLeft()
|
||||
|
@ -498,24 +489,24 @@ openerp.point_of_sale = function(instance) {
|
|||
},
|
||||
});
|
||||
|
||||
var OrderCollection = Backbone.Collection.extend({
|
||||
model: Order,
|
||||
namespace.OrderCollection = Backbone.Collection.extend({
|
||||
model: namespace.Order,
|
||||
});
|
||||
|
||||
var Shop = Backbone.Model.extend({
|
||||
namespace.Shop = Backbone.Model.extend({
|
||||
initialize: function(attributes) {
|
||||
var self = this;
|
||||
this.set({
|
||||
orders: new OrderCollection(),
|
||||
products: new ProductCollection(),
|
||||
orders: new namespace.OrderCollection(),
|
||||
products: new namespace.ProductCollection(),
|
||||
});
|
||||
this.posmodel = attributes.posmodel;
|
||||
this.set({
|
||||
cashRegisters: new CashRegisterCollection(this.posmodel.get('bank_statements')),
|
||||
cashRegisters: new namespace.CashRegisterCollection(this.posmodel.get('bank_statements')),
|
||||
});
|
||||
return (this.get('orders')).bind('remove', _.bind( function(removedOrder) {
|
||||
if ((this.get('orders')).isEmpty()) {
|
||||
this.addAndSelectOrder(new Order({posmodel: self.posmodel}));
|
||||
this.addAndSelectOrder(new namespace.Order({posmodel: self.posmodel}));
|
||||
}
|
||||
if ((this.get('selectedOrder')) === removedOrder) {
|
||||
return this.set({
|
||||
|
@ -536,7 +527,7 @@ openerp.point_of_sale = function(instance) {
|
|||
The numpad handles both the choice of the property currently being modified
|
||||
(quantity, price or discount) and the edition of the corresponding numeric value.
|
||||
*/
|
||||
var NumpadState = Backbone.Model.extend({
|
||||
namespace.NumpadState = Backbone.Model.extend({
|
||||
defaults: {
|
||||
buffer: "0",
|
||||
mode: "quantity"
|
||||
|
@ -604,10 +595,10 @@ openerp.point_of_sale = function(instance) {
|
|||
Views
|
||||
---
|
||||
*/
|
||||
var NumpadWidget = instance.web.OldWidget.extend({
|
||||
namespace.NumpadWidget = instance.web.OldWidget.extend({
|
||||
init: function(parent, options) {
|
||||
this._super(parent);
|
||||
this.state = new NumpadState();
|
||||
this.state = new namespace.NumpadState();
|
||||
},
|
||||
start: function() {
|
||||
this.state.bind('change:mode', this.changedMode, this);
|
||||
|
@ -641,7 +632,7 @@ openerp.point_of_sale = function(instance) {
|
|||
/*
|
||||
Gives access to the payment methods (aka. 'cash registers')
|
||||
*/
|
||||
var PaypadWidget = instance.web.OldWidget.extend({
|
||||
namespace.PaypadWidget = instance.web.OldWidget.extend({
|
||||
init: function(parent, options) {
|
||||
this._super(parent);
|
||||
this.shop = options.shop;
|
||||
|
@ -666,13 +657,14 @@ openerp.point_of_sale = function(instance) {
|
|||
renderElement: function() {
|
||||
this.$element.empty();
|
||||
return (this.shop.get('cashRegisters')).each(_.bind( function(cashRegister) {
|
||||
var button = new PaymentButtonWidget();
|
||||
var button = new namespace.PaymentButtonWidget();
|
||||
button.model = cashRegister;
|
||||
button.appendTo(this.$element);
|
||||
}, this));
|
||||
}
|
||||
});
|
||||
var PaymentButtonWidget = instance.web.OldWidget.extend({
|
||||
|
||||
namespace.PaymentButtonWidget = instance.web.OldWidget.extend({
|
||||
template_fct: qweb_template('pos-payment-button-template'),
|
||||
renderElement: function() {
|
||||
this.$element.html(this.template_fct({
|
||||
|
@ -690,7 +682,7 @@ openerp.point_of_sale = function(instance) {
|
|||
It should be possible to go back to any step as long as step 3 hasn't been completed.
|
||||
Modifying an order after validation shouldn't be allowed.
|
||||
*/
|
||||
var StepSwitcher = instance.web.OldWidget.extend({
|
||||
namespace.StepSwitcher = instance.web.OldWidget.extend({
|
||||
init: function(parent, options) {
|
||||
this._super(parent);
|
||||
this.shop = options.shop;
|
||||
|
@ -716,7 +708,7 @@ openerp.point_of_sale = function(instance) {
|
|||
/*
|
||||
Shopping carts.
|
||||
*/
|
||||
var OrderlineWidget = instance.web.OldWidget.extend({
|
||||
namespace.OrderlineWidget = instance.web.OldWidget.extend({
|
||||
tagName: 'tr',
|
||||
template_fct: qweb_template('pos-orderline-template'),
|
||||
init: function(parent, options) {
|
||||
|
@ -757,7 +749,7 @@ openerp.point_of_sale = function(instance) {
|
|||
on_selected: function() {},
|
||||
});
|
||||
|
||||
var OrderWidget = instance.web.OldWidget.extend({
|
||||
namespace.OrderWidget = instance.web.OldWidget.extend({
|
||||
init: function(parent, options) {
|
||||
this._super(parent);
|
||||
this.shop = options.shop;
|
||||
|
@ -796,7 +788,7 @@ openerp.point_of_sale = function(instance) {
|
|||
this.currentOrderLines.bind('remove', this.renderElement, this);
|
||||
},
|
||||
addLine: function(newLine) {
|
||||
var line = new OrderlineWidget(null, {
|
||||
var line = new namespace.OrderlineWidget(null, {
|
||||
model: newLine,
|
||||
order: this.shop.get('selectedOrder')
|
||||
});
|
||||
|
@ -818,7 +810,7 @@ openerp.point_of_sale = function(instance) {
|
|||
renderElement: function() {
|
||||
this.$element.empty();
|
||||
this.currentOrderLines.each(_.bind( function(orderLine) {
|
||||
var line = new OrderlineWidget(null, {
|
||||
var line = new namespace.OrderlineWidget(null, {
|
||||
model: orderLine,
|
||||
order: this.shop.get('selectedOrder')
|
||||
});
|
||||
|
@ -842,7 +834,7 @@ openerp.point_of_sale = function(instance) {
|
|||
/*
|
||||
"Products" step.
|
||||
*/
|
||||
var CategoryWidget = instance.web.OldWidget.extend({
|
||||
namespace.CategoryWidget = instance.web.OldWidget.extend({
|
||||
init: function(parent, options){
|
||||
this._super(parent,options.element_id);
|
||||
this.posmodel = options.posmodel;
|
||||
|
@ -882,7 +874,7 @@ openerp.point_of_sale = function(instance) {
|
|||
on_change_category: function(id) {},
|
||||
});
|
||||
|
||||
var ProductWidget = instance.web.OldWidget.extend({
|
||||
namespace.ProductWidget = instance.web.OldWidget.extend({
|
||||
tagName:'li',
|
||||
template_fct: qweb_template('pos-product-template'),
|
||||
init: function(parent, options) {
|
||||
|
@ -905,7 +897,7 @@ openerp.point_of_sale = function(instance) {
|
|||
},
|
||||
});
|
||||
|
||||
var ProductListWidget = instance.web.OldWidget.extend({
|
||||
namespace.ProductListWidget = instance.web.OldWidget.extend({
|
||||
init: function(parent, options) {
|
||||
this._super(parent);
|
||||
this.model = options.model;
|
||||
|
@ -915,7 +907,7 @@ openerp.point_of_sale = function(instance) {
|
|||
renderElement: function() {
|
||||
this.$element.empty();
|
||||
(this.shop.get('products')).each(_.bind( function(product) {
|
||||
var p = new ProductWidget(null, {
|
||||
var p = new namespace.ProductWidget(null, {
|
||||
model: product,
|
||||
shop: this.shop
|
||||
});
|
||||
|
@ -927,7 +919,7 @@ openerp.point_of_sale = function(instance) {
|
|||
/*
|
||||
"Payment" step.
|
||||
*/
|
||||
var PaymentlineWidget = instance.web.OldWidget.extend({
|
||||
namespace.PaymentlineWidget = instance.web.OldWidget.extend({
|
||||
tagName: 'tr',
|
||||
template_fct: qweb_template('pos-paymentline-template'),
|
||||
init: function(parent, options) {
|
||||
|
@ -962,7 +954,7 @@ openerp.point_of_sale = function(instance) {
|
|||
},
|
||||
});
|
||||
|
||||
var PaymentWidget = instance.web.OldWidget.extend({
|
||||
namespace.PaymentWidget = instance.web.OldWidget.extend({
|
||||
init: function(parent, options) {
|
||||
this._super(parent);
|
||||
this.model = options.model;
|
||||
|
@ -1011,7 +1003,7 @@ openerp.point_of_sale = function(instance) {
|
|||
this.renderElement();
|
||||
},
|
||||
addPaymentLine: function(newPaymentLine) {
|
||||
var x = new PaymentlineWidget(null, {
|
||||
var x = new namespace.PaymentlineWidget(null, {
|
||||
model: newPaymentLine
|
||||
});
|
||||
x.on_delete.add(_.bind(this.deleteLine, this, x));
|
||||
|
@ -1059,7 +1051,7 @@ openerp.point_of_sale = function(instance) {
|
|||
},
|
||||
});
|
||||
|
||||
var ReceiptWidget = instance.web.OldWidget.extend({
|
||||
namespace.ReceiptWidget = instance.web.OldWidget.extend({
|
||||
init: function(parent, options) {
|
||||
this._super(parent);
|
||||
this.model = options.model;
|
||||
|
@ -1103,7 +1095,7 @@ openerp.point_of_sale = function(instance) {
|
|||
},
|
||||
});
|
||||
|
||||
var OrderButtonWidget = instance.web.OldWidget.extend({
|
||||
namespace.OrderButtonWidget = instance.web.OldWidget.extend({
|
||||
tagName: 'li',
|
||||
template_fct: qweb_template('pos-order-selector-button-template'),
|
||||
init: function(parent, options) {
|
||||
|
@ -1143,7 +1135,7 @@ openerp.point_of_sale = function(instance) {
|
|||
}
|
||||
});
|
||||
|
||||
var ActionButtonWidget = instance.web.Widget.extend({
|
||||
namespace.ActionButtonWidget = instance.web.Widget.extend({
|
||||
template:'pos-action-button',
|
||||
init: function(parent, options){
|
||||
this._super(parent, options);
|
||||
|
@ -1156,7 +1148,7 @@ openerp.point_of_sale = function(instance) {
|
|||
},
|
||||
});
|
||||
|
||||
var ActionbarWidget = instance.web.Widget.extend({
|
||||
namespace.ActionbarWidget = instance.web.Widget.extend({
|
||||
template:'pos-actionbar',
|
||||
init: function(parent, options){
|
||||
this._super(parent,options);
|
||||
|
@ -1194,7 +1186,7 @@ openerp.point_of_sale = function(instance) {
|
|||
button_list = this.right_button_list;
|
||||
$button_list = $('.pos-actionbar-right-region');
|
||||
}
|
||||
var button = new ActionButtonWidget(this,button_options);
|
||||
var button = new namespace.ActionButtonWidget(this,button_options);
|
||||
button_list.push(button);
|
||||
button.appendTo($button_list);
|
||||
}else{
|
||||
|
@ -1221,7 +1213,7 @@ openerp.point_of_sale = function(instance) {
|
|||
//
|
||||
// The widget is initially hidden. It can be shown with this.show(), and is
|
||||
// automatically shown when the input_selector gets focused.
|
||||
var OnscreenKeyboardWidget = instance.web.Widget.extend({
|
||||
namespace.OnscreenKeyboardWidget = instance.web.Widget.extend({
|
||||
tagName: 'div',
|
||||
|
||||
init: function(parent, options){
|
||||
|
@ -1404,7 +1396,7 @@ openerp.point_of_sale = function(instance) {
|
|||
},
|
||||
});
|
||||
|
||||
var ShopWidget = instance.web.OldWidget.extend({
|
||||
namespace.ShopWidget = instance.web.OldWidget.extend({
|
||||
init: function(parent, options) {
|
||||
this._super(parent);
|
||||
this.shop = options.shop;
|
||||
|
@ -1414,46 +1406,46 @@ openerp.point_of_sale = function(instance) {
|
|||
$('button#neworder-button', this.$element).click(_.bind(this.createNewOrder, this));
|
||||
|
||||
(this.shop.get('orders')).bind('add', this.orderAdded, this);
|
||||
(this.shop.get('orders')).add(new Order({'posmodel':this.posmodel}));
|
||||
this.productListView = new ProductListWidget(null, {
|
||||
(this.shop.get('orders')).add(new namespace.Order({'posmodel':this.posmodel}));
|
||||
this.productListView = new namespace.ProductListWidget(null, {
|
||||
shop: this.shop
|
||||
});
|
||||
this.productListView.$element = $("#products-screen-ol");
|
||||
this.productListView.renderElement();
|
||||
this.productListView.start();
|
||||
this.paypadView = new PaypadWidget(null, {
|
||||
this.paypadView = new namespace.PaypadWidget(null, {
|
||||
shop: this.shop
|
||||
});
|
||||
this.paypadView.$element = $('#paypad');
|
||||
this.paypadView.renderElement();
|
||||
this.paypadView.start();
|
||||
this.numpadView = new NumpadWidget(null);
|
||||
this.numpadView = new namespace.NumpadWidget(null);
|
||||
this.numpadView.$element = $('#numpad');
|
||||
this.numpadView.start();
|
||||
this.orderView = new OrderWidget(null, {
|
||||
this.orderView = new namespace.OrderWidget(null, {
|
||||
shop: this.shop,
|
||||
});
|
||||
this.orderView.$element = $('#current-order-content');
|
||||
this.orderView.start();
|
||||
this.paymentView = new PaymentWidget(null, {
|
||||
this.paymentView = new namespace.PaymentWidget(null, {
|
||||
shop: this.shop,
|
||||
posmodel: this.posmodel,
|
||||
});
|
||||
this.paymentView.$element = $('#payment-screen');
|
||||
this.paymentView.renderElement();
|
||||
this.paymentView.start();
|
||||
this.receiptView = new ReceiptWidget(null, {
|
||||
this.receiptView = new namespace.ReceiptWidget(null, {
|
||||
shop: this.shop,
|
||||
posmodel: this.posmodel,
|
||||
});
|
||||
this.receiptView.replace($('#receipt-screen'));
|
||||
this.stepSwitcher = new StepSwitcher(this, {shop: this.shop});
|
||||
this.stepSwitcher = new namespace.StepSwitcher(this, {shop: this.shop});
|
||||
this.shop.bind('change:selectedOrder', this.changedSelectedOrder, this);
|
||||
this.changedSelectedOrder();
|
||||
},
|
||||
createNewOrder: function() {
|
||||
var newOrder;
|
||||
newOrder = new Order({'posmodel': this.posmodel});
|
||||
newOrder = new namespace.Order({'posmodel': this.posmodel});
|
||||
(this.shop.get('orders')).add(newOrder);
|
||||
this.shop.set({
|
||||
selectedOrder: newOrder
|
||||
|
@ -1461,7 +1453,7 @@ openerp.point_of_sale = function(instance) {
|
|||
},
|
||||
orderAdded: function(newOrder) {
|
||||
var newOrderButton;
|
||||
newOrderButton = new OrderButtonWidget(null, {
|
||||
newOrderButton = new namespace.OrderButtonWidget(null, {
|
||||
order: newOrder,
|
||||
shop: this.shop
|
||||
});
|
||||
|
@ -1488,7 +1480,7 @@ openerp.point_of_sale = function(instance) {
|
|||
},
|
||||
});
|
||||
|
||||
var App = (function() {
|
||||
namespace.App = (function() {
|
||||
|
||||
function App($element, posmodel) {
|
||||
this.initialize($element, posmodel);
|
||||
|
@ -1496,21 +1488,21 @@ openerp.point_of_sale = function(instance) {
|
|||
|
||||
App.prototype.initialize = function($element, posmodel) {
|
||||
this.posmodel = posmodel;
|
||||
this.shop = new Shop({'posmodel': posmodel});
|
||||
this.shopView = new ShopWidget(null, {
|
||||
this.shop = new namespace.Shop({'posmodel': posmodel});
|
||||
this.shopView = new namespace.ShopWidget(null, {
|
||||
shop: this.shop,
|
||||
'posmodel': posmodel,
|
||||
});
|
||||
this.shopView.$element = $element;
|
||||
this.shopView.start();
|
||||
this.categoryView = new CategoryWidget(null, {element_id: 'products-screen-categories', posmodel: posmodel} );
|
||||
this.categoryView = new namespace.CategoryWidget(null, {element_id: 'products-screen-categories', posmodel: posmodel} );
|
||||
this.categoryView.on_change_category.add_last(_.bind(this.category, this));
|
||||
this.category();
|
||||
|
||||
this.onscreenKeyboard = new OnscreenKeyboardWidget(null,{keyboard_model:'simple'});
|
||||
this.onscreenKeyboard = new namespace.OnscreenKeyboardWidget(null,{keyboard_model:'simple'});
|
||||
this.onscreenKeyboard.appendTo($(".point-of-sale #content"));
|
||||
|
||||
this.actionBar = new ActionbarWidget(null);
|
||||
this.actionBar = new namespace.ActionbarWidget(null);
|
||||
this.actionBar.appendTo($(".point-of-sale #content"));
|
||||
|
||||
this.actionBar.addNewButton('left',{
|
||||
|
@ -1669,7 +1661,7 @@ openerp.point_of_sale = function(instance) {
|
|||
}*/
|
||||
});
|
||||
} else {
|
||||
selectedOrder.addProduct(new Product(scannedProductModel));
|
||||
selectedOrder.addProduct(new namespace.Product(scannedProductModel));
|
||||
}
|
||||
|
||||
codeNumbers = [];
|
||||
|
@ -1703,7 +1695,7 @@ openerp.point_of_sale = function(instance) {
|
|||
return App;
|
||||
})();
|
||||
|
||||
instance.point_of_sale.SynchNotification = instance.web.OldWidget.extend({
|
||||
namespace.SynchNotification = instance.web.OldWidget.extend({
|
||||
template: "pos-synch-notification",
|
||||
init: function() {
|
||||
this._super.apply(this, arguments);
|
||||
|
@ -1722,18 +1714,18 @@ openerp.point_of_sale = function(instance) {
|
|||
|
||||
instance.web.client_actions.add('pos.ui', 'instance.point_of_sale.POSWidget');
|
||||
|
||||
instance.point_of_sale.POSWidget = instance.web.OldWidget.extend({
|
||||
namespace.POSWidget = instance.web.OldWidget.extend({
|
||||
init: function() {
|
||||
this._super.apply(this, arguments);
|
||||
|
||||
this.posmodel = new PosModel(this.session);
|
||||
this.posmodel = new namespace.PosModel(this.session);
|
||||
|
||||
},
|
||||
start: function() {
|
||||
var self = this;
|
||||
return self.posmodel.ready.then(_.bind(function() {
|
||||
this.renderElement();
|
||||
this.synch_notification = new instance.point_of_sale.SynchNotification(this);
|
||||
this.synch_notification = new namespace.SynchNotification(this);
|
||||
this.synch_notification.replace($('.oe_pos_synch-notification', this.$element));
|
||||
this.synch_notification.on_synch.add(_.bind(self.posmodel.flush, self.posmodel));
|
||||
|
||||
|
@ -1744,7 +1736,7 @@ openerp.point_of_sale = function(instance) {
|
|||
self.try_close();
|
||||
});
|
||||
|
||||
self.posmodel.app = new App(self.$element, self.posmodel);
|
||||
self.posmodel.app = new namespace.App(self.$element, self.posmodel);
|
||||
instance.webclient.set_content_full_screen(true);
|
||||
|
||||
if (self.posmodel.get('bank_statements').length === 0)
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
openerp.point_of_sale = function(instance) {
|
||||
|
||||
instance.point_of_sale = {};
|
||||
|
||||
var module = instance.point_of_sale;
|
||||
|
||||
pos_models(module,instance); // import pos_models.js
|
||||
|
||||
pos_widgets(module,instance); // import pos_widgets.js
|
||||
|
||||
instance.web.client_actions.add('pos.ui', 'instance.point_of_sale.POSWidget');
|
||||
};
|
||||
|
||||
|
|
@ -0,0 +1,771 @@
|
|||
function pos_models(module, instance){
|
||||
var QWeb = instance.web.qweb;
|
||||
|
||||
module.LocalStorageDAO = instance.web.Class.extend({
|
||||
add_operation: function(operation) {
|
||||
var self = this;
|
||||
return $.async_when().pipe(function() {
|
||||
var tmp = self._get('oe_pos_operations', []);
|
||||
var last_id = self._get('oe_pos_operations_sequence', 1);
|
||||
tmp.push({'id': last_id, 'data': operation});
|
||||
self._set('oe_pos_operations', tmp);
|
||||
self._set('oe_pos_operations_sequence', last_id + 1);
|
||||
});
|
||||
},
|
||||
remove_operation: function(id) {
|
||||
var self = this;
|
||||
return $.async_when().pipe(function() {
|
||||
var tmp = self._get('oe_pos_operations', []);
|
||||
tmp = _.filter(tmp, function(el) {
|
||||
return el.id !== id;
|
||||
});
|
||||
self._set('oe_pos_operations', tmp);
|
||||
});
|
||||
},
|
||||
get_operations: function() {
|
||||
var self = this;
|
||||
return $.async_when().pipe(function() {
|
||||
return self._get('oe_pos_operations', []);
|
||||
});
|
||||
},
|
||||
_get: function(key, default_) {
|
||||
var txt = localStorage[key];
|
||||
if (! txt)
|
||||
return default_;
|
||||
return JSON.parse(txt);
|
||||
},
|
||||
_set: function(key, value) {
|
||||
localStorage[key] = JSON.stringify(value);
|
||||
},
|
||||
});
|
||||
|
||||
var fetch = function(osvModel, fields, domain){
|
||||
var dataSetSearch = new instance.web.DataSetSearch(null, osvModel, {}, domain);
|
||||
return dataSetSearch.read_slice(fields, 0);
|
||||
};
|
||||
|
||||
/*
|
||||
Gets all the necessary data from the OpenERP web client (instance, shop data etc.)
|
||||
*/
|
||||
module.PosModel = Backbone.Model.extend({
|
||||
initialize: function(session, attributes) {
|
||||
Backbone.Model.prototype.initialize.call(this, attributes);
|
||||
var self = this;
|
||||
this.dao = new module.LocalStorageDAO();
|
||||
this.ready = $.Deferred();
|
||||
this.flush_mutex = new $.Mutex();
|
||||
this.build_tree = _.bind(this.build_tree, this);
|
||||
this.session = session;
|
||||
this.categories = {};
|
||||
this.set({
|
||||
'nbr_pending_operations': 0,
|
||||
'currency': {symbol: '$', position: 'after'},
|
||||
'shop': {},
|
||||
'company': {},
|
||||
'user': {}
|
||||
});
|
||||
|
||||
var cat_def = fetch('pos.category', ['name', 'parent_id', 'child_id'])
|
||||
.pipe(function(result){
|
||||
return self.set({'categories': result});
|
||||
});
|
||||
|
||||
var prod_def = fetch(
|
||||
'product.product',
|
||||
['name', 'list_price', 'pos_categ_id', 'taxes_id','product_image_small'],
|
||||
[['pos_categ_id','!=', 'false']]
|
||||
).then(function(result){
|
||||
return self.set({'product_list': result});
|
||||
});
|
||||
|
||||
var bank_def = fetch(
|
||||
'account.bank.statement',
|
||||
['account_id', 'currency', 'journal_id', 'state', 'name'],
|
||||
[['state','=','open'], ['user_id', '=', this.session.uid]]
|
||||
).then(function(result){
|
||||
return self.set({'bank_statements': result});
|
||||
});
|
||||
|
||||
var tax_def = fetch('account.tax', ['amount','price_include','type'])
|
||||
.then(function(result){
|
||||
return self.set({'taxes': result});
|
||||
});
|
||||
|
||||
$.when(cat_def,prod_def,bank_def,tax_def,this.get_app_data(), this.flush())
|
||||
.pipe(_.bind(this.build_tree, this));
|
||||
},
|
||||
|
||||
get_app_data: function() {
|
||||
var self = this;
|
||||
return $.when(new instance.web.Model("sale.shop").get_func("search_read")([]).pipe(function(result) {
|
||||
self.set({'shop': result[0]});
|
||||
var company_id = result[0]['company_id'][0];
|
||||
return new instance.web.Model("res.company").get_func("read")(company_id, ['currency_id', 'name', 'phone']).pipe(function(result) {
|
||||
self.set({'company': result});
|
||||
var currency_id = result['currency_id'][0]
|
||||
return new instance.web.Model("res.currency").get_func("read")([currency_id],
|
||||
['symbol', 'position']).pipe(function(result) {
|
||||
self.set({'currency': result[0]});
|
||||
|
||||
});
|
||||
});
|
||||
}), new instance.web.Model("res.users").get_func("read")(this.session.uid, ['name']).pipe(function(result) {
|
||||
self.set({'user': result});
|
||||
}));
|
||||
},
|
||||
push_order: function(record) {
|
||||
var self = this;
|
||||
return this.dao.add_operation(record).pipe(function(){
|
||||
return self.flush();
|
||||
});
|
||||
},
|
||||
flush: function() {
|
||||
return this.flush_mutex.exec(_.bind(function() {
|
||||
return this._int_flush();
|
||||
}, this));
|
||||
},
|
||||
_int_flush : function() {
|
||||
var self = this;
|
||||
|
||||
this.dao.get_operations().pipe(function(operations) {
|
||||
self.set( {'nbr_pending_operations':operations.length} );
|
||||
if(operations.length === 0){
|
||||
return $.when();
|
||||
}
|
||||
var op = operations[0].data;
|
||||
|
||||
// we prevent the default error handler and assume errors
|
||||
// are a normal use case, except we stop the current iteration
|
||||
|
||||
return new instance.web.Model('pos.order').get_func('create_from_ui')([op])
|
||||
.fail(function(unused, event){
|
||||
event.preventDefault();
|
||||
})
|
||||
.pipe(function(){
|
||||
//console.debug('saved 1 record'); TODO Debug this
|
||||
self.dao.remove_operation(op.id).pipe(function(){
|
||||
return self._int_flush();
|
||||
});
|
||||
}, function(){
|
||||
return $.when();
|
||||
});
|
||||
});
|
||||
},
|
||||
build_tree: function() {
|
||||
var c, id, _i, _len, _ref, _ref2;
|
||||
_ref = this.get('categories');
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
c = _ref[_i];
|
||||
this.categories[c.id] = {
|
||||
id: c.id,
|
||||
name: c.name,
|
||||
children: c.child_id,
|
||||
parent: c.parent_id[0],
|
||||
ancestors: [c.id],
|
||||
subtree: [c.id]
|
||||
};
|
||||
}
|
||||
_ref2 = this.categories;
|
||||
for (id in _ref2) {
|
||||
c = _ref2[id];
|
||||
this.current_category = c;
|
||||
this.build_ancestors(c.parent);
|
||||
this.build_subtree(c);
|
||||
}
|
||||
this.categories[0] = {
|
||||
ancestors: [],
|
||||
children: (function() {
|
||||
var _j, _len2, _ref3, _results;
|
||||
_ref3 = this.get('categories');
|
||||
_results = [];
|
||||
for (_j = 0, _len2 = _ref3.length; _j < _len2; _j++) {
|
||||
c = _ref3[_j];
|
||||
if (!(c.parent_id[0] != null)) {
|
||||
_results.push(c.id);
|
||||
}
|
||||
}
|
||||
return _results;
|
||||
}).call(this),
|
||||
subtree: (function() {
|
||||
var _j, _len2, _ref3, _results;
|
||||
_ref3 = this.get('categories');
|
||||
_results = [];
|
||||
for (_j = 0, _len2 = _ref3.length; _j < _len2; _j++) {
|
||||
c = _ref3[_j];
|
||||
_results.push(c.id);
|
||||
}
|
||||
return _results;
|
||||
}).call(this)
|
||||
};
|
||||
return this.ready.resolve();
|
||||
},
|
||||
build_ancestors: function(parent) {
|
||||
if (parent != null) {
|
||||
this.current_category.ancestors.unshift(parent);
|
||||
return this.build_ancestors(this.categories[parent].parent);
|
||||
}
|
||||
},
|
||||
build_subtree: function(category) {
|
||||
var c, _i, _len, _ref, _results;
|
||||
_ref = category.children;
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
c = _ref[_i];
|
||||
this.current_category.subtree.push(c);
|
||||
_results.push(this.build_subtree(this.categories[c]));
|
||||
}
|
||||
return _results;
|
||||
}
|
||||
});
|
||||
|
||||
module.CashRegister = Backbone.Model.extend({
|
||||
});
|
||||
|
||||
module.CashRegisterCollection = Backbone.Collection.extend({
|
||||
model: module.CashRegister,
|
||||
});
|
||||
|
||||
module.Product = Backbone.Model.extend({
|
||||
});
|
||||
|
||||
module.ProductCollection = Backbone.Collection.extend({
|
||||
model: module.Product,
|
||||
});
|
||||
|
||||
/*
|
||||
Each Order contains zero or more Orderlines (i.e. the content of the "shopping cart".)
|
||||
There should only ever be one Orderline per distinct product in an Order.
|
||||
To add more of the same product, just update the quantity accordingly.
|
||||
The Order also contains payment information.
|
||||
*/
|
||||
module.Orderline = Backbone.Model.extend({
|
||||
defaults: {
|
||||
quantity: 1,
|
||||
list_price: 0,
|
||||
discount: 0
|
||||
},
|
||||
initialize: function(attributes) {
|
||||
this.posmodel = attributes.posmodel;
|
||||
Backbone.Model.prototype.initialize.apply(this, arguments);
|
||||
this.bind('change:quantity', function(unused, qty) {
|
||||
if (qty == 0)
|
||||
this.trigger('killme');
|
||||
}, this);
|
||||
},
|
||||
incrementQuantity: function() {
|
||||
return this.set({
|
||||
quantity: (this.get('quantity')) + 1
|
||||
});
|
||||
},
|
||||
getPriceWithoutTax: function() {
|
||||
return this.getAllPrices().priceWithoutTax;
|
||||
},
|
||||
getPriceWithTax: function() {
|
||||
return this.getAllPrices().priceWithTax;
|
||||
},
|
||||
getTax: function() {
|
||||
return this.getAllPrices().tax;
|
||||
},
|
||||
getAllPrices: function() {
|
||||
var self = this;
|
||||
var base = (this.get('quantity')) * (this.get('list_price')) * (1 - (this.get('discount')) / 100);
|
||||
var totalTax = base;
|
||||
var totalNoTax = base;
|
||||
|
||||
var product_list = self.posmodel.get('product_list');
|
||||
var product = _.detect(product_list, function(el) {return el.id === self.get('id');});
|
||||
var taxes_ids = product.taxes_id;
|
||||
var taxes = self.posmodel.get('taxes');
|
||||
var taxtotal = 0;
|
||||
_.each(taxes_ids, function(el) {
|
||||
var tax = _.detect(taxes, function(t) {return t.id === el;});
|
||||
if (tax.price_include) {
|
||||
var tmp;
|
||||
if (tax.type === "percent") {
|
||||
tmp = base - (base / (1 + tax.amount));
|
||||
} else if (tax.type === "fixed") {
|
||||
tmp = tax.amount * self.get('quantity');
|
||||
} else {
|
||||
throw "This type of tax is not supported by the point of sale: " + tax.type;
|
||||
}
|
||||
taxtotal += tmp;
|
||||
totalNoTax -= tmp;
|
||||
} else {
|
||||
var tmp;
|
||||
if (tax.type === "percent") {
|
||||
tmp = tax.amount * base;
|
||||
} else if (tax.type === "fixed") {
|
||||
tmp = tax.amount * self.get('quantity');
|
||||
} else {
|
||||
throw "This type of tax is not supported by the point of sale: " + tax.type;
|
||||
}
|
||||
taxtotal += tmp;
|
||||
totalTax += tmp;
|
||||
}
|
||||
});
|
||||
return {
|
||||
"priceWithTax": totalTax,
|
||||
"priceWithoutTax": totalNoTax,
|
||||
"tax": taxtotal,
|
||||
};
|
||||
},
|
||||
exportAsJSON: function() {
|
||||
return {
|
||||
qty: this.get('quantity'),
|
||||
price_unit: this.get('list_price'),
|
||||
discount: this.get('discount'),
|
||||
product_id: this.get('id')
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
module.OrderlineCollection = Backbone.Collection.extend({
|
||||
model: module.Orderline,
|
||||
});
|
||||
|
||||
// Every PaymentLine has all the attributes of the corresponding CashRegister.
|
||||
module.Paymentline = Backbone.Model.extend({
|
||||
defaults: {
|
||||
amount: 0,
|
||||
},
|
||||
initialize: function(attributes) {
|
||||
Backbone.Model.prototype.initialize.apply(this, arguments);
|
||||
},
|
||||
getAmount: function(){
|
||||
return this.get('amount');
|
||||
},
|
||||
exportAsJSON: function(){
|
||||
return {
|
||||
name: instance.web.datetime_to_str(new Date()),
|
||||
statement_id: this.get('id'),
|
||||
account_id: (this.get('account_id'))[0],
|
||||
journal_id: (this.get('journal_id'))[0],
|
||||
amount: this.getAmount()
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
module.PaymentlineCollection = Backbone.Collection.extend({
|
||||
model: module.Paymentline,
|
||||
});
|
||||
|
||||
module.Order = Backbone.Model.extend({
|
||||
defaults:{
|
||||
validated: false,
|
||||
step: 'products',
|
||||
},
|
||||
initialize: function(attributes){
|
||||
Backbone.Model.prototype.initialize.apply(this, arguments);
|
||||
this.set({
|
||||
creationDate: new Date(),
|
||||
orderLines: new module.OrderlineCollection(),
|
||||
paymentLines: new module.PaymentlineCollection(),
|
||||
name: "Order " + this.generateUniqueId(),
|
||||
});
|
||||
this.posmodel = attributes.posmodel; //TODO put that in set and remember to use 'get' to read it ...
|
||||
this.bind('change:validated', this.validatedChanged);
|
||||
return this;
|
||||
},
|
||||
events: {
|
||||
'change:validated': 'validatedChanged'
|
||||
},
|
||||
validatedChanged: function() {
|
||||
if (this.get("validated") && !this.previous("validated")) {
|
||||
this.set({'step': 'receipt'});
|
||||
}
|
||||
},
|
||||
generateUniqueId: function() {
|
||||
return new Date().getTime();
|
||||
},
|
||||
addProduct: function(product) {
|
||||
var existing;
|
||||
existing = (this.get('orderLines')).get(product.id);
|
||||
if (existing != null) {
|
||||
existing.incrementQuantity();
|
||||
} else {
|
||||
var attr = product.toJSON();
|
||||
attr.posmodel = this.posmodel;
|
||||
var line = new module.Orderline(attr);
|
||||
this.get('orderLines').add(line);
|
||||
line.bind('killme', function() {
|
||||
this.get('orderLines').remove(line);
|
||||
}, this);
|
||||
}
|
||||
},
|
||||
addPaymentLine: function(cashRegister) {
|
||||
var newPaymentline;
|
||||
newPaymentline = new module.Paymentline(cashRegister);
|
||||
/* TODO: Should be 0 for cash-like accounts */
|
||||
newPaymentline.set({
|
||||
amount: this.getDueLeft()
|
||||
});
|
||||
return (this.get('paymentLines')).add(newPaymentline);
|
||||
},
|
||||
getName: function() {
|
||||
return this.get('name');
|
||||
},
|
||||
getTotal: function() {
|
||||
return (this.get('orderLines')).reduce((function(sum, orderLine) {
|
||||
return sum + orderLine.getPriceWithTax();
|
||||
}), 0);
|
||||
},
|
||||
getTotalTaxExcluded: function() {
|
||||
return (this.get('orderLines')).reduce((function(sum, orderLine) {
|
||||
return sum + orderLine.getPriceWithoutTax();
|
||||
}), 0);
|
||||
},
|
||||
getTax: function() {
|
||||
return (this.get('orderLines')).reduce((function(sum, orderLine) {
|
||||
return sum + orderLine.getTax();
|
||||
}), 0);
|
||||
},
|
||||
getPaidTotal: function() {
|
||||
return (this.get('paymentLines')).reduce((function(sum, paymentLine) {
|
||||
return sum + paymentLine.getAmount();
|
||||
}), 0);
|
||||
},
|
||||
getChange: function() {
|
||||
return this.getPaidTotal() - this.getTotal();
|
||||
},
|
||||
getDueLeft: function() {
|
||||
return this.getTotal() - this.getPaidTotal();
|
||||
},
|
||||
exportAsJSON: function() {
|
||||
var orderLines, paymentLines;
|
||||
orderLines = [];
|
||||
(this.get('orderLines')).each(_.bind( function(item) {
|
||||
return orderLines.push([0, 0, item.exportAsJSON()]);
|
||||
}, this));
|
||||
paymentLines = [];
|
||||
(this.get('paymentLines')).each(_.bind( function(item) {
|
||||
return paymentLines.push([0, 0, item.exportAsJSON()]);
|
||||
}, this));
|
||||
return {
|
||||
name: this.getName(),
|
||||
amount_paid: this.getPaidTotal(),
|
||||
amount_total: this.getTotal(),
|
||||
amount_tax: this.getTax(),
|
||||
amount_return: this.getChange(),
|
||||
lines: orderLines,
|
||||
statement_ids: paymentLines
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
module.OrderCollection = Backbone.Collection.extend({
|
||||
model: module.Order,
|
||||
});
|
||||
|
||||
module.Shop = Backbone.Model.extend({
|
||||
initialize: function(attributes) {
|
||||
var self = this;
|
||||
this.set({
|
||||
orders: new module.OrderCollection(),
|
||||
products: new module.ProductCollection(),
|
||||
});
|
||||
this.posmodel = attributes.posmodel;
|
||||
this.set({
|
||||
cashRegisters: new module.CashRegisterCollection(this.posmodel.get('bank_statements')),
|
||||
});
|
||||
return (this.get('orders')).bind('remove', _.bind( function(removedOrder) {
|
||||
if ((this.get('orders')).isEmpty()) {
|
||||
this.addAndSelectOrder(new module.Order({posmodel: self.posmodel}));
|
||||
}
|
||||
if ((this.get('selectedOrder')) === removedOrder) {
|
||||
return this.set({
|
||||
selectedOrder: (this.get('orders')).last()
|
||||
});
|
||||
}
|
||||
}, this));
|
||||
},
|
||||
addAndSelectOrder: function(newOrder) {
|
||||
(this.get('orders')).add(newOrder);
|
||||
return this.set({
|
||||
selectedOrder: newOrder
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
/*
|
||||
The numpad handles both the choice of the property currently being modified
|
||||
(quantity, price or discount) and the edition of the corresponding numeric value.
|
||||
*/
|
||||
module.NumpadState = Backbone.Model.extend({
|
||||
defaults: {
|
||||
buffer: "0",
|
||||
mode: "quantity"
|
||||
},
|
||||
appendNewChar: function(newChar) {
|
||||
var oldBuffer;
|
||||
oldBuffer = this.get('buffer');
|
||||
if (oldBuffer === '0') {
|
||||
this.set({
|
||||
buffer: newChar
|
||||
});
|
||||
} else if (oldBuffer === '-0') {
|
||||
this.set({
|
||||
buffer: "-" + newChar
|
||||
});
|
||||
} else {
|
||||
this.set({
|
||||
buffer: (this.get('buffer')) + newChar
|
||||
});
|
||||
}
|
||||
this.updateTarget();
|
||||
},
|
||||
deleteLastChar: function() {
|
||||
var tempNewBuffer;
|
||||
tempNewBuffer = (this.get('buffer')).slice(0, -1) || "0";
|
||||
if (isNaN(tempNewBuffer)) {
|
||||
tempNewBuffer = "0";
|
||||
}
|
||||
this.set({
|
||||
buffer: tempNewBuffer
|
||||
});
|
||||
this.updateTarget();
|
||||
},
|
||||
switchSign: function() {
|
||||
var oldBuffer;
|
||||
oldBuffer = this.get('buffer');
|
||||
this.set({
|
||||
buffer: oldBuffer[0] === '-' ? oldBuffer.substr(1) : "-" + oldBuffer
|
||||
});
|
||||
this.updateTarget();
|
||||
},
|
||||
changeMode: function(newMode) {
|
||||
this.set({
|
||||
buffer: "0",
|
||||
mode: newMode
|
||||
});
|
||||
},
|
||||
reset: function() {
|
||||
this.set({
|
||||
buffer: "0",
|
||||
mode: "quantity"
|
||||
});
|
||||
},
|
||||
updateTarget: function() {
|
||||
var bufferContent, params;
|
||||
bufferContent = this.get('buffer');
|
||||
if (bufferContent && !isNaN(bufferContent)) {
|
||||
this.trigger('setValue', parseFloat(bufferContent));
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
namespace.App = (function() {
|
||||
|
||||
function App($element, posmodel) {
|
||||
this.initialize($element, posmodel);
|
||||
}
|
||||
|
||||
App.prototype.initialize = function($element, posmodel) {
|
||||
this.posmodel = posmodel;
|
||||
this.shop = new namespace.Shop({'posmodel': posmodel});
|
||||
this.shopView = new namespace.ShopWidget(null, {
|
||||
shop: this.shop,
|
||||
'posmodel': posmodel,
|
||||
});
|
||||
this.shopView.$element = $element;
|
||||
this.shopView.start();
|
||||
this.categoryView = new namespace.CategoryWidget(null, {element_id: 'products-screen-categories', posmodel: posmodel} );
|
||||
this.categoryView.on_change_category.add_last(_.bind(this.category, this));
|
||||
this.category();
|
||||
|
||||
this.onscreenKeyboard = new namespace.OnscreenKeyboardWidget(null,{keyboard_model:'simple'});
|
||||
this.onscreenKeyboard.appendTo($(".point-of-sale #content"));
|
||||
|
||||
this.actionBar = new namespace.ActionbarWidget(null);
|
||||
this.actionBar.appendTo($(".point-of-sale #content"));
|
||||
|
||||
this.actionBar.addNewButton('left',{
|
||||
label : 'Aide',
|
||||
icon : '/point_of_sale/static/src/img/icons/png48/help-browser.png',
|
||||
});
|
||||
this.actionBar.addNewButton('left',{'label':'test'});
|
||||
this.actionBar.addNewButton('left',{'label':'kikoo', rightalign:true});
|
||||
|
||||
this.actionBar.addNewButton('right',{'label':'boo'});
|
||||
this.actionBar.addNewButton('right',{
|
||||
label : 'Payer',
|
||||
rightalign : true,
|
||||
icon : '/point_of_sale/static/src/img/icons/png48/go-next.png',
|
||||
});
|
||||
this.actionBar.addNewButton('right',{
|
||||
label : 'Ook Ook',
|
||||
rightalign : true,
|
||||
icon : '/point_of_sale/static/src/img/icons/png48/face-monkey.png',
|
||||
});
|
||||
};
|
||||
|
||||
//returns true if the code is a valid EAN codebar number by checking the control digit.
|
||||
App.checkEan = function(code){
|
||||
var st1 = code.slice();
|
||||
var st2 = st1.slice(0,st1.length-1).reverse();
|
||||
// some EAN13 barcodes have a length of 12, as they start by 0
|
||||
while (st2.length < 12) {
|
||||
st2.push(0);
|
||||
}
|
||||
var countSt3 = 1;
|
||||
var st3 = 0;
|
||||
$.each(st2, function() {
|
||||
if (countSt3%2 === 1) {
|
||||
st3 += this;
|
||||
}
|
||||
countSt3 ++;
|
||||
});
|
||||
st3 *= 3;
|
||||
var st4 = 0;
|
||||
var countSt4 = 1;
|
||||
$.each(st2, function() {
|
||||
if (countSt4%2 === 0) {
|
||||
st4 += this;
|
||||
}
|
||||
countSt4 ++;
|
||||
});
|
||||
var st5 = st3 + st4;
|
||||
var cd = (10 - (st5%10)) % 10;
|
||||
return code[code.length-1] === cd;
|
||||
};
|
||||
|
||||
// returns a product that has a packaging with an EAN matching to provided ean string.
|
||||
// returns undefined if no such product is found.
|
||||
App.getProductByEAN = function(ean, allPackages, allProducts) {
|
||||
var prefix = ean.substring(0,2);
|
||||
var scannedProductModel = undefined;
|
||||
|
||||
if (prefix in {'02':'', '22':'', '24':'', '26':'', '28':''}) {
|
||||
|
||||
// PRICE barcode
|
||||
var itemCode = ean.substring(0,7);
|
||||
var scannedPackaging = _.detect(allPackages, function(pack) { return pack.ean !== undefined && pack.ean.substring(0,7) === itemCode;});
|
||||
if (scannedPackaging !== undefined) {
|
||||
scannedProductModel = _.detect(allProducts, function(pc) { return pc.id === scannedPackaging.product_id[0];});
|
||||
scannedProductModel.list_price = Number(ean.substring(7,12))/100;
|
||||
}
|
||||
} else if (prefix in {'21':'','23':'','27':'','29':'','25':''}) {
|
||||
// WEIGHT barcode
|
||||
var weight = Number(barcode.substring(7,12))/1000;
|
||||
var itemCode = ean.substring(0,7);
|
||||
var scannedPackaging = _.detect(allPackages, function(pack) { return pack.ean !== undefined && pack.ean.substring(0,7) === itemCode;});
|
||||
if (scannedPackaging !== undefined) {
|
||||
scannedProductModel = _.detect(allProducts, function(pc) { return pc.id === scannedPackaging.product_id[0];});
|
||||
scannedProductModel.list_price *= weight;
|
||||
scannedProductModel.name += ' - ' + weight + ' Kg.';
|
||||
}
|
||||
} else {
|
||||
// UNIT barcode
|
||||
scannedProductModel = _.detect(allProducts, function(pc) { return pc.ean13 === ean;}); //TODO DOES NOT SCALE
|
||||
}
|
||||
return scannedProductModel;
|
||||
};
|
||||
|
||||
App.prototype.category = function(id) {
|
||||
var c, product_list, self = this;
|
||||
|
||||
id = !id ? 0 : id;
|
||||
|
||||
c = this.posmodel.categories[id];
|
||||
this.categoryView.ancestors = c.ancestors;
|
||||
this.categoryView.children = c.children;
|
||||
this.categoryView.renderElement();
|
||||
this.categoryView.start();
|
||||
|
||||
allProducts = this.posmodel.get('product_list');
|
||||
|
||||
allPackages = this.posmodel.get('product.packaging');
|
||||
|
||||
product_list = this.posmodel.get('product_list').filter( function(p) {
|
||||
var _ref;
|
||||
return _ref = p.pos_categ_id[0], _.indexOf(c.subtree, _ref) >= 0;
|
||||
});
|
||||
(this.shop.get('products')).reset(product_list);
|
||||
|
||||
var codeNumbers = [];
|
||||
|
||||
// The barcode readers acts as a keyboard, we catch all keyup events and try to find a
|
||||
// barcode sequence in the typed keys, then act accordingly.
|
||||
$('body').delegate('','keyup', function (e){
|
||||
|
||||
//We only care about numbers
|
||||
if (!isNaN(Number(String.fromCharCode(e.keyCode)))) {
|
||||
|
||||
// The barcode reader sends keystrokes with a specific interval.
|
||||
// We look if the typed keys fit in the interval.
|
||||
if (codeNumbers.length==0) {
|
||||
timeStamp = new Date().getTime();
|
||||
} else {
|
||||
if (lastTimeStamp + 30 < new Date().getTime()) {
|
||||
// not a barcode reader
|
||||
codeNumbers = [];
|
||||
timeStamp = new Date().getTime();
|
||||
}
|
||||
}
|
||||
codeNumbers.push(e.keyCode - 48);
|
||||
lastTimeStamp = new Date().getTime();
|
||||
if (codeNumbers.length == 13) {
|
||||
console.log('found code:', codeNumbers.join(''));
|
||||
|
||||
// a barcode reader
|
||||
if (!App.checkEan(codeNumbers)) {
|
||||
// barcode read error, raise warning
|
||||
$(QWeb.render('pos-scan-warning')).dialog({
|
||||
resizable: false,
|
||||
height:220,
|
||||
modal: true,
|
||||
title: "Warning",
|
||||
});
|
||||
}
|
||||
var selectedOrder = self.shop.get('selectedOrder');
|
||||
var scannedProductModel = App.getProductByEAN(codeNumbers.join(''),allPackages,allProducts);
|
||||
if (scannedProductModel === undefined) {
|
||||
// product not recognized, raise warning
|
||||
$(QWeb.render('pos-scan-warning')).dialog({
|
||||
resizable: false,
|
||||
height:220,
|
||||
modal: true,
|
||||
title: "Warning",
|
||||
/*
|
||||
buttons: {
|
||||
"OK": function() {
|
||||
$( this ).dialog( "close" );
|
||||
return;
|
||||
},
|
||||
}*/
|
||||
});
|
||||
} else {
|
||||
selectedOrder.addProduct(new namespace.Product(scannedProductModel));
|
||||
}
|
||||
|
||||
codeNumbers = [];
|
||||
}
|
||||
} else {
|
||||
// NaN
|
||||
codeNumbers = [];
|
||||
}
|
||||
});
|
||||
|
||||
$('.searchbox input').keyup(function() {
|
||||
var m, s;
|
||||
s = $(this).val().toLowerCase();
|
||||
if (s) {
|
||||
m = product_list.filter( function(p) {
|
||||
return p.name.toLowerCase().indexOf(s) != -1;
|
||||
});
|
||||
$('.search-clear').fadeIn();
|
||||
} else {
|
||||
m = product_list;
|
||||
$('.search-clear').fadeOut();
|
||||
}
|
||||
return (self.shop.get('products')).reset(m);
|
||||
});
|
||||
return $('.search-clear').click( function() {
|
||||
(self.shop.get('products')).reset(product_list);
|
||||
$('.searchbox input').val('').focus();
|
||||
return $('.search-clear').fadeOut();
|
||||
});
|
||||
};
|
||||
return App;
|
||||
})();
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue