diff --git a/accounts/doctype/sales_invoice/pos.js b/accounts/doctype/sales_invoice/pos.js index 5045530aa9..c27adc3a57 100644 --- a/accounts/doctype/sales_invoice/pos.js +++ b/accounts/doctype/sales_invoice/pos.js @@ -5,10 +5,63 @@ erpnext.POS = Class.extend({ init: function(wrapper, frm) { this.wrapper = wrapper; this.frm = frm; - this.wrapper.html('
\ -
\ -
'); - + this.wrapper.html('
\ +
\ +
\ +
\ +
\ +
\ + \ +
\ +
\ + \ +
\ +
\ +
 
\ +
\ + \ + \ + \ + \ + \ + \ + \ +
Item#RateAmount
\ +
\ + \ +
\ +
\ +
\ +
 
\ +
\ +
Net Total
\ +
 
\ +
\ +
\ +
Tax
\ +
 
\ +
\ +
\ +
Grand Total
\ +
 
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
'); + this.make(); var me = this; @@ -16,10 +69,20 @@ erpnext.POS = Class.extend({ me.refresh(); }); + this.wrapper.find(".delete-items").on("click", function() { + me.remove_selected_item(); + }); + + this.wrapper.find(".make-payment").on("click", function() { + me.make_payment(); + }); }, make: function() { this.make_customer(); - this.make_items(); + this.make_item_group(); + this.make_search(); + this.make_barcode(); + this.make_item_list(); }, make_customer: function() { var me = this; @@ -36,25 +99,272 @@ erpnext.POS = Class.extend({ this.customer.$input.on("change", function() { if(!me.customer.autocomplete_open) wn.model.set_value("Sales Invoice", me.frm.docname, "customer", this.value); - }); - }, - make_items: function() { - var me = this; - this.wrapper.find(".btn-add").click(function() { - var child = wn.model.add_child(me.frm.doc, "Sales Invoice Item", "entries"); - child.item_code = "Test Item"; - me.frm.cscript.item_code(me.frm.doc, child.doctype, child.name); }); }, + make_item_group: function() { + var me = this; + this.item_group = wn.ui.form.make_control({ + df: { + "fieldtype": "Link", + "options": "Item Group", + "label": "Item Group", + "fieldname": "pos_item_group" + }, + parent: this.wrapper.find(".item-group-area") + }); + this.item_group.make_input(); + this.item_group.$input.on("change", function() { + if(!me.item_group.autocomplete_open) + me.make_item_list(); + }); + }, + make_search: function() { + var me = this; + this.search = wn.ui.form.make_control({ + df: { + "fieldtype": "Link", + "options": "Item", + "label": "Item", + "fieldname": "pos_item" + }, + parent: this.wrapper.find(".search-area") + }); + this.search.make_input(); + this.search.$input.on("change", function() { + if(!me.search.autocomplete_open) + me.make_item_list(); + }); + }, + make_barcode: function() { + var me = this; + this.barcode = wn.ui.form.make_control({ + df: { + "fieldtype": "Data", + "label": "Barcode", + "fieldname": "pos_barcode" + }, + parent: this.wrapper.find(".barcode-area") + }); + this.barcode.make_input(); + this.barcode.$input.on("change", function() { + me.add_item_thru_barcode(); + }); + }, + make_item_list: function() { + var me = this; + wn.call({ + method: 'accounts.doctype.sales_invoice.pos.get_items', + args: { + price_list: cur_frm.doc.selling_price_list, + item_group: this.item_group.$input.val(), + item: this.search.$input.val() + }, + callback: function(r) { + var $wrap = me.wrapper.find(".item-list"); + me.wrapper.find(".item-list").empty(); + $.each(r.message, function(index, obj) { + if (obj.image) + image = ""; + else + image = "
"; + + $(repl('
\ + \ + \ + \ + \ + \ + \ +
%(item_image)s
%(item_code)s%(item_price)s
%(item_name)s
', + { + item_code: obj.name, + item_price: format_currency(obj.ref_rate, obj.ref_currency), + item_name: obj.item_name, + item_image: image + })).appendTo($wrap); + }); + + $("div.item").on("click", function() { + me.add_to_cart($(this).find("a").attr("data-item_code")); + }); + } + }); + }, + add_to_cart: function(item_code) { + var me = this; + var caught = false; + + // get no_of_items + no_of_items = me.wrapper.find("#cart tr").length; + + // check whether the item is already added + if (no_of_items != 0) { + $.each(wn.model.get_children("Sales Invoice Item", this.frm.doc.name, "entries", + "Sales Invoice"), function(i, d) { + if (d.item_code == item_code) + caught = true; + }); + } + + // if duplicate row then append the qty + if (caught) { + me.update_qty(item_code, 1); + } + else { + var child = wn.model.add_child(me.frm.doc, "Sales Invoice Item", "entries"); + child.item_code = item_code; + me.frm.cscript.item_code(me.frm.doc, child.doctype, child.name); + me.refresh(); + } + }, + update_qty: function(item_code, qty) { + var me = this; + $.each(wn.model.get_children("Sales Invoice Item", this.frm.doc.name, "entries", + "Sales Invoice"), function(i, d) { + if (d.item_code == item_code) { + if (qty == 1) + d.qty += 1; + else + d.qty = qty; + + me.frm.cscript.qty(me.frm.doc, d.doctype, d.name); + } + }); + me.refresh(); + }, refresh: function() { var me = this; this.customer.set_input(this.frm.doc.customer); - + this.barcode.set_input(""); + // add items - var $items = me.wrapper.find(".item-area").empty(); + var $items = me.wrapper.find("#cart").empty(); + $.each(wn.model.get_children("Sales Invoice Item", this.frm.doc.name, "entries", - "Sales Invoice"), function(i, d) { - $(repl("
%(item_code)s
", d)).appendTo($items); + "Sales Invoice"), function(i, d) { + $(repl('\ + %(item_code)s
%(item_name)s\ + \ + %(rate)s\ + %(amount)s', + { + item_code: d.item_code, + item_name: d.item_name, + qty: d.qty, + rate: format_currency(d.ref_rate, cur_frm.doc.price_list_currency), + amount: format_currency(d.export_amount, cur_frm.doc.price_list_currency) + } + )).appendTo($items); + }); + + // set totals + this.wrapper.find(".net-total").text(format_currency(this.frm.doc.net_total_export, + cur_frm.doc.price_list_currency)); + this.wrapper.find(".tax").text(format_currency(this.frm.doc.other_charges_total_export, + cur_frm.doc.price_list_currency)); + this.wrapper.find(".grand-total").text(format_currency(this.frm.doc.grand_total_export, + cur_frm.doc.price_list_currency)); + + // append quantity to the respective item after change from input box + $("input.qty").on("change", function() { + var item_code = $(this).closest("tr")[0].id; + me.update_qty(item_code, $(this).val()); + }); + + // on td click highlight the respective row + $("td").on("click", function() { + var row = $(this).closest("tr"); + if (row.attr("data-selected") == "false") { + row.attr("class", "warning"); + row.attr("data-selected", "true"); + } + else { + row.prop("class", null); + row.attr("data-selected", "false"); + } + }); + }, + add_item_thru_barcode: function() { + var me = this; + wn.call({ + method: 'accounts.doctype.sales_invoice.pos.get_item_from_barcode', + args: {barcode: this.barcode.$input.val()}, + callback: function(r) { + if (r.message) { + me.add_to_cart(r.message[0].name); + me.refresh(); + } + else + msgprint(wn._("Invalid Barcode")); + } + }); + }, + remove_selected_item: function() { + var me = this; + var selected_items = []; + var no_of_items = $("#cart tr").length; + for(var x=0; x<=no_of_items - 1; x++) { + var row = $("#cart tr:eq(" + x + ")"); + if(row.attr("data-selected") == "true") { + selected_items.push(row.attr("id")); + } + } + + if (!selected_items[0]) + msgprint(wn._("Please select any item to remove it")); + + var child = wn.model.get_children("Sales Invoice Item", this.frm.doc.name, "entries", + "Sales Invoice"); + $.each(child, function(i, d) { + for (var i in selected_items) { + if (d.item_code == selected_items[i]) { + wn.model.clear_doc(d.doctype, d.name); + } + } + }); + cur_frm.fields_dict["entries"].grid.refresh(); + me.refresh(); + }, + make_payment: function() { + var me = this; + var no_of_items = $("#cart tr").length; + var mode_of_payment = []; + + if (no_of_items == 0) + msgprint(wn._("Payment cannot be made for empty cart")); + else { + wn.call({ + method: 'accounts.doctype.sales_invoice.pos.get_mode_of_payment', + callback: function(r) { + for (x=0; x<=r.message.length - 1; x++) { + mode_of_payment.push(r.message[x].name); + } + + // show payment wizard + var dialog = new wn.ui.Dialog({ + width: 400, + title: 'Payment', + fields: [ + {fieldtype:'Data', fieldname:'total_amount', label:'Total Amount', read_only:1}, + {fieldtype:'Select', fieldname:'mode_of_payment', label:'Mode of Payment', + options:mode_of_payment.join('\n'), reqd: 1}, + {fieldtype:'Button', fieldname:'pay', label:'Pay'} + ] + }); + dialog.set_values({ + "total_amount": $(".grand-total").text() + }); + dialog.show(); + + dialog.fields_dict.pay.input.onclick = function() { + cur_frm.set_value("mode_of_payment", dialog.get_values().mode_of_payment); + cur_frm.set_value("paid_amount", dialog.get_values().total_amount); + cur_frm.save(); + dialog.hide(); + me.refresh(); + }; + } }); - } -}) \ No newline at end of file + } + }, +}); \ No newline at end of file diff --git a/accounts/doctype/sales_invoice/pos.py b/accounts/doctype/sales_invoice/pos.py new file mode 100644 index 0000000000..f7dacf19a6 --- /dev/null +++ b/accounts/doctype/sales_invoice/pos.py @@ -0,0 +1,28 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import webnotes + +@webnotes.whitelist() +def get_items(price_list, item=None, item_group=None): + condition = "" + + if item_group and item_group != "All Item Groups": + condition = "where i.item_group='%s'" % item_group + + if item: + condition = "where i.name='%s'" % item + + return webnotes.conn.sql("""select i.name, i.item_name, i.image, ip.ref_rate, + ip.ref_currency from `tabItem` i LEFT JOIN `tabItem Price` ip ON ip.parent=i.name + and ip.price_list=%s %s""" % ('%s', condition), (price_list), as_dict=1) + +@webnotes.whitelist() +def get_item_from_barcode(barcode): + return webnotes.conn.sql("""select name from `tabItem` where barcode=%s""", + (barcode), as_dict=1) + +@webnotes.whitelist() +def get_mode_of_payment(): + return webnotes.conn.sql("""select name from `tabMode of Payment`""", as_dict=1) \ No newline at end of file diff --git a/accounts/doctype/sales_invoice/sales_invoice.js b/accounts/doctype/sales_invoice/sales_invoice.js index 0b25a683f9..3baa226884 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.js +++ b/accounts/doctype/sales_invoice/sales_invoice.js @@ -12,7 +12,7 @@ cur_frm.pformat.print_heading = 'Invoice'; wn.require('app/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js'); wn.require('app/utilities/doctype/sms_control/sms_control.js'); wn.require('app/selling/doctype/sales_common/sales_common.js'); -// wn.require('app/accounts/doctype/sales_invoice/pos.js'); +wn.require('app/accounts/doctype/sales_invoice/pos.js'); wn.provide("erpnext.accounts"); erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.extend({ @@ -25,9 +25,11 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte this.frm.set_df_property("debit_to", "print_hide", 0); } } - // if(this.frm.doc.is_pos && this.frm.doc.docstatus===0) { - // cur_frm.cscript.toggle_pos(true); - // } + + pos_view = cint(sys_defaults.fs_pos_view); + if(this.frm.doc.is_pos && this.frm.doc.docstatus===0 && pos_view===1) { + cur_frm.cscript.toggle_pos(true); + } }, refresh: function(doc, dt, dn) { @@ -92,32 +94,52 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte } }); }); - - // cur_frm.add_custom_button(wn._("POS View"), function() { - // cur_frm.cscript.toggle_pos(); - // }, 'icon-desktop'); - + + if (cint(sys_defaults.fs_pos_view)===1) + cur_frm.cscript.pos_btn(); } }, + pos_btn: function() { + if(cur_frm.$pos_btn) cur_frm.$pos_btn.remove(); + + if(!cur_frm.pos_active) { + var btn_label = wn._("POS View"), + icon = "icon-desktop"; + } else { + var btn_label = wn._("Invoice View"), + icon = "icon-file-text"; + } + + cur_frm.add_custom_button(btn_label, function() { + cur_frm.$pos_btn = $(this); + cur_frm.cscript.toggle_pos(); + cur_frm.cscript.pos_btn(); + }, icon); + }, + toggle_pos: function(show) { - if((show===true && cur_frm.pos_active) || (show===false && !cur_frm.pos_active)) return; - - // make pos - if(!cur_frm.pos) { - cur_frm.layout.add_view("pos"); - cur_frm.pos = new erpnext.POS(cur_frm.layout.views.pos, cur_frm); + if (!this.frm.doc.selling_price_list) + msgprint(wn._("Please select Price List")) + else { + if((show===true && cur_frm.pos_active) || (show===false && !cur_frm.pos_active)) return; + + // make pos + if(!cur_frm.pos) { + cur_frm.layout.add_view("pos"); + cur_frm.pos = new erpnext.POS(cur_frm.layout.views.pos, cur_frm); + } + + // toggle view + cur_frm.layout.set_view(cur_frm.pos_active ? "" : "pos"); + cur_frm.pos_active = !cur_frm.pos_active; + + // refresh + if(cur_frm.pos_active) + cur_frm.pos.refresh(); } - - // toggle view - cur_frm.layout.set_view(cur_frm.pos_active ? "" : "pos"); - cur_frm.pos_active = !cur_frm.pos_active; - - // refresh - if(cur_frm.pos_active) - cur_frm.pos.refresh(); - }, + tc_name: function() { this.get_terms(); }, diff --git a/setup/doctype/features_setup/features_setup.txt b/setup/doctype/features_setup/features_setup.txt index e1a4c08acf..89c9dd310b 100644 --- a/setup/doctype/features_setup/features_setup.txt +++ b/setup/doctype/features_setup/features_setup.txt @@ -2,7 +2,7 @@ { "creation": "2012-12-20 12:50:49", "docstatus": 0, - "modified": "2013-07-05 14:37:59", + "modified": "2013-08-22 15:36:43", "modified_by": "Administrator", "owner": "Administrator" }, @@ -184,6 +184,13 @@ "fieldtype": "Check", "label": "Point of Sale" }, + { + "description": "To enable Point of Sale view", + "doctype": "DocField", + "fieldname": "fs_pos_view", + "fieldtype": "Check", + "label": "POS View" + }, { "doctype": "DocField", "fieldname": "production",