71
87
$.when(this.fetch('pos.category', ['name', 'parent_id', 'child_id']),
72
this.fetch('product.product', ['name', 'list_price', 'pos_categ_id', 'taxes_id', 'product_image_small', 'ean13', 'id'], [['pos_categ_id', '!=', false]]),
73
this.fetch('product.packaging', ['product_id', 'ean']),
88
this.fetch('product.product', ['name', 'list_price', 'pos_categ_id', 'taxes_id', 'product_image_small'], [['pos_categ_id', '!=', 'false']]),
74
89
this.fetch('account.bank.statement', ['account_id', 'currency', 'journal_id', 'state', 'name'],
75
90
[['state', '=', 'open'], ['user_id', '=', this.session.uid]]),
76
91
this.fetch('account.journal', ['auto_cash', 'check_dtls', 'currency', 'name', 'type']),
212
var CashRegister = Backbone.Model.extend({
215
var CashRegisterCollection = Backbone.Collection.extend({
219
var Product = Backbone.Model.extend({
222
var ProductCollection = Backbone.Collection.extend({
226
var Category = Backbone.Model.extend({
229
var CategoryCollection = Backbone.Collection.extend({
226
var CashRegister = (function() {
227
__extends(CashRegister, Backbone.Model);
228
function CashRegister() {
229
CashRegister.__super__.constructor.apply(this, arguments);
234
var CashRegisterCollection = (function() {
235
__extends(CashRegisterCollection, Backbone.Collection);
236
function CashRegisterCollection() {
237
CashRegisterCollection.__super__.constructor.apply(this, arguments);
240
CashRegisterCollection.prototype.model = CashRegister;
241
return CashRegisterCollection;
243
var Product = (function() {
244
__extends(Product, Backbone.Model);
246
Product.__super__.constructor.apply(this, arguments);
251
var ProductCollection = (function() {
252
__extends(ProductCollection, Backbone.Collection);
253
function ProductCollection() {
254
ProductCollection.__super__.constructor.apply(this, arguments);
257
ProductCollection.prototype.model = Product;
258
return ProductCollection;
260
var Category = (function() {
261
__extends(Category, Backbone.Model);
262
function Category() {
263
Category.__super__.constructor.apply(this, arguments);
268
var CategoryCollection = (function() {
269
__extends(CategoryCollection, Backbone.Collection);
270
function CategoryCollection() {
271
CategoryCollection.__super__.constructor.apply(this, arguments);
274
CategoryCollection.prototype.model = Category;
275
return CategoryCollection;
234
278
Each Order contains zero or more Orderlines (i.e. the content of the "shopping cart".)
235
279
There should only ever be one Orderline per distinct product in an Order.
309
353
exportAsJSON: function() {
311
356
qty: this.get('quantity'),
312
357
price_unit: this.get('list_price'),
313
358
discount: this.get('discount'),
314
359
product_id: this.get('id')
319
364
var OrderlineCollection = Backbone.Collection.extend({
320
365
model: Orderline,
368
Every PaymentLine has all the attributes of the corresponding CashRegister.
370
var Paymentline = (function() {
371
__extends(Paymentline, Backbone.Model);
372
function Paymentline() {
373
Paymentline.__super__.constructor.apply(this, arguments);
323
// Every PaymentLine has all the attributes of the corresponding CashRegister.
324
var Paymentline = Backbone.Model.extend({
328
initialize: function(attributes) {
329
Backbone.Model.prototype.initialize.apply(this, arguments);
331
getAmount: function(){
376
Paymentline.prototype.defaults = {
379
Paymentline.prototype.getAmount = function() {
332
380
return this.get('amount');
334
exportAsJSON: function(){
382
Paymentline.prototype.exportAsJSON = function() {
336
385
name: db.web.datetime_to_str(new Date()),
337
386
statement_id: this.get('id'),
338
387
account_id: (this.get('account_id'))[0],
339
388
journal_id: (this.get('journal_id'))[0],
340
389
amount: this.getAmount()
345
var PaymentlineCollection = Backbone.Collection.extend({
349
var Order = Backbone.Model.extend({
395
var PaymentlineCollection = (function() {
396
__extends(PaymentlineCollection, Backbone.Collection);
397
function PaymentlineCollection() {
398
PaymentlineCollection.__super__.constructor.apply(this, arguments);
401
PaymentlineCollection.prototype.model = Paymentline;
402
return PaymentlineCollection;
404
var Order = (function() {
405
__extends(Order, Backbone.Model);
407
Order.__super__.constructor.apply(this, arguments);
410
Order.prototype.defaults = {
351
411
validated: false,
352
412
step: 'products',
354
initialize: function(attributes){
355
Backbone.Model.prototype.initialize.apply(this, arguments);
357
creationDate: new Date,
358
orderLines: new OrderlineCollection,
359
paymentLines: new PaymentlineCollection,
360
name: "Order " + this.generateUniqueId(),
414
Order.prototype.initialize = function() {
415
this.set({creationDate: new Date});
417
orderLines: new OrderlineCollection
420
paymentLines: new PaymentlineCollection
362
422
this.bind('change:validated', this.validatedChanged);
424
name: "Order " + this.generateUniqueId()
427
Order.prototype.events = {
366
428
'change:validated': 'validatedChanged'
368
validatedChanged: function() {
430
Order.prototype.validatedChanged = function() {
369
431
if (this.get("validated") && !this.previous("validated")) {
370
432
this.set({'step': 'receipt'});
373
generateUniqueId: function() {
435
Order.prototype.generateUniqueId = function() {
374
436
return new Date().getTime();
376
addProduct: function(product) {
438
Order.prototype.addProduct = function(product) {
378
440
existing = (this.get('orderLines')).get(product.id);
379
441
if (existing != null) {
394
456
amount: this.getDueLeft()
396
458
return (this.get('paymentLines')).add(newPaymentline);
398
getName: function() {
460
Order.prototype.getName = function() {
399
461
return this.get('name');
401
getTotal: function() {
463
Order.prototype.getTotal = function() {
402
464
return (this.get('orderLines')).reduce((function(sum, orderLine) {
403
465
return sum + orderLine.getPriceWithTax();
406
getTotalTaxExcluded: function() {
468
Order.prototype.getTotalTaxExcluded = function() {
407
469
return (this.get('orderLines')).reduce((function(sum, orderLine) {
408
470
return sum + orderLine.getPriceWithoutTax();
473
Order.prototype.getTax = function() {
412
474
return (this.get('orderLines')).reduce((function(sum, orderLine) {
413
475
return sum + orderLine.getTax();
416
getPaidTotal: function() {
478
Order.prototype.getPaidTotal = function() {
417
479
return (this.get('paymentLines')).reduce((function(sum, paymentLine) {
418
480
return sum + paymentLine.getAmount();
421
getChange: function() {
483
Order.prototype.getChange = function() {
422
484
return this.getPaidTotal() - this.getTotal();
424
getDueLeft: function() {
486
Order.prototype.getDueLeft = function() {
425
487
return this.getTotal() - this.getPaidTotal();
427
exportAsJSON: function() {
428
var orderLines, paymentLines;
489
Order.prototype.exportAsJSON = function() {
490
var orderLines, paymentLines, result;
430
492
(this.get('orderLines')).each(_.bind( function(item) {
431
493
return orderLines.push([0, 0, item.exportAsJSON()]);
443
505
lines: orderLines,
444
506
statement_ids: paymentLines
449
var OrderCollection = Backbone.Collection.extend({
453
var Shop = Backbone.Model.extend({
454
initialize: function() {
512
var OrderCollection = (function() {
513
__extends(OrderCollection, Backbone.Collection);
514
function OrderCollection() {
515
OrderCollection.__super__.constructor.apply(this, arguments);
518
OrderCollection.prototype.model = Order;
519
return OrderCollection;
521
var Shop = (function() {
522
__extends(Shop, Backbone.Model);
524
Shop.__super__.constructor.apply(this, arguments);
527
Shop.prototype.initialize = function() {
456
529
orders: new OrderCollection(),
457
530
products: new ProductCollection()
1181
1243
this.categoryView.on_change_category.add_last(_.bind(this.category, this));
1182
1244
this.category();
1185
1246
App.prototype.category = function(id) {
1186
var c, products, self = this;
1190
1251
c = pos.categories[id];
1191
1252
this.categoryView.ancestors = c.ancestors;
1192
1253
this.categoryView.children = c.children;
1193
1254
this.categoryView.render_element();
1194
1255
this.categoryView.start();
1195
allProducts = pos.store.get('product.product');
1196
allPackages = pos.store.get('product.packaging');
1197
1256
products = pos.store.get('product.product').filter( function(p) {
1199
1258
return _ref = p.pos_categ_id[0], _.indexOf(c.subtree, _ref) >= 0;
1201
1260
(this.shop.get('products')).reset(products);
1204
//returns true if the code is a valid EAN codebar number by checking the control digit.
1205
var checkEan = function(code) {
1206
var st1 = code.slice();
1207
var st2 = st1.slice(0,st1.length-1).reverse();
1208
// some EAN13 barcodes have a length of 12, as they start by 0
1209
while (st2.length < 12) {
1214
$.each(st2, function() {
1215
if (countSt3%2 === 1) {
1223
$.each(st2, function() {
1224
if (countSt4%2 === 0) {
1229
var st5 = st3 + st4;
1230
var cd = (10 - (st5%10)) % 10;
1231
return code[code.length-1] === cd;
1234
var codeNumbers = [];
1236
// returns a product that has a packaging with an EAN matching to provided ean string.
1237
// returns undefined if no such product is found.
1238
var getProductByEAN = function(ean) {
1239
var prefix = ean.substring(0,2);
1240
var scannedProductModel = undefined;
1241
if (prefix in {'02':'', '22':'', '24':'', '26':'', '28':''}) {
1243
var itemCode = ean.substring(0,7);
1244
var scannedPackaging = _.detect(allPackages, function(pack) { return pack.ean !== undefined && pack.ean.substring(0,7) === itemCode;});
1245
if (scannedPackaging !== undefined) {
1246
scannedProductModel = _.detect(allProducts, function(pc) { return pc.id === scannedPackaging.product_id[0];});
1247
scannedProductModel.list_price = Number(ean.substring(7,12))/100;
1249
} else if (prefix in {'21':'','23':'','27':'','29':'','25':''}) {
1251
var weight = Number(barcode.substring(7,12))/1000;
1252
var itemCode = ean.substring(0,7);
1253
var scannedPackaging = _.detect(allPackages, function(pack) { return pack.ean !== undefined && pack.ean.substring(0,7) === itemCode;});
1254
if (scannedPackaging !== undefined) {
1255
scannedProductModel = _.detect(allProducts, function(pc) { return pc.id === scannedPackaging.product_id[0];});
1256
scannedProductModel.list_price *= weight;
1257
scannedProductModel.name += ' - ' + weight + ' Kg.';
1261
scannedProductModel = _.detect(allProducts, function(pc) { return pc.ean13 === ean;}); //TODO DOES NOT SCALE
1263
return scannedProductModel;
1266
// The barcode readers acts as a keyboard, we catch all keyup events and try to find a
1267
// barcode sequence in the typed keys, then act accordingly.
1268
$('body').delegate('','keyup', function (e){
1270
//We only care about numbers
1271
if (!isNaN(Number(String.fromCharCode(e.keyCode)))) {
1273
// The barcode reader sends keystrokes with a specific interval.
1274
// We look if the typed keys fit in the interval.
1275
if (codeNumbers.length==0) {
1276
timeStamp = new Date().getTime();
1278
if (lastTimeStamp + 30 < new Date().getTime()) {
1279
// not a barcode reader
1281
timeStamp = new Date().getTime();
1284
codeNumbers.push(e.keyCode - 48);
1285
lastTimeStamp = new Date().getTime();
1286
if (codeNumbers.length == 13) {
1288
if (!checkEan(codeNumbers)) {
1289
// barcode read error, raise warning
1290
$(QWeb.render('pos-scan-warning')).dialog({
1297
$( this ).dialog( "close" );
1303
var selectedOrder = self.shop.get('selectedOrder');
1304
var scannedProductModel = getProductByEAN(codeNumbers.join(''));
1305
if (scannedProductModel === undefined) {
1306
// product not recognized, raise warning
1307
$(QWeb.render('pos-scan-warning')).dialog({
1314
$( this ).dialog( "close" );
1320
selectedOrder.addProduct(new Product(scannedProductModel));
1331
1262
$('.searchbox input').keyup(function() {
1333
1264
s = $(this).val().toLowerCase();