1416 lines
54 KiB
JavaScript
1416 lines
54 KiB
JavaScript
openerp.point_of_sale = function(db) {
|
|
|
|
db.point_of_sale = {};
|
|
|
|
var __extends = function(child, parent) {
|
|
var __hasProp = Object.prototype.hasOwnProperty;
|
|
for (var key in parent) {
|
|
if (__hasProp.call(parent, key))
|
|
child[key] = parent[key];
|
|
}
|
|
function ctor() {
|
|
this.constructor = child;
|
|
}
|
|
|
|
ctor.prototype = parent.prototype;
|
|
child.prototype = new ctor;
|
|
child.__super__ = parent.prototype;
|
|
return child;
|
|
};
|
|
|
|
var QWeb = db.web.qweb;
|
|
var qweb_template = function(template) {
|
|
return function(ctx) {
|
|
return QWeb.render(template, _.extend({}, ctx,{
|
|
'currency': pos.get('currency'),
|
|
'format_amount': function(amount) {
|
|
if (pos.get('currency').position == 'after') {
|
|
return amount + ' ' + pos.get('currency').symbol;
|
|
} else {
|
|
return pos.get('currency').symbol + ' ' + amount;
|
|
}
|
|
},
|
|
}));
|
|
};
|
|
};
|
|
var _t = db.web._t;
|
|
|
|
var DAOInterface = {
|
|
add_operation: function(operation) {},
|
|
remove_operation: function(id) {},
|
|
get_operations: function() {},
|
|
};
|
|
var LocalStorageDAO = db.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;
|
|
dataSetSearch = new db.web.DataSetSearch(null, osvModel, {}, domain);
|
|
return dataSetSearch.read_slice(fields, 0);
|
|
};
|
|
|
|
/*
|
|
Gets all the necessary data from the OpenERP web client (session, shop data etc.)
|
|
*/
|
|
var Pos = Backbone.Model.extend({
|
|
initialize: function(session, attributes) {
|
|
Backbone.Model.prototype.initialize.call(this, attributes);
|
|
this.dao = new LocalStorageDAO();
|
|
this.ready = $.Deferred();
|
|
this.flush_mutex = new $.Mutex();
|
|
this.build_tree = _.bind(this.build_tree, this);
|
|
this.session = session;
|
|
this.set({'nbr_pending_operations': 0,
|
|
'currency': {symbol: '$', position: 'after'},
|
|
'shop': {},
|
|
'company': {},
|
|
'user': {}});
|
|
|
|
var self = this;
|
|
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 db.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 db.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 db.web.Model("res.currency").get_func("read")([currency_id],
|
|
['symbol', 'position']).pipe(function(result) {
|
|
self.set({'currency': result[0]});
|
|
|
|
});
|
|
});
|
|
}), new db.web.Model("res.users").get_func("read")(this.session.uid, ['name']).pipe(function(result) {
|
|
self.set({'user': result});
|
|
}));
|
|
},
|
|
pushOrder: 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(ops) {
|
|
self.set({"nbr_pending_operations": ops.length});
|
|
if (ops.length === 0)
|
|
return $.when();
|
|
var op = ops[0].data;
|
|
var op_id = ops[0].id;
|
|
/* we prevent the default error handler and assume errors
|
|
* are a normal use case, except we stop the current iteration
|
|
*/
|
|
return new db.web.Model("pos.order").get_func("create_from_ui")([op]).fail(function(unused, event) {
|
|
event.preventDefault();
|
|
}).pipe(function() {
|
|
console.debug('saved 1 record');
|
|
self.dao.remove_operation(op_id).pipe(function() {
|
|
return self._int_flush();
|
|
});
|
|
}, function() {
|
|
return $.when();
|
|
});
|
|
});
|
|
},
|
|
categories: {},
|
|
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;
|
|
}
|
|
});
|
|
|
|
/* global variable */
|
|
var pos;
|
|
|
|
/*
|
|
---
|
|
Models
|
|
---
|
|
*/
|
|
var CashRegister = (function() {
|
|
__extends(CashRegister, Backbone.Model);
|
|
function CashRegister() {
|
|
CashRegister.__super__.constructor.apply(this, arguments);
|
|
}
|
|
|
|
return CashRegister;
|
|
})();
|
|
var CashRegisterCollection = (function() {
|
|
__extends(CashRegisterCollection, Backbone.Collection);
|
|
function CashRegisterCollection() {
|
|
CashRegisterCollection.__super__.constructor.apply(this, arguments);
|
|
}
|
|
|
|
CashRegisterCollection.prototype.model = CashRegister;
|
|
return CashRegisterCollection;
|
|
})();
|
|
var Product = (function() {
|
|
__extends(Product, Backbone.Model);
|
|
function Product() {
|
|
Product.__super__.constructor.apply(this, arguments);
|
|
}
|
|
|
|
return Product;
|
|
})();
|
|
var ProductCollection = (function() {
|
|
__extends(ProductCollection, Backbone.Collection);
|
|
function ProductCollection() {
|
|
ProductCollection.__super__.constructor.apply(this, arguments);
|
|
}
|
|
|
|
ProductCollection.prototype.model = Product;
|
|
return ProductCollection;
|
|
})();
|
|
var Category = (function() {
|
|
__extends(Category, Backbone.Model);
|
|
function Category() {
|
|
Category.__super__.constructor.apply(this, arguments);
|
|
}
|
|
|
|
return Category;
|
|
})();
|
|
var CategoryCollection = (function() {
|
|
__extends(CategoryCollection, Backbone.Collection);
|
|
function CategoryCollection() {
|
|
CategoryCollection.__super__.constructor.apply(this, arguments);
|
|
}
|
|
|
|
CategoryCollection.prototype.model = Category;
|
|
return CategoryCollection;
|
|
})();
|
|
/*
|
|
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.
|
|
*/
|
|
var Orderline = Backbone.Model.extend({
|
|
defaults: {
|
|
quantity: 1,
|
|
list_price: 0,
|
|
discount: 0
|
|
},
|
|
initialize: function(attributes) {
|
|
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 = pos.get('product_list');
|
|
var product = _.detect(product_list, function(el) {return el.id === self.get('id');});
|
|
var taxes_ids = product.taxes_id;
|
|
var taxes = pos.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() {
|
|
var result;
|
|
result = {
|
|
qty: this.get('quantity'),
|
|
price_unit: this.get('list_price'),
|
|
discount: this.get('discount'),
|
|
product_id: this.get('id')
|
|
};
|
|
return result;
|
|
},
|
|
});
|
|
var OrderlineCollection = Backbone.Collection.extend({
|
|
model: Orderline,
|
|
});
|
|
/*
|
|
Every PaymentLine has all the attributes of the corresponding CashRegister.
|
|
*/
|
|
var Paymentline = (function() {
|
|
__extends(Paymentline, Backbone.Model);
|
|
function Paymentline() {
|
|
Paymentline.__super__.constructor.apply(this, arguments);
|
|
}
|
|
|
|
Paymentline.prototype.defaults = {
|
|
amount: 0
|
|
};
|
|
Paymentline.prototype.getAmount = function() {
|
|
return this.get('amount');
|
|
};
|
|
Paymentline.prototype.exportAsJSON = function() {
|
|
var result;
|
|
result = {
|
|
name: db.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()
|
|
};
|
|
return result;
|
|
};
|
|
return Paymentline;
|
|
})();
|
|
var PaymentlineCollection = (function() {
|
|
__extends(PaymentlineCollection, Backbone.Collection);
|
|
function PaymentlineCollection() {
|
|
PaymentlineCollection.__super__.constructor.apply(this, arguments);
|
|
}
|
|
|
|
PaymentlineCollection.prototype.model = Paymentline;
|
|
return PaymentlineCollection;
|
|
})();
|
|
var Order = (function() {
|
|
__extends(Order, Backbone.Model);
|
|
function Order() {
|
|
Order.__super__.constructor.apply(this, arguments);
|
|
}
|
|
|
|
Order.prototype.defaults = {
|
|
validated: false,
|
|
step: 'products',
|
|
};
|
|
Order.prototype.initialize = function() {
|
|
this.set({creationDate: new Date});
|
|
this.set({
|
|
orderLines: new OrderlineCollection
|
|
});
|
|
this.set({
|
|
paymentLines: new PaymentlineCollection
|
|
});
|
|
this.bind('change:validated', this.validatedChanged);
|
|
return this.set({
|
|
name: "Order " + this.generateUniqueId()
|
|
});
|
|
};
|
|
Order.prototype.events = {
|
|
'change:validated': 'validatedChanged'
|
|
};
|
|
Order.prototype.validatedChanged = function() {
|
|
if (this.get("validated") && !this.previous("validated")) {
|
|
this.set({'step': 'receipt'});
|
|
}
|
|
}
|
|
Order.prototype.generateUniqueId = function() {
|
|
return new Date().getTime();
|
|
};
|
|
Order.prototype.addProduct = function(product) {
|
|
var existing;
|
|
existing = (this.get('orderLines')).get(product.id);
|
|
if (existing != null) {
|
|
existing.incrementQuantity();
|
|
} else {
|
|
var line = new Orderline(product.toJSON());
|
|
this.get('orderLines').add(line);
|
|
line.bind('killme', function() {
|
|
this.get('orderLines').remove(line);
|
|
}, this);
|
|
}
|
|
};
|
|
Order.prototype.addPaymentLine = function(cashRegister) {
|
|
var newPaymentline;
|
|
newPaymentline = new Paymentline(cashRegister);
|
|
/* TODO: Should be 0 for cash-like accounts */
|
|
newPaymentline.set({
|
|
amount: this.getDueLeft()
|
|
});
|
|
return (this.get('paymentLines')).add(newPaymentline);
|
|
};
|
|
Order.prototype.getName = function() {
|
|
return this.get('name');
|
|
};
|
|
Order.prototype.getTotal = function() {
|
|
return (this.get('orderLines')).reduce((function(sum, orderLine) {
|
|
return sum + orderLine.getPriceWithTax();
|
|
}), 0);
|
|
};
|
|
Order.prototype.getTotalTaxExcluded = function() {
|
|
return (this.get('orderLines')).reduce((function(sum, orderLine) {
|
|
return sum + orderLine.getPriceWithoutTax();
|
|
}), 0);
|
|
};
|
|
Order.prototype.getTax = function() {
|
|
return (this.get('orderLines')).reduce((function(sum, orderLine) {
|
|
return sum + orderLine.getTax();
|
|
}), 0);
|
|
};
|
|
Order.prototype.getPaidTotal = function() {
|
|
return (this.get('paymentLines')).reduce((function(sum, paymentLine) {
|
|
return sum + paymentLine.getAmount();
|
|
}), 0);
|
|
};
|
|
Order.prototype.getChange = function() {
|
|
return this.getPaidTotal() - this.getTotal();
|
|
};
|
|
Order.prototype.getDueLeft = function() {
|
|
return this.getTotal() - this.getPaidTotal();
|
|
};
|
|
Order.prototype.exportAsJSON = function() {
|
|
var orderLines, paymentLines, result;
|
|
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));
|
|
result = {
|
|
name: this.getName(),
|
|
amount_paid: this.getPaidTotal(),
|
|
amount_total: this.getTotal(),
|
|
amount_tax: this.getTax(),
|
|
amount_return: this.getChange(),
|
|
lines: orderLines,
|
|
statement_ids: paymentLines
|
|
};
|
|
return result;
|
|
};
|
|
return Order;
|
|
})();
|
|
var OrderCollection = (function() {
|
|
__extends(OrderCollection, Backbone.Collection);
|
|
function OrderCollection() {
|
|
OrderCollection.__super__.constructor.apply(this, arguments);
|
|
}
|
|
|
|
OrderCollection.prototype.model = Order;
|
|
return OrderCollection;
|
|
})();
|
|
var Shop = (function() {
|
|
__extends(Shop, Backbone.Model);
|
|
function Shop() {
|
|
Shop.__super__.constructor.apply(this, arguments);
|
|
}
|
|
|
|
Shop.prototype.initialize = function() {
|
|
this.set({
|
|
orders: new OrderCollection(),
|
|
products: new ProductCollection()
|
|
});
|
|
this.set({
|
|
cashRegisters: new CashRegisterCollection(pos.get('bank_statements')),
|
|
});
|
|
return (this.get('orders')).bind('remove', _.bind( function(removedOrder) {
|
|
if ((this.get('orders')).isEmpty()) {
|
|
this.addAndSelectOrder(new Order);
|
|
}
|
|
if ((this.get('selectedOrder')) === removedOrder) {
|
|
return this.set({
|
|
selectedOrder: (this.get('orders')).last()
|
|
});
|
|
}
|
|
}, this));
|
|
};
|
|
Shop.prototype.addAndSelectOrder = function(newOrder) {
|
|
(this.get('orders')).add(newOrder);
|
|
return this.set({
|
|
selectedOrder: newOrder
|
|
});
|
|
};
|
|
return Shop;
|
|
})();
|
|
/*
|
|
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({
|
|
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));
|
|
}
|
|
},
|
|
});
|
|
/*
|
|
---
|
|
Views
|
|
---
|
|
*/
|
|
var NumpadWidget = db.web.OldWidget.extend({
|
|
init: function(parent, options) {
|
|
this._super(parent);
|
|
this.state = new NumpadState();
|
|
},
|
|
start: function() {
|
|
this.state.bind('change:mode', this.changedMode, this);
|
|
this.changedMode();
|
|
this.$element.find('button#numpad-backspace').click(_.bind(this.clickDeleteLastChar, this));
|
|
this.$element.find('button#numpad-minus').click(_.bind(this.clickSwitchSign, this));
|
|
this.$element.find('button.number-char').click(_.bind(this.clickAppendNewChar, this));
|
|
this.$element.find('button.mode-button').click(_.bind(this.clickChangeMode, this));
|
|
},
|
|
clickDeleteLastChar: function() {
|
|
return this.state.deleteLastChar();
|
|
},
|
|
clickSwitchSign: function() {
|
|
return this.state.switchSign();
|
|
},
|
|
clickAppendNewChar: function(event) {
|
|
var newChar;
|
|
newChar = event.currentTarget.innerText || event.currentTarget.textContent;
|
|
return this.state.appendNewChar(newChar);
|
|
},
|
|
clickChangeMode: function(event) {
|
|
var newMode = event.currentTarget.attributes['data-mode'].nodeValue;
|
|
return this.state.changeMode(newMode);
|
|
},
|
|
changedMode: function() {
|
|
var mode = this.state.get('mode');
|
|
$('.selected-mode').removeClass('selected-mode');
|
|
$(_.str.sprintf('.mode-button[data-mode="%s"]', mode), this.$element).addClass('selected-mode');
|
|
},
|
|
});
|
|
/*
|
|
Gives access to the payment methods (aka. 'cash registers')
|
|
*/
|
|
var PaypadWidget = db.web.OldWidget.extend({
|
|
init: function(parent, options) {
|
|
this._super(parent);
|
|
this.shop = options.shop;
|
|
},
|
|
start: function() {
|
|
this.$element.find('button').click(_.bind(this.performPayment, this));
|
|
},
|
|
performPayment: function(event) {
|
|
if (this.shop.get('selectedOrder').get('step') === 'receipt')
|
|
return;
|
|
var cashRegister, cashRegisterCollection, cashRegisterId;
|
|
/* set correct view */
|
|
this.shop.get('selectedOrder').set({'step': 'payment'});
|
|
|
|
cashRegisterId = event.currentTarget.attributes['cash-register-id'].nodeValue;
|
|
cashRegisterCollection = this.shop.get('cashRegisters');
|
|
cashRegister = cashRegisterCollection.find(_.bind( function(item) {
|
|
return (item.get('id')) === parseInt(cashRegisterId, 10);
|
|
}, this));
|
|
return (this.shop.get('selectedOrder')).addPaymentLine(cashRegister);
|
|
},
|
|
renderElement: function() {
|
|
this.$element.empty();
|
|
return (this.shop.get('cashRegisters')).each(_.bind( function(cashRegister) {
|
|
var button = new PaymentButtonWidget();
|
|
button.model = cashRegister;
|
|
button.appendTo(this.$element);
|
|
}, this));
|
|
}
|
|
});
|
|
var PaymentButtonWidget = db.web.OldWidget.extend({
|
|
template_fct: qweb_template('pos-payment-button-template'),
|
|
renderElement: function() {
|
|
this.$element.html(this.template_fct({
|
|
id: this.model.get('id'),
|
|
name: (this.model.get('journal_id'))[1]
|
|
}));
|
|
return this;
|
|
}
|
|
});
|
|
/*
|
|
There are 3 steps in a POS workflow:
|
|
1. prepare the order (i.e. chose products, quantities etc.)
|
|
2. choose payment method(s) and amount(s)
|
|
3. validae order and print receipt
|
|
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 = db.web.OldWidget.extend({
|
|
init: function(parent, options) {
|
|
this._super(parent);
|
|
this.shop = options.shop;
|
|
this.change_order();
|
|
this.shop.bind('change:selectedOrder', this.change_order, this);
|
|
},
|
|
change_order: function() {
|
|
if (this.selected_order) {
|
|
this.selected_order.unbind('change:step', this.change_step);
|
|
}
|
|
this.selected_order = this.shop.get('selectedOrder');
|
|
if (this.selected_order) {
|
|
this.selected_order.bind('change:step', this.change_step, this);
|
|
}
|
|
this.change_step();
|
|
},
|
|
change_step: function() {
|
|
var new_step = this.selected_order ? this.selected_order.get('step') : 'products';
|
|
$('.step-screen').hide();
|
|
$('#' + new_step + '-screen').show();
|
|
},
|
|
});
|
|
/*
|
|
Shopping carts.
|
|
*/
|
|
var OrderlineWidget = db.web.OldWidget.extend({
|
|
tagName: 'tr',
|
|
template_fct: qweb_template('pos-orderline-template'),
|
|
init: function(parent, options) {
|
|
this._super(parent);
|
|
this.model = options.model;
|
|
this.model.bind('change', _.bind( function() {
|
|
this.refresh();
|
|
}, this));
|
|
this.model.bind('remove', _.bind( function() {
|
|
this.$element.remove();
|
|
}, this));
|
|
this.order = options.order;
|
|
},
|
|
start: function() {
|
|
this.$element.click(_.bind(this.clickHandler, this));
|
|
this.refresh();
|
|
},
|
|
clickHandler: function() {
|
|
this.select();
|
|
},
|
|
renderElement: function() {
|
|
this.$element.html(this.template_fct(this.model.toJSON()));
|
|
this.select();
|
|
},
|
|
refresh: function() {
|
|
this.renderElement();
|
|
var heights = _.map(this.$element.prevAll(), function(el) {return $(el).outerHeight();});
|
|
heights.push($('#current-order thead').outerHeight());
|
|
var position = _.reduce(heights, function(memo, num){ return memo + num; }, 0);
|
|
$('#current-order').scrollTop(position);
|
|
},
|
|
select: function() {
|
|
$('tr.selected').removeClass('selected');
|
|
this.$element.addClass('selected');
|
|
this.order.selected = this.model;
|
|
this.on_selected();
|
|
},
|
|
on_selected: function() {},
|
|
});
|
|
var OrderWidget = db.web.OldWidget.extend({
|
|
init: function(parent, options) {
|
|
this._super(parent);
|
|
this.shop = options.shop;
|
|
this.setNumpadState(options.numpadState);
|
|
this.shop.bind('change:selectedOrder', this.changeSelectedOrder, this);
|
|
this.bindOrderLineEvents();
|
|
},
|
|
setNumpadState: function(numpadState) {
|
|
if (this.numpadState) {
|
|
this.numpadState.unbind('setValue', this.setValue);
|
|
}
|
|
this.numpadState = numpadState;
|
|
if (this.numpadState) {
|
|
this.numpadState.bind('setValue', this.setValue, this);
|
|
this.numpadState.reset();
|
|
}
|
|
},
|
|
setValue: function(val) {
|
|
var param = {};
|
|
param[this.numpadState.get('mode')] = val;
|
|
var order = this.shop.get('selectedOrder');
|
|
if (order.get('orderLines').length !== 0) {
|
|
order.selected.set(param);
|
|
} else {
|
|
this.shop.get('selectedOrder').destroy();
|
|
}
|
|
},
|
|
changeSelectedOrder: function() {
|
|
this.currentOrderLines.unbind();
|
|
this.bindOrderLineEvents();
|
|
this.renderElement();
|
|
},
|
|
bindOrderLineEvents: function() {
|
|
this.currentOrderLines = (this.shop.get('selectedOrder')).get('orderLines');
|
|
this.currentOrderLines.bind('add', this.addLine, this);
|
|
this.currentOrderLines.bind('remove', this.renderElement, this);
|
|
},
|
|
addLine: function(newLine) {
|
|
var line = new OrderlineWidget(null, {
|
|
model: newLine,
|
|
order: this.shop.get('selectedOrder')
|
|
});
|
|
line.on_selected.add(_.bind(this.selectedLine, this));
|
|
this.selectedLine();
|
|
line.appendTo(this.$element);
|
|
this.updateSummary();
|
|
},
|
|
selectedLine: function() {
|
|
var reset = false;
|
|
if (this.currentSelected !== this.shop.get('selectedOrder').selected) {
|
|
reset = true;
|
|
}
|
|
this.currentSelected = this.shop.get('selectedOrder').selected;
|
|
if (reset && this.numpadState)
|
|
this.numpadState.reset();
|
|
this.updateSummary();
|
|
},
|
|
renderElement: function() {
|
|
this.$element.empty();
|
|
this.currentOrderLines.each(_.bind( function(orderLine) {
|
|
var line = new OrderlineWidget(null, {
|
|
model: orderLine,
|
|
order: this.shop.get('selectedOrder')
|
|
});
|
|
line.on_selected.add(_.bind(this.selectedLine, this));
|
|
line.appendTo(this.$element);
|
|
}, this));
|
|
this.updateSummary();
|
|
},
|
|
updateSummary: function() {
|
|
var currentOrder, tax, total, totalTaxExcluded;
|
|
currentOrder = this.shop.get('selectedOrder');
|
|
total = currentOrder.getTotal();
|
|
totalTaxExcluded = currentOrder.getTotalTaxExcluded();
|
|
tax = currentOrder.getTax();
|
|
$('#subtotal').html(totalTaxExcluded.toFixed(2)).hide().fadeIn();
|
|
$('#tax').html(tax.toFixed(2)).hide().fadeIn();
|
|
$('#total').html(total.toFixed(2)).hide().fadeIn();
|
|
},
|
|
});
|
|
/*
|
|
"Products" step.
|
|
*/
|
|
var CategoryWidget = db.web.OldWidget.extend({
|
|
start: function() {
|
|
this.$element.find(".oe_pos_categories_list a").click(_.bind(this.changeCategory, this));
|
|
},
|
|
template_fct: qweb_template('pos-category-template'),
|
|
renderElement: function() {
|
|
var self = this;
|
|
var c;
|
|
this.$element.html(this.template_fct({
|
|
breadcrumb: (function() {
|
|
var _i, _len, _results;
|
|
_results = [];
|
|
for (_i = 0, _len = self.ancestors.length; _i < _len; _i++) {
|
|
c = self.ancestors[_i];
|
|
_results.push(pos.categories[c]);
|
|
}
|
|
return _results;
|
|
})(),
|
|
categories: (function() {
|
|
var _i, _len, _results;
|
|
_results = [];
|
|
for (_i = 0, _len = self.children.length; _i < _len; _i++) {
|
|
c = self.children[_i];
|
|
_results.push(pos.categories[c]);
|
|
}
|
|
return _results;
|
|
})()
|
|
}));
|
|
},
|
|
changeCategory: function(a) {
|
|
var id = $(a.target).data("category-id");
|
|
this.on_change_category(id);
|
|
},
|
|
on_change_category: function(id) {},
|
|
});
|
|
var ProductWidget = db.web.OldWidget.extend({
|
|
tagName:'li',
|
|
template_fct: qweb_template('pos-product-template'),
|
|
init: function(parent, options) {
|
|
this._super(parent);
|
|
this.model = options.model;
|
|
this.shop = options.shop;
|
|
},
|
|
start: function(options) {
|
|
$("a", this.$element).click(_.bind(this.addToOrder, this));
|
|
},
|
|
addToOrder: function(event) {
|
|
/* Preserve the category URL */
|
|
event.preventDefault();
|
|
return (this.shop.get('selectedOrder')).addProduct(this.model);
|
|
},
|
|
renderElement: function() {
|
|
this.$element.addClass("product");
|
|
this.$element.html(this.template_fct(this.model.toJSON()));
|
|
return this;
|
|
},
|
|
});
|
|
var ProductListWidget = db.web.OldWidget.extend({
|
|
init: function(parent, options) {
|
|
this._super(parent);
|
|
this.model = options.model;
|
|
this.shop = options.shop;
|
|
this.shop.get('products').bind('reset', this.renderElement, this);
|
|
},
|
|
renderElement: function() {
|
|
this.$element.empty();
|
|
(this.shop.get('products')).each(_.bind( function(product) {
|
|
var p = new ProductWidget(null, {
|
|
model: product,
|
|
shop: this.shop
|
|
});
|
|
p.appendTo(this.$element);
|
|
}, this));
|
|
return this;
|
|
},
|
|
});
|
|
/*
|
|
"Payment" step.
|
|
*/
|
|
var PaymentlineWidget = db.web.OldWidget.extend({
|
|
tagName: 'tr',
|
|
template_fct: qweb_template('pos-paymentline-template'),
|
|
init: function(parent, options) {
|
|
this._super(parent);
|
|
this.model = options.model;
|
|
this.model.bind('change', this.changedAmount, this);
|
|
},
|
|
on_delete: function() {},
|
|
changeAmount: function(event) {
|
|
var newAmount;
|
|
newAmount = event.currentTarget.value;
|
|
if (newAmount && !isNaN(newAmount)) {
|
|
this.amount = parseFloat(newAmount);
|
|
this.model.set({
|
|
amount: this.amount,
|
|
});
|
|
}
|
|
},
|
|
changedAmount: function() {
|
|
if (this.amount !== this.model.get('amount'))
|
|
this.renderElement();
|
|
},
|
|
renderElement: function() {
|
|
this.amount = this.model.get('amount');
|
|
this.$element.html(this.template_fct({
|
|
name: (this.model.get('journal_id'))[1],
|
|
amount: this.amount,
|
|
}));
|
|
this.$element.addClass('paymentline');
|
|
$('input', this.$element).keyup(_.bind(this.changeAmount, this));
|
|
$('.delete-payment-line', this.$element).click(this.on_delete);
|
|
},
|
|
});
|
|
var PaymentWidget = db.web.OldWidget.extend({
|
|
init: function(parent, options) {
|
|
this._super(parent);
|
|
this.model = options.model;
|
|
this.shop = options.shop;
|
|
this.shop.bind('change:selectedOrder', this.changeSelectedOrder, this);
|
|
this.bindPaymentLineEvents();
|
|
this.bindOrderLineEvents();
|
|
},
|
|
paymentLineList: function() {
|
|
return this.$element.find('#paymentlines');
|
|
},
|
|
start: function() {
|
|
$('button#validate-order', this.$element).click(_.bind(this.validateCurrentOrder, this));
|
|
$('.oe_back_to_products', this.$element).click(_.bind(this.back, this));
|
|
},
|
|
back: function() {
|
|
this.shop.get('selectedOrder').set({"step": "products"});
|
|
},
|
|
validateCurrentOrder: function() {
|
|
var callback, currentOrder;
|
|
currentOrder = this.shop.get('selectedOrder');
|
|
$('button#validate-order', this.$element).attr('disabled', 'disabled');
|
|
pos.pushOrder(currentOrder.exportAsJSON()).then(_.bind(function() {
|
|
$('button#validate-order', this.$element).removeAttr('disabled');
|
|
return currentOrder.set({
|
|
validated: true
|
|
});
|
|
}, this));
|
|
},
|
|
bindPaymentLineEvents: function() {
|
|
this.currentPaymentLines = (this.shop.get('selectedOrder')).get('paymentLines');
|
|
this.currentPaymentLines.bind('add', this.addPaymentLine, this);
|
|
this.currentPaymentLines.bind('remove', this.renderElement, this);
|
|
this.currentPaymentLines.bind('all', this.updatePaymentSummary, this);
|
|
},
|
|
bindOrderLineEvents: function() {
|
|
this.currentOrderLines = (this.shop.get('selectedOrder')).get('orderLines');
|
|
this.currentOrderLines.bind('all', this.updatePaymentSummary, this);
|
|
},
|
|
changeSelectedOrder: function() {
|
|
this.currentPaymentLines.unbind();
|
|
this.bindPaymentLineEvents();
|
|
this.currentOrderLines.unbind();
|
|
this.bindOrderLineEvents();
|
|
this.renderElement();
|
|
},
|
|
addPaymentLine: function(newPaymentLine) {
|
|
var x = new PaymentlineWidget(null, {
|
|
model: newPaymentLine
|
|
});
|
|
x.on_delete.add(_.bind(this.deleteLine, this, x));
|
|
x.appendTo(this.paymentLineList());
|
|
},
|
|
renderElement: function() {
|
|
this.paymentLineList().empty();
|
|
this.currentPaymentLines.each(_.bind( function(paymentLine) {
|
|
this.addPaymentLine(paymentLine);
|
|
}, this));
|
|
this.updatePaymentSummary();
|
|
},
|
|
deleteLine: function(lineWidget) {
|
|
this.currentPaymentLines.remove([lineWidget.model]);
|
|
},
|
|
updatePaymentSummary: function() {
|
|
var currentOrder, dueTotal, paidTotal, remaining, remainingAmount;
|
|
currentOrder = this.shop.get('selectedOrder');
|
|
paidTotal = currentOrder.getPaidTotal();
|
|
dueTotal = currentOrder.getTotal();
|
|
this.$element.find('#payment-due-total').html(dueTotal.toFixed(2));
|
|
this.$element.find('#payment-paid-total').html(paidTotal.toFixed(2));
|
|
remainingAmount = dueTotal - paidTotal;
|
|
remaining = remainingAmount > 0 ? 0 : (-remainingAmount).toFixed(2);
|
|
$('#payment-remaining').html(remaining);
|
|
},
|
|
setNumpadState: function(numpadState) {
|
|
if (this.numpadState) {
|
|
this.numpadState.unbind('setValue', this.setValue);
|
|
this.numpadState.unbind('change:mode', this.setNumpadMode);
|
|
}
|
|
this.numpadState = numpadState;
|
|
if (this.numpadState) {
|
|
this.numpadState.bind('setValue', this.setValue, this);
|
|
this.numpadState.bind('change:mode', this.setNumpadMode, this);
|
|
this.numpadState.reset();
|
|
this.setNumpadMode();
|
|
}
|
|
},
|
|
setNumpadMode: function() {
|
|
this.numpadState.set({mode: 'payment'});
|
|
},
|
|
setValue: function(val) {
|
|
this.currentPaymentLines.last().set({amount: val});
|
|
},
|
|
});
|
|
var ReceiptWidget = db.web.OldWidget.extend({
|
|
init: function(parent, options) {
|
|
this._super(parent);
|
|
this.model = options.model;
|
|
this.shop = options.shop;
|
|
this.user = pos.get('user');
|
|
this.company = pos.get('company');
|
|
this.shop_obj = pos.get('shop');
|
|
},
|
|
start: function() {
|
|
this.shop.bind('change:selectedOrder', this.changeSelectedOrder, this);
|
|
this.changeSelectedOrder();
|
|
},
|
|
renderElement: function() {
|
|
this.$element.html(qweb_template('pos-receipt-view'));
|
|
$('button#pos-finish-order', this.$element).click(_.bind(this.finishOrder, this));
|
|
$('button#print-the-ticket', this.$element).click(_.bind(this.print, this));
|
|
},
|
|
print: function() {
|
|
window.print();
|
|
},
|
|
finishOrder: function() {
|
|
this.shop.get('selectedOrder').destroy();
|
|
},
|
|
changeSelectedOrder: function() {
|
|
if (this.currentOrderLines)
|
|
this.currentOrderLines.unbind();
|
|
this.currentOrderLines = (this.shop.get('selectedOrder')).get('orderLines');
|
|
this.currentOrderLines.bind('add', this.refresh, this);
|
|
this.currentOrderLines.bind('change', this.refresh, this);
|
|
this.currentOrderLines.bind('remove', this.refresh, this);
|
|
if (this.currentPaymentLines)
|
|
this.currentPaymentLines.unbind();
|
|
this.currentPaymentLines = (this.shop.get('selectedOrder')).get('paymentLines');
|
|
this.currentPaymentLines.bind('all', this.refresh, this);
|
|
this.refresh();
|
|
},
|
|
refresh: function() {
|
|
this.currentOrder = this.shop.get('selectedOrder');
|
|
$('.pos-receipt-container', this.$element).html(qweb_template('pos-ticket')({widget:this}));
|
|
},
|
|
});
|
|
var OrderButtonWidget = db.web.OldWidget.extend({
|
|
tagName: 'li',
|
|
template_fct: qweb_template('pos-order-selector-button-template'),
|
|
init: function(parent, options) {
|
|
this._super(parent);
|
|
this.order = options.order;
|
|
this.shop = options.shop;
|
|
this.order.bind('destroy', _.bind( function() {
|
|
this.destroy();
|
|
}, this));
|
|
this.shop.bind('change:selectedOrder', _.bind( function(shop) {
|
|
var selectedOrder;
|
|
selectedOrder = shop.get('selectedOrder');
|
|
if (this.order === selectedOrder) {
|
|
this.setButtonSelected();
|
|
}
|
|
}, this));
|
|
},
|
|
start: function() {
|
|
$('button.select-order', this.$element).click(_.bind(this.selectOrder, this));
|
|
$('button.close-order', this.$element).click(_.bind(this.closeOrder, this));
|
|
},
|
|
selectOrder: function(event) {
|
|
this.shop.set({
|
|
selectedOrder: this.order
|
|
});
|
|
},
|
|
setButtonSelected: function() {
|
|
$('.selected-order').removeClass('selected-order');
|
|
this.$element.addClass('selected-order');
|
|
},
|
|
closeOrder: function(event) {
|
|
this.order.destroy();
|
|
},
|
|
renderElement: function() {
|
|
this.$element.html(this.template_fct({widget:this}));
|
|
this.$element.addClass('order-selector-button');
|
|
}
|
|
});
|
|
var ShopWidget = db.web.OldWidget.extend({
|
|
init: function(parent, options) {
|
|
this._super(parent);
|
|
this.shop = options.shop;
|
|
},
|
|
start: function() {
|
|
$('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);
|
|
this.productListView = new ProductListWidget(null, {
|
|
shop: this.shop
|
|
});
|
|
this.productListView.$element = $("#products-screen-ol");
|
|
this.productListView.renderElement();
|
|
this.productListView.start();
|
|
this.paypadView = new PaypadWidget(null, {
|
|
shop: this.shop
|
|
});
|
|
this.paypadView.$element = $('#paypad');
|
|
this.paypadView.renderElement();
|
|
this.paypadView.start();
|
|
this.numpadView = new NumpadWidget(null);
|
|
this.numpadView.$element = $('#numpad');
|
|
this.numpadView.start();
|
|
this.orderView = new OrderWidget(null, {
|
|
shop: this.shop,
|
|
});
|
|
this.orderView.$element = $('#current-order-content');
|
|
this.orderView.start();
|
|
this.paymentView = new PaymentWidget(null, {
|
|
shop: this.shop
|
|
});
|
|
this.paymentView.$element = $('#payment-screen');
|
|
this.paymentView.renderElement();
|
|
this.paymentView.start();
|
|
this.receiptView = new ReceiptWidget(null, {
|
|
shop: this.shop,
|
|
});
|
|
this.receiptView.replace($('#receipt-screen'));
|
|
this.stepSwitcher = new StepSwitcher(this, {shop: this.shop});
|
|
this.shop.bind('change:selectedOrder', this.changedSelectedOrder, this);
|
|
this.changedSelectedOrder();
|
|
},
|
|
createNewOrder: function() {
|
|
var newOrder;
|
|
newOrder = new Order;
|
|
(this.shop.get('orders')).add(newOrder);
|
|
this.shop.set({
|
|
selectedOrder: newOrder
|
|
});
|
|
},
|
|
orderAdded: function(newOrder) {
|
|
var newOrderButton;
|
|
newOrderButton = new OrderButtonWidget(null, {
|
|
order: newOrder,
|
|
shop: this.shop
|
|
});
|
|
newOrderButton.appendTo($('#orders'));
|
|
newOrderButton.selectOrder();
|
|
},
|
|
changedSelectedOrder: function() {
|
|
if (this.currentOrder) {
|
|
this.currentOrder.unbind('change:step', this.changedStep);
|
|
}
|
|
this.currentOrder = this.shop.get('selectedOrder');
|
|
this.currentOrder.bind('change:step', this.changedStep, this);
|
|
this.changedStep();
|
|
},
|
|
changedStep: function() {
|
|
var step = this.currentOrder.get('step');
|
|
this.orderView.setNumpadState(null);
|
|
this.paymentView.setNumpadState(null);
|
|
if (step === 'products') {
|
|
this.orderView.setNumpadState(this.numpadView.state);
|
|
} else if (step === 'payment') {
|
|
this.paymentView.setNumpadState(this.numpadView.state);
|
|
}
|
|
},
|
|
});
|
|
var App = (function() {
|
|
function App($element) {
|
|
this.initialize($element);
|
|
}
|
|
|
|
App.prototype.initialize = function($element) {
|
|
this.shop = new Shop;
|
|
this.shopView = new ShopWidget(null, {
|
|
shop: this.shop
|
|
});
|
|
this.shopView.$element = $element;
|
|
this.shopView.start();
|
|
this.categoryView = new CategoryWidget(null, 'products-screen-categories');
|
|
this.categoryView.on_change_category.add_last(_.bind(this.category, this));
|
|
this.category();
|
|
};
|
|
App.prototype.category = function(id) {
|
|
var c, product_list;
|
|
if (id == null) {
|
|
id = 0;
|
|
}
|
|
c = pos.categories[id];
|
|
this.categoryView.ancestors = c.ancestors;
|
|
this.categoryView.children = c.children;
|
|
this.categoryView.renderElement();
|
|
this.categoryView.start();
|
|
product_list = pos.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 self = this;
|
|
$('.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;
|
|
})();
|
|
|
|
db.point_of_sale.SynchNotification = db.web.OldWidget.extend({
|
|
template: "pos-synch-notification",
|
|
init: function() {
|
|
this._super.apply(this, arguments);
|
|
this.nbr_pending = 0;
|
|
},
|
|
renderElement: function() {
|
|
this._super.apply(this, arguments);
|
|
$('.oe_pos_synch-notification-button', this.$element).click(this.on_synch);
|
|
},
|
|
on_change_nbr_pending: function(nbr_pending) {
|
|
this.nbr_pending = nbr_pending;
|
|
this.renderElement();
|
|
},
|
|
on_synch: function() {}
|
|
});
|
|
|
|
db.web.client_actions.add('pos.ui', 'db.point_of_sale.PointOfSale');
|
|
db.point_of_sale.PointOfSale = db.web.OldWidget.extend({
|
|
init: function() {
|
|
this._super.apply(this, arguments);
|
|
|
|
if (pos)
|
|
throw "It is not possible to instantiate multiple instances "+
|
|
"of the point of sale at the same time.";
|
|
pos = new Pos(this.session);
|
|
},
|
|
start: function() {
|
|
var self = this;
|
|
return pos.ready.then(_.bind(function() {
|
|
this.renderElement();
|
|
this.synch_notification = new db.point_of_sale.SynchNotification(this);
|
|
this.synch_notification.replace($('.oe_pos_synch-notification', this.$element));
|
|
this.synch_notification.on_synch.add(_.bind(pos.flush, pos));
|
|
|
|
pos.bind('change:nbr_pending_operations', this.changed_pending_operations, this);
|
|
this.changed_pending_operations();
|
|
|
|
this.$element.find("#loggedas button").click(function() {
|
|
self.try_close();
|
|
});
|
|
|
|
pos.app = new App(self.$element);
|
|
db.webclient.set_content_full_screen(true);
|
|
|
|
if (pos.get('bank_statements').length === 0)
|
|
return new db.web.Model("ir.model.data").get_func("search_read")([['name', '=', 'action_pos_open_statement']], ['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.result;
|
|
this.do_action(action);
|
|
}, this));
|
|
}, this));
|
|
}, this));
|
|
},
|
|
render: function() {
|
|
return qweb_template("PointOfSale")();
|
|
},
|
|
changed_pending_operations: function () {
|
|
this.synch_notification.on_change_nbr_pending(pos.get('nbr_pending_operations'));
|
|
},
|
|
try_close: function() {
|
|
pos.flush().then(_.bind(function() {
|
|
var close = _.bind(this.close, this);
|
|
if (pos.get('nbr_pending_operations') > 0) {
|
|
var confirm = false;
|
|
$(QWeb.render('pos-close-warning')).dialog({
|
|
resizable: false,
|
|
height:160,
|
|
modal: true,
|
|
title: "Warning",
|
|
buttons: {
|
|
"Yes": function() {
|
|
confirm = true;
|
|
$( this ).dialog( "close" );
|
|
},
|
|
"No": function() {
|
|
$( this ).dialog( "close" );
|
|
}
|
|
},
|
|
close: function() {
|
|
if (confirm)
|
|
close();
|
|
}
|
|
});
|
|
} else {
|
|
close();
|
|
}
|
|
}, this));
|
|
},
|
|
close: function() {
|
|
return new db.web.Model("ir.model.data").get_func("search_read")([['name', '=', 'action_pos_close_statement']], ['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.result;
|
|
action.context = _.extend(action.context || {}, {'cancel_action': {type: 'ir.actions.client', tag: 'default_home'}});
|
|
this.do_action(action);
|
|
}, this));
|
|
}, this));
|
|
},
|
|
destroy: function() {
|
|
db.webclient.set_content_full_screen(false);
|
|
pos = undefined;
|
|
this._super();
|
|
}
|
|
});
|
|
}
|