diff --git a/addons/point_of_sale/static/src/js/pos.js.THIS b/addons/point_of_sale/static/src/js/pos.js.THIS deleted file mode 100644 index 8605e8cac9c..00000000000 --- a/addons/point_of_sale/static/src/js/pos.js.THIS +++ /dev/null @@ -1,1415 +0,0 @@ -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(); - } - }); -}