From d5b01a1ddc0366dfda3db6765b7d41e04dfe9ea2 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 22 Aug 2013 15:43:18 +0530 Subject: [PATCH 01/13] [fix] [minor] removed reserved warehouse from no_copy in sales order item --- selling/doctype/sales_order_item/sales_order_item.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selling/doctype/sales_order_item/sales_order_item.txt b/selling/doctype/sales_order_item/sales_order_item.txt index eb4dec8d2b..47b4d6b870 100644 --- a/selling/doctype/sales_order_item/sales_order_item.txt +++ b/selling/doctype/sales_order_item/sales_order_item.txt @@ -2,7 +2,7 @@ { "creation": "2013-03-07 11:42:58", "docstatus": 0, - "modified": "2013-08-07 14:44:50", + "modified": "2013-08-22 15:43:07", "modified_by": "Administrator", "owner": "Administrator" }, @@ -230,7 +230,7 @@ "fieldtype": "Link", "in_list_view": 0, "label": "Reserved Warehouse", - "no_copy": 1, + "no_copy": 0, "oldfieldname": "reserved_warehouse", "oldfieldtype": "Link", "options": "Warehouse", From d6aa4bff7ff56f39c28ff6fb6d65333a31f301b1 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Thu, 22 Aug 2013 17:26:43 +0530 Subject: [PATCH 02/13] [pos] pos view first commit --- accounts/doctype/sales_invoice/pos.js | 348 +++++++++++++++++- accounts/doctype/sales_invoice/pos.py | 28 ++ .../doctype/sales_invoice/sales_invoice.js | 70 ++-- .../doctype/features_setup/features_setup.txt | 9 +- 4 files changed, 411 insertions(+), 44 deletions(-) create mode 100644 accounts/doctype/sales_invoice/pos.py 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_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", From 26c3240b67d45f029b5730721932aef70f34e65a Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Fri, 23 Aug 2013 12:21:52 +0530 Subject: [PATCH 03/13] [fix] [patch] [minor] make notes --- patches/may_2013/p06_make_notes.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/patches/may_2013/p06_make_notes.py b/patches/may_2013/p06_make_notes.py index b60642c53e..29bfe25da4 100644 --- a/patches/may_2013/p06_make_notes.py +++ b/patches/may_2013/p06_make_notes.py @@ -13,17 +13,27 @@ def execute(): name = question.question[:180] if webnotes.conn.exists("Note", name): webnotes.delete_doc("Note", name) - note = webnotes.bean({ + + similar_questions = webnotes.conn.sql_list("""select name from `tabQuestion` + where question like %s""", "%s%%" % name) + answers = [markdown2.markdown(c) for c in webnotes.conn.sql_list(""" + select answer from tabAnswer where question in (%s)""" % \ + ", ".join(["%s"]*len(similar_questions)), similar_questions)] + + webnotes.bean({ "doctype":"Note", "title": name, - "content": "
".join([markdown2.markdown(c) for c in webnotes.conn.sql_list(""" - select answer from tabAnswer where question=%s""", question.name)]), + "content": "
".join(answers), "owner": question.owner, "creation": question.creation, "public": 1 }).insert() + except NameError: pass + except Exception, e: + if e.args[0] != 1062: + raise e webnotes.delete_doc("DocType", "Question") webnotes.delete_doc("DocType", "Answer") From 1e4fb689fc12d442274b739f4f9f8f8b70deaccf Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Fri, 23 Aug 2013 12:56:33 +0530 Subject: [PATCH 04/13] [fix] [minor] trigger grid_fieldname_remove function on removing grid row --- public/js/transaction.js | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/public/js/transaction.js b/public/js/transaction.js index 118594c816..9bc9f3379e 100644 --- a/public/js/transaction.js +++ b/public/js/transaction.js @@ -6,9 +6,9 @@ wn.require("app/js/controllers/stock_controller.js"); erpnext.TransactionController = erpnext.stock.StockController.extend({ onload: function() { + var me = this; if(this.frm.doc.__islocal) { - var me = this, - today = get_today(), + var today = get_today(), currency = wn.defaults.get_default("currency"); $.each({ @@ -30,6 +30,10 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ me.frm.script_manager.trigger("company"); } + + if(this.other_fname) { + this[this.fname + "_remove"] = this[this.other_fname + "_remove"] = this.calculate_taxes_and_totals; + } }, onload_post_render: function() { @@ -311,9 +315,14 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ function(item_code, tax_data) { if(!item_tax[item_code]) item_tax[item_code] = {}; if($.isArray(tax_data)) { - var tax_rate = tax_data[0] == null ? "" : (flt(tax_data[0], tax_rate_precision) + "%"), - tax_amount = format_currency(flt(tax_data[1], tax_amount_precision), company_currency, - tax_amount_precision); + var tax_rate = ""; + if(tax_data[0] != null) { + tax_rate = (tax.charge_type === "Actual") ? + format_currency(flt(tax_data[0], tax_amount_precision), company_currency, tax_amount_precision) : + (flt(tax_data[0], tax_rate_precision) + "%"); + } + var tax_amount = format_currency(flt(tax_data[1], tax_amount_precision), company_currency, + tax_amount_precision); item_tax[item_code][tax.name] = [tax_rate, tax_amount]; } else { From a91c95f0febc5fefd0c5dd6e478ce0e2c3ac4b5e Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Fri, 23 Aug 2013 13:00:47 +0530 Subject: [PATCH 05/13] [fix] [minor] recalculate on removing row --- public/js/transaction.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/public/js/transaction.js b/public/js/transaction.js index 9bc9f3379e..1d06a9f487 100644 --- a/public/js/transaction.js +++ b/public/js/transaction.js @@ -32,7 +32,11 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ } if(this.other_fname) { - this[this.fname + "_remove"] = this[this.other_fname + "_remove"] = this.calculate_taxes_and_totals; + this[this.other_fname + "_remove"] = this.calculate_taxes_and_totals; + } + + if(this.fname) { + this[this.fname + "_remove"] = this.calculate_taxes_and_totals; } }, From 16a62fa4becce3bfd72c1826d313f836dd01ff52 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Fri, 23 Aug 2013 13:16:22 +0530 Subject: [PATCH 06/13] [pos] [cleanup] --- accounts/doctype/sales_invoice/pos.js | 193 +++++++++++------- accounts/doctype/sales_invoice/pos.py | 14 +- .../doctype/sales_invoice/sales_invoice.js | 18 +- startup/install.py | 2 +- utilities/make_demo.py | 3 +- 5 files changed, 141 insertions(+), 89 deletions(-) diff --git a/accounts/doctype/sales_invoice/pos.js b/accounts/doctype/sales_invoice/pos.js index c27adc3a57..126b88745c 100644 --- a/accounts/doctype/sales_invoice/pos.js +++ b/accounts/doctype/sales_invoice/pos.js @@ -7,56 +7,66 @@ erpnext.POS = Class.extend({ this.frm = frm; this.wrapper.html('
\
\ -
\ -
\ -
\ -
\ - \ -
\ -
\ - \ -
\ -
\ -
 
\ -
\ - \ - \ - \ - \ - \ - \ - \ -
Item#RateAmount
\ -
\ - \ +
\ +
\ +
\ +
\ + \ +
\ +
\ +
\ +
\ +
\ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
ItemQtyRate
\ +
\ +
\ +
\ + \ + \ + \ + \ + \ +
Net Total
\ + \ + \ + \ + \ + \ + \
Grand Total
\
\
\ -
 
\ -
\ -
Net Total
\ -
 
\ -
\ -
\ -
Tax
\ -
 
\ -
\ -
\ -
Grand Total
\ -
 
\ -
\ +

\ + \ + \ +

\
\ -
\ -
\ -
\ -
\ -
\ -
\ -
\ -
\ -
\ +
\
\ -
\ +
\
\
\
\ @@ -91,7 +101,8 @@ erpnext.POS = Class.extend({ "fieldtype": "Link", "options": "Customer", "label": "Customer", - "fieldname": "pos_customer" + "fieldname": "pos_customer", + "placeholder": "Customer" }, parent: this.wrapper.find(".customer-area") }); @@ -108,7 +119,8 @@ erpnext.POS = Class.extend({ "fieldtype": "Link", "options": "Item Group", "label": "Item Group", - "fieldname": "pos_item_group" + "fieldname": "pos_item_group", + "placeholder": "Filter by Item Group" }, parent: this.wrapper.find(".item-group-area") }); @@ -125,7 +137,8 @@ erpnext.POS = Class.extend({ "fieldtype": "Link", "options": "Item", "label": "Item", - "fieldname": "pos_item" + "fieldname": "pos_item", + "placeholder": "Select Item" }, parent: this.wrapper.find(".search-area") }); @@ -141,7 +154,8 @@ erpnext.POS = Class.extend({ df: { "fieldtype": "Data", "label": "Barcode", - "fieldname": "pos_barcode" + "fieldname": "pos_barcode", + "placeholder": "Select Barcode" }, parent: this.wrapper.find(".barcode-area") }); @@ -164,28 +178,30 @@ erpnext.POS = Class.extend({ me.wrapper.find(".item-list").empty(); $.each(r.message, function(index, obj) { if (obj.image) - image = ""; + image = ""; else - image = "
"; + image = '
'; - $(repl('', + $(repl('
\ + %(item_image)s\ +
%(item_code)s
\ +
%(item_name)s
\ +
%(item_price)s
\ +
', { item_code: obj.name, item_price: format_currency(obj.ref_rate, obj.ref_currency), - item_name: obj.item_name, + item_name: obj.name===obj.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")); + $("div.pos-item").on("click", function() { + if(!cur_frm.doc.customer) { + msgprint("Please select customer first."); + return; + } + me.add_to_cart($(this).attr("data-item_code")); }); } }); @@ -195,7 +211,7 @@ erpnext.POS = Class.extend({ var caught = false; // get no_of_items - no_of_items = me.wrapper.find("#cart tr").length; + no_of_items = me.wrapper.find("#cart tbody").length; // check whether the item is already added if (no_of_items != 0) { @@ -214,7 +230,7 @@ erpnext.POS = Class.extend({ 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(); + //me.refresh(); } }, update_qty: function(item_code, qty) { @@ -238,18 +254,19 @@ erpnext.POS = Class.extend({ this.barcode.set_input(""); // add items - var $items = me.wrapper.find("#cart").empty(); + var $items = me.wrapper.find("#cart tbody").empty(); $.each(wn.model.get_children("Sales Invoice Item", this.frm.doc.name, "entries", - "Sales Invoice"), function(i, d) { + "Sales Invoice"), function(i, d) { $(repl('\ - %(item_code)s
%(item_name)s\ - \ - %(rate)s\ - %(amount)s', + %(item_code)s%(item_name)s\ + \ + %(rate)s
%(amount)s\ + ', { item_code: d.item_code, - item_name: d.item_name, + item_name: d.item_name===d.item_code ? "" : ("
" + 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) @@ -257,11 +274,26 @@ erpnext.POS = Class.extend({ )).appendTo($items); }); + // taxes + var taxes = wn.model.get_children("Sales Taxes and Charges", this.frm.doc.name, "other_charges", + "Sales Invoice"); + $(".tax-table") + .toggle((taxes && taxes.length) ? true : false) + .find("tbody").empty(); + + $.each(taxes, function(i, d) { + $(repl('\ + %(description)s\ + %(tax_amount)s\ + ', { + description: d.description, + tax_amount: format_currency(d.tax_amount, me.frm.doc.price_list_currency) + })).appendTo(".tax-table tbody") + }); + // 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)); @@ -282,7 +314,14 @@ erpnext.POS = Class.extend({ row.prop("class", null); row.attr("data-selected", "false"); } + me.refresh_delete_btn(); + }); + + me.refresh_delete_btn(); + }, + refresh_delete_btn: function() { + $(".delete-items").toggle($(".item-cart .warning").length ? true : false); }, add_item_thru_barcode: function() { var me = this; @@ -302,9 +341,9 @@ erpnext.POS = Class.extend({ remove_selected_item: function() { var me = this; var selected_items = []; - var no_of_items = $("#cart tr").length; + var no_of_items = $("#cart tbody tr").length; for(var x=0; x<=no_of_items - 1; x++) { - var row = $("#cart tr:eq(" + x + ")"); + var row = $("#cart tbody tr:eq(" + x + ")"); if(row.attr("data-selected") == "true") { selected_items.push(row.attr("id")); } @@ -327,7 +366,7 @@ erpnext.POS = Class.extend({ }, make_payment: function() { var me = this; - var no_of_items = $("#cart tr").length; + var no_of_items = $("#cart tbody tr").length; var mode_of_payment = []; if (no_of_items == 0) @@ -356,6 +395,8 @@ erpnext.POS = Class.extend({ }); dialog.show(); + dialog.get_input("total_amount").attr("disabled", "disabled"); + 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); diff --git a/accounts/doctype/sales_invoice/pos.py b/accounts/doctype/sales_invoice/pos.py index f7dacf19a6..2f2ad6a36c 100644 --- a/accounts/doctype/sales_invoice/pos.py +++ b/accounts/doctype/sales_invoice/pos.py @@ -9,14 +9,18 @@ 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 + condition = "and i.item_group='%s'" % item_group if item: - condition = "where i.name='%s'" % item + condition = "and 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) + 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 + where + i.is_sales_item='Yes'%s""" % ('%s', condition), (price_list), as_dict=1) @webnotes.whitelist() def get_item_from_barcode(barcode): diff --git a/accounts/doctype/sales_invoice/sales_invoice.js b/accounts/doctype/sales_invoice/sales_invoice.js index 3baa226884..5d11ecbecb 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.js +++ b/accounts/doctype/sales_invoice/sales_invoice.js @@ -26,8 +26,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte } } - pos_view = cint(sys_defaults.fs_pos_view); - if(this.frm.doc.is_pos && this.frm.doc.docstatus===0 && pos_view===1) { + if(this.frm.doc.is_pos && this.frm.doc.docstatus===0) { cur_frm.cscript.toggle_pos(true); } }, @@ -60,7 +59,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte cur_frm.add_custom_button('Make Payment Entry', cur_frm.cscript.make_bank_voucher); } - if (this.frm.doc.docstatus===0) { + if (doc.docstatus===0) { cur_frm.add_custom_button(wn._('From Sales Order'), function() { wn.model.map_current_doc({ @@ -97,11 +96,18 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte if (cint(sys_defaults.fs_pos_view)===1) cur_frm.cscript.pos_btn(); + + setTimeout(function() { cur_frm.$pos_btn.click(); }, 1000); + + } else { + // hide shown pos for submitted records + if(cur_frm.pos_active) cur_frm.cscript.toggle_pos(false); } }, pos_btn: function() { - if(cur_frm.$pos_btn) cur_frm.$pos_btn.remove(); + if(cur_frm.$pos_btn) + cur_frm.$pos_btn.remove(); if(!cur_frm.pos_active) { var btn_label = wn._("POS View"), @@ -111,11 +117,11 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte icon = "icon-file-text"; } - cur_frm.add_custom_button(btn_label, function() { - cur_frm.$pos_btn = $(this); + cur_frm.$pos_btn = cur_frm.add_custom_button(btn_label, function() { cur_frm.cscript.toggle_pos(); cur_frm.cscript.pos_btn(); }, icon); + }, toggle_pos: function(show) { diff --git a/startup/install.py b/startup/install.py index 7e9273ca58..ea281b8ea7 100644 --- a/startup/install.py +++ b/startup/install.py @@ -72,7 +72,7 @@ def feature_setup(): 'fs_exports', 'fs_imports', 'fs_discounts', 'fs_purchase_discounts', 'fs_after_sales_installations', 'fs_projects', 'fs_sales_extras', 'fs_recurring_invoice', 'fs_pos', 'fs_manufacturing', 'fs_quality', - 'fs_page_break', 'fs_more_info' + 'fs_page_break', 'fs_more_info', 'fs_pos_view' ] doc.fields.update(dict(zip(flds, [1]*len(flds)))) doc.save() diff --git a/utilities/make_demo.py b/utilities/make_demo.py index 809a12b6c5..2884144135 100644 --- a/utilities/make_demo.py +++ b/utilities/make_demo.py @@ -24,13 +24,14 @@ bank_name = "Citibank" runs_for = 20 prob = { "default": { "make": 0.6, "qty": (1,5) }, + "Sales Order": { "make": 0.4, "qty": (1,3) }, "Purchase Order": { "make": 0.7, "qty": (1,15) }, "Purchase Receipt": { "make": 0.7, "qty": (1,15) }, } def make(reset=False): webnotes.connect() - webnotes.print_messages = True + #webnotes.print_messages = True webnotes.mute_emails = True webnotes.rollback_on_exception = True From cb50dee98cd97d0e3e344bf887223ca9d7595c88 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Fri, 23 Aug 2013 13:35:21 +0530 Subject: [PATCH 07/13] [pos] [minor] added css file --- accounts/doctype/sales_invoice/sales_invoice.css | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 accounts/doctype/sales_invoice/sales_invoice.css diff --git a/accounts/doctype/sales_invoice/sales_invoice.css b/accounts/doctype/sales_invoice/sales_invoice.css new file mode 100644 index 0000000000..e4b61b66ca --- /dev/null +++ b/accounts/doctype/sales_invoice/sales_invoice.css @@ -0,0 +1,15 @@ +.pos-item { + height: 200px; + overflow: hidden; + cursor: pointer; + padding-left: 5px !important; + padding-right: 5px !important; +} + +.pos-bill { + padding: 20px 5px; + font-family: Monospace; + border: 1px solid #eee; + -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); +} \ No newline at end of file From 53cd86b0d8f5a6c7c30db13f268c6f8f331c0626 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Fri, 23 Aug 2013 16:38:25 +0530 Subject: [PATCH 08/13] [fix] [minor] added item_name field in sales bom item query --- selling/doctype/sales_bom/sales_bom.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selling/doctype/sales_bom/sales_bom.py b/selling/doctype/sales_bom/sales_bom.py index 8bcac1771f..15d8fd1e5b 100644 --- a/selling/doctype/sales_bom/sales_bom.py +++ b/selling/doctype/sales_bom/sales_bom.py @@ -76,8 +76,8 @@ class DocType: def get_new_item_code(doctype, txt, searchfield, start, page_len, filters): from controllers.queries import get_match_cond - - return webnotes.conn.sql("""select name, description from tabItem + + return webnotes.conn.sql("""select name, item_name, description from tabItem where is_stock_item="No" and is_sales_item="Yes" and name not in (select name from `tabSales BOM`) and %s like %s %s limit %s, %s""" % (searchfield, "%s", From 4d47b007aa49d528fc1b29fd386d258a837b4d33 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Fri, 23 Aug 2013 16:54:31 +0530 Subject: [PATCH 09/13] [fix] [minor] fix in re-order query --- stock/utils.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/stock/utils.py b/stock/utils.py index 848783b2c6..5376342979 100644 --- a/stock/utils.py +++ b/stock/utils.py @@ -193,8 +193,7 @@ def reorder_item(): and exists (select name from `tabItem` where `tabItem`.name = `tabBin`.item_code and is_stock_item='Yes' and (is_purchase_item='Yes' or is_sub_contracted_item='Yes') and - (ifnull(end_of_life, '')='') or end_of_life > now())""", - as_dict=True) + (ifnull(end_of_life, '')='' or end_of_life > now()))""", as_dict=True) for bin in bin_list: #check if re-order is required item_reorder = webnotes.conn.get("Item Reorder", From 6c0a1a9674eeb3289e7d4a32a80de12ba1080b06 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Fri, 23 Aug 2013 19:30:44 +0530 Subject: [PATCH 10/13] [fix] [minor] temporarily disabled pos view --- accounts/doctype/sales_invoice/pos.js | 2 +- accounts/doctype/sales_invoice/sales_invoice.js | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/accounts/doctype/sales_invoice/pos.js b/accounts/doctype/sales_invoice/pos.js index 126b88745c..1bd6de1030 100644 --- a/accounts/doctype/sales_invoice/pos.js +++ b/accounts/doctype/sales_invoice/pos.js @@ -288,7 +288,7 @@ erpnext.POS = Class.extend({ ', { description: d.description, tax_amount: format_currency(d.tax_amount, me.frm.doc.price_list_currency) - })).appendTo(".tax-table tbody") + })).appendTo(".tax-table tbody"); }); // set totals diff --git a/accounts/doctype/sales_invoice/sales_invoice.js b/accounts/doctype/sales_invoice/sales_invoice.js index 5d11ecbecb..109d9f8a07 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.js +++ b/accounts/doctype/sales_invoice/sales_invoice.js @@ -26,9 +26,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte } } - if(this.frm.doc.is_pos && this.frm.doc.docstatus===0) { - cur_frm.cscript.toggle_pos(true); - } + cur_frm.cscript.toggle_pos(true); }, refresh: function(doc, dt, dn) { @@ -94,10 +92,10 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte }); }); - if (cint(sys_defaults.fs_pos_view)===1) + if(cint(sys_defaults.fs_pos_view)===1) cur_frm.cscript.pos_btn(); - setTimeout(function() { cur_frm.$pos_btn.click(); }, 1000); + // setTimeout(function() { cur_frm.$pos_btn.click(); }, 1000); } else { // hide shown pos for submitted records @@ -125,6 +123,9 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte }, toggle_pos: function(show) { + if(cint(sys_defaults.fs_pos_view)===0) return; + if(!(this.frm.doc.is_pos && this.frm.doc.docstatus===0)) return; + if (!this.frm.doc.selling_price_list) msgprint(wn._("Please select Price List")) else { From cf343174a4a2b51df750c1004d45ba98b212a501 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Fri, 23 Aug 2013 19:53:41 +0530 Subject: [PATCH 11/13] [fix] removed purchase order no from purchase list view, since it does not show purchase receipt when the form doesn't have any purchase receipt items --- .../purchase_receipt/purchase_receipt_list.js | 22 ------------------- 1 file changed, 22 deletions(-) delete mode 100644 stock/doctype/purchase_receipt/purchase_receipt_list.js diff --git a/stock/doctype/purchase_receipt/purchase_receipt_list.js b/stock/doctype/purchase_receipt/purchase_receipt_list.js deleted file mode 100644 index bc0c9f6e00..0000000000 --- a/stock/doctype/purchase_receipt/purchase_receipt_list.js +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. -// License: GNU General Public License v3. See license.txt - -// render -wn.listview_settings['Purchase Receipt'] = { - add_fields: ["group_concat(`tabPurchase Receipt Item`.prevdoc_docname) \ - as purchase_order_no"], - add_columns: [{"content":"purchase_order_no", width:"30%"}], - group_by: "`tabPurchase Receipt`.name", - prepare_data: function(data) { - if(data.purchase_order_no) { - data.purchase_order_no = $.unique(data.purchase_order_no.split(",")); - var po_list = []; - $.each(data.purchase_order_no, function(i, v){ - if(po_list.indexOf(v)==-1) po_list.push( - repl("%(name)s", - {name: v})); - }); - data.purchase_order_no = po_list.join(", "); - } - } -}; From acd3367e331a8345d39e62c61a4f2f030303acac Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Mon, 26 Aug 2013 16:17:50 +0530 Subject: [PATCH 12/13] [demo] New ERPNext Demo --- config.json | 1 + utilities/demo/__init__.py | 0 utilities/demo/demo-login.css | 3 + utilities/demo/demo-login.html | 25 ++++++ utilities/demo/demo-login.js | 27 ++++++ utilities/demo/demo_control_panel.py | 13 +++ utilities/{ => demo}/demo_docs/Address.csv | 0 utilities/{ => demo}/demo_docs/BOM.csv | 0 utilities/{ => demo}/demo_docs/Contact.csv | 0 utilities/{ => demo}/demo_docs/Customer.csv | 0 utilities/{ => demo}/demo_docs/Employee.csv | 0 .../{ => demo}/demo_docs/Fiscal_Year.csv | 0 utilities/{ => demo}/demo_docs/Item.csv | 0 utilities/{ => demo}/demo_docs/Item_Price.csv | 0 utilities/{ => demo}/demo_docs/Lead.csv | 0 utilities/{ => demo}/demo_docs/Profile.csv | 0 .../{ => demo}/demo_docs/Salary_Structure.csv | 0 .../Stock Reconcilation Template.csv | 0 utilities/{ => demo}/demo_docs/Supplier.csv | 0 .../{ => demo}/demo_docs/bearing-block.png | Bin .../{ => demo}/demo_docs/wind-turbine.png | Bin utilities/{ => demo}/make_demo.py | 51 +++++++----- utilities/demo/make_erpnext_demo.py | 77 ++++++++++++++++++ .../website_settings/website_settings.js | 8 ++ .../website_settings/website_settings.py | 20 +++++ 25 files changed, 203 insertions(+), 22 deletions(-) create mode 100644 utilities/demo/__init__.py create mode 100644 utilities/demo/demo-login.css create mode 100644 utilities/demo/demo-login.html create mode 100644 utilities/demo/demo-login.js create mode 100644 utilities/demo/demo_control_panel.py rename utilities/{ => demo}/demo_docs/Address.csv (100%) rename utilities/{ => demo}/demo_docs/BOM.csv (100%) rename utilities/{ => demo}/demo_docs/Contact.csv (100%) rename utilities/{ => demo}/demo_docs/Customer.csv (100%) rename utilities/{ => demo}/demo_docs/Employee.csv (100%) rename utilities/{ => demo}/demo_docs/Fiscal_Year.csv (100%) rename utilities/{ => demo}/demo_docs/Item.csv (100%) rename utilities/{ => demo}/demo_docs/Item_Price.csv (100%) rename utilities/{ => demo}/demo_docs/Lead.csv (100%) rename utilities/{ => demo}/demo_docs/Profile.csv (100%) rename utilities/{ => demo}/demo_docs/Salary_Structure.csv (100%) rename utilities/{ => demo}/demo_docs/Stock Reconcilation Template.csv (100%) rename utilities/{ => demo}/demo_docs/Supplier.csv (100%) rename utilities/{ => demo}/demo_docs/bearing-block.png (100%) rename utilities/{ => demo}/demo_docs/wind-turbine.png (100%) rename utilities/{ => demo}/make_demo.py (93%) create mode 100644 utilities/demo/make_erpnext_demo.py diff --git a/config.json b/config.json index c9d1aa71f8..5412b017b2 100644 --- a/config.json +++ b/config.json @@ -1,4 +1,5 @@ { + "app_name": "ERPNext", "modules": { "Selling": { "link": "selling-home", diff --git a/utilities/demo/__init__.py b/utilities/demo/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/utilities/demo/demo-login.css b/utilities/demo/demo-login.css new file mode 100644 index 0000000000..f3464a3a2d --- /dev/null +++ b/utilities/demo/demo-login.css @@ -0,0 +1,3 @@ +body, #container, .outer { + background-color: #888 !important; +} \ No newline at end of file diff --git a/utilities/demo/demo-login.html b/utilities/demo/demo-login.html new file mode 100644 index 0000000000..ef24678e27 --- /dev/null +++ b/utilities/demo/demo-login.html @@ -0,0 +1,25 @@ +
+
+
+
+
+ Start ERPNext Demo +
+
+

+ +

+

+ +

+
+

Some functionality is disabled for the demo app. The demo data will be cleared regulary. To start your own ERPNext Trial, click here

+
+
+
+
+
+
+
diff --git a/utilities/demo/demo-login.js b/utilities/demo/demo-login.js new file mode 100644 index 0000000000..229d1690e5 --- /dev/null +++ b/utilities/demo/demo-login.js @@ -0,0 +1,27 @@ +$(document).ready(function() { + $(".navbar, footer, .banner, #user-tools").toggle(false); + + $("#login_btn").click(function() { + var me = this; + $(this).html("Logging In...").attr("disabled", "disabled"); + wn.call({ + "method": "login", + args: { + usr: "demo@erpnext.com", + pwd: "demo", + lead_email: $("#lead-email").val(), + }, + callback: function(r) { + $(me).attr("disabled", false); + if(r.exc) { + alert("Error, please contact support@erpnext.com"); + } else { + console.log("Logged In"); + window.location.href = "app.html"; + } + } + }) + return false; + }) + .attr("disabled", false); +}) \ No newline at end of file diff --git a/utilities/demo/demo_control_panel.py b/utilities/demo/demo_control_panel.py new file mode 100644 index 0000000000..c70913ee68 --- /dev/null +++ b/utilities/demo/demo_control_panel.py @@ -0,0 +1,13 @@ + + def on_login(self): + from webnotes.utils import validate_email_add + import conf + if hasattr(conf, "demo_notify_url"): + if webnotes.form_dict.lead_email and validate_email_add(webnotes.form_dict.lead_email): + import requests + response = requests.post(conf.demo_notify_url, data={ + "cmd":"website.helpers.contact.send_message", + "subject":"Logged into Demo", + "sender": webnotes.form_dict.lead_email, + "message": "via demo.erpnext.com" + }) diff --git a/utilities/demo_docs/Address.csv b/utilities/demo/demo_docs/Address.csv similarity index 100% rename from utilities/demo_docs/Address.csv rename to utilities/demo/demo_docs/Address.csv diff --git a/utilities/demo_docs/BOM.csv b/utilities/demo/demo_docs/BOM.csv similarity index 100% rename from utilities/demo_docs/BOM.csv rename to utilities/demo/demo_docs/BOM.csv diff --git a/utilities/demo_docs/Contact.csv b/utilities/demo/demo_docs/Contact.csv similarity index 100% rename from utilities/demo_docs/Contact.csv rename to utilities/demo/demo_docs/Contact.csv diff --git a/utilities/demo_docs/Customer.csv b/utilities/demo/demo_docs/Customer.csv similarity index 100% rename from utilities/demo_docs/Customer.csv rename to utilities/demo/demo_docs/Customer.csv diff --git a/utilities/demo_docs/Employee.csv b/utilities/demo/demo_docs/Employee.csv similarity index 100% rename from utilities/demo_docs/Employee.csv rename to utilities/demo/demo_docs/Employee.csv diff --git a/utilities/demo_docs/Fiscal_Year.csv b/utilities/demo/demo_docs/Fiscal_Year.csv similarity index 100% rename from utilities/demo_docs/Fiscal_Year.csv rename to utilities/demo/demo_docs/Fiscal_Year.csv diff --git a/utilities/demo_docs/Item.csv b/utilities/demo/demo_docs/Item.csv similarity index 100% rename from utilities/demo_docs/Item.csv rename to utilities/demo/demo_docs/Item.csv diff --git a/utilities/demo_docs/Item_Price.csv b/utilities/demo/demo_docs/Item_Price.csv similarity index 100% rename from utilities/demo_docs/Item_Price.csv rename to utilities/demo/demo_docs/Item_Price.csv diff --git a/utilities/demo_docs/Lead.csv b/utilities/demo/demo_docs/Lead.csv similarity index 100% rename from utilities/demo_docs/Lead.csv rename to utilities/demo/demo_docs/Lead.csv diff --git a/utilities/demo_docs/Profile.csv b/utilities/demo/demo_docs/Profile.csv similarity index 100% rename from utilities/demo_docs/Profile.csv rename to utilities/demo/demo_docs/Profile.csv diff --git a/utilities/demo_docs/Salary_Structure.csv b/utilities/demo/demo_docs/Salary_Structure.csv similarity index 100% rename from utilities/demo_docs/Salary_Structure.csv rename to utilities/demo/demo_docs/Salary_Structure.csv diff --git a/utilities/demo_docs/Stock Reconcilation Template.csv b/utilities/demo/demo_docs/Stock Reconcilation Template.csv similarity index 100% rename from utilities/demo_docs/Stock Reconcilation Template.csv rename to utilities/demo/demo_docs/Stock Reconcilation Template.csv diff --git a/utilities/demo_docs/Supplier.csv b/utilities/demo/demo_docs/Supplier.csv similarity index 100% rename from utilities/demo_docs/Supplier.csv rename to utilities/demo/demo_docs/Supplier.csv diff --git a/utilities/demo_docs/bearing-block.png b/utilities/demo/demo_docs/bearing-block.png similarity index 100% rename from utilities/demo_docs/bearing-block.png rename to utilities/demo/demo_docs/bearing-block.png diff --git a/utilities/demo_docs/wind-turbine.png b/utilities/demo/demo_docs/wind-turbine.png similarity index 100% rename from utilities/demo_docs/wind-turbine.png rename to utilities/demo/demo_docs/wind-turbine.png diff --git a/utilities/make_demo.py b/utilities/demo/make_demo.py similarity index 93% rename from utilities/make_demo.py rename to utilities/demo/make_demo.py index 2884144135..fc0776740e 100644 --- a/utilities/make_demo.py +++ b/utilities/demo/make_demo.py @@ -19,9 +19,9 @@ company_abbr = "WP" country = "United States" currency = "USD" time_zone = "America/New York" -start_date = '2010-01-01' +start_date = '2013-01-01' bank_name = "Citibank" -runs_for = 20 +runs_for = None prob = { "default": { "make": 0.6, "qty": (1,5) }, "Sales Order": { "make": 0.4, "qty": (1,3) }, @@ -50,21 +50,24 @@ def setup(): # make_opening_accounts() def simulate(): - current_date = None - for i in xrange(runs_for): - if not current_date: - # get last stock ledger posting date or use default - last_posting = webnotes.conn.sql("""select max(posting_date) from `tabStock Ledger Entry`""") - if last_posting[0][0]: - current_date = webnotes.utils.add_days(last_posting[0][0], 1) - else: - current_date = webnotes.utils.getdate(start_date) - else: - current_date = webnotes.utils.add_days(current_date, 1) - + global runs_for + current_date = webnotes.utils.getdate(start_date) + + # continue? + last_posting = webnotes.conn.sql("""select max(posting_date) from `tabStock Ledger Entry`""") + if last_posting[0][0]: + current_date = webnotes.utils.add_days(last_posting[0][0], 1) + + # run till today + if not runs_for: + runs_for = webnotes.utils.date_diff(webnotes.utils.nowdate(), current_date) + + for i in xrange(runs_for): print current_date.strftime("%Y-%m-%d") + webnotes.utils.current_date = current_date if current_date.weekday() in (5, 6): + current_date = webnotes.utils.add_days(current_date, 1) continue run_sales(current_date) @@ -72,6 +75,8 @@ def simulate(): run_manufacturing(current_date) run_stock(current_date) run_accounts(current_date) + + current_date = webnotes.utils.add_days(current_date, 1) def run_sales(current_date): if can_make("Quotation"): @@ -136,7 +141,7 @@ def run_stock(current_date): for po in list(set([r[0] for r in query_report.run(report)["result"] if r[0]!="Total"]))[:how_many("Purchase Receipt")]: pr = webnotes.bean(make_purchase_receipt(po)) pr.doc.posting_date = current_date - pr.doc.fiscal_year = "2010" + pr.doc.fiscal_year = "2013" pr.insert() pr.submit() webnotes.conn.commit() @@ -150,7 +155,7 @@ def run_stock(current_date): for so in list(set([r[0] for r in query_report.run(report)["result"] if r[0]!="Total"]))[:how_many("Delivery Note")]: dn = webnotes.bean(make_delivery_note(so)) dn.doc.posting_date = current_date - dn.doc.fiscal_year = "2010" + dn.doc.fiscal_year = "2013" dn.insert() try: dn.submit() @@ -173,7 +178,7 @@ def run_purchase(current_date): mr = webnotes.new_bean("Material Request") mr.doc.material_request_type = "Purchase" mr.doc.transaction_date = current_date - mr.doc.fiscal_year = "2010" + mr.doc.fiscal_year = "2013" mr.doclist.append({ "doctype": "Material Request Item", "parentfield": "indent_details", @@ -192,7 +197,7 @@ def run_purchase(current_date): if row[0] != "Total": sq = webnotes.bean(make_supplier_quotation(row[0])) sq.doc.transaction_date = current_date - sq.doc.fiscal_year = "2010" + sq.doc.fiscal_year = "2013" sq.insert() sq.submit() webnotes.conn.commit() @@ -205,7 +210,7 @@ def run_purchase(current_date): if row[0] != "Total": po = webnotes.bean(make_purchase_order(row[0])) po.doc.transaction_date = current_date - po.doc.fiscal_year = "2010" + po.doc.fiscal_year = "2013" po.insert() po.submit() webnotes.conn.commit() @@ -263,7 +268,7 @@ def make_stock_entry_from_pro(pro_id, purpose, current_date): st = webnotes.bean(make_stock_entry(pro_id, purpose)) st.doc.posting_date = current_date - st.doc.fiscal_year = "2010" + st.doc.fiscal_year = "2013" st.doc.expense_adjustment_account = "Stock in Hand - WP" try: st.insert() @@ -282,7 +287,7 @@ def make_quotation(current_date): "customer": get_random("Customer"), "order_type": "Sales", "transaction_date": current_date, - "fiscal_year": "2010" + "fiscal_year": "2013" }]) add_random_children(b, { @@ -349,8 +354,9 @@ def how_many(doctype): def install(): print "Creating Fresh Database..." from webnotes.install_lib.install import Installer + import conf inst = Installer('root') - inst.import_from_db("demo", verbose = 1) + inst.import_from_db(conf.demo_db_name, verbose = 1) def complete_setup(): print "Complete Setup..." @@ -392,6 +398,7 @@ def make_bank_account(): }).insert() webnotes.set_value("Company", company, "default_bank_account", ba.doc.name) + webnotes.conn.commit() def import_data(dt, submit=False): if not isinstance(dt, (tuple, list)): diff --git a/utilities/demo/make_erpnext_demo.py b/utilities/demo/make_erpnext_demo.py new file mode 100644 index 0000000000..fde05f6a9b --- /dev/null +++ b/utilities/demo/make_erpnext_demo.py @@ -0,0 +1,77 @@ +import webnotes, os + +def make_demo_app(): + import utilities.demo.make_demo + utilities.demo.make_demo.make(reset=True) + +def make_demo_user(): + if webnotes.conn.exists("Profile", "demo@erpnext.com"): + webnotes.delete_doc("Profile", "demo@erpnext.com") + + p = webnotes.new_bean("Profile") + p.doc.email = "demo@erpnext.com" + p.doc.first_name = "Demo" + p.doc.last_name = "User" + p.doc.enabled = 1 + p.doc.user_type = "ERPNext Demo" + p.doc.send_invite_email = 0 + p.doc.new_password = "demo" + p.insert() + + for role in ("Accounts Manager", "Analytics", "Expense Approver", "Accounts User", + "Leave Approver", "Blogger", "Customer", "Sales Manager", "Employee", "Support Manager", + "HR Manager", "HR User", "Maintenance Manager", "Maintenance User", "Material Manager", + "Material Master Manager", "Material User", "Partner", "Manufacturing Manager", + "Manufacturing User", "Projects User", "Purchase Manager", "Purchase Master Manager", + "Purchase User", "Quality Manager", "Report Manager", "Sales Master Manager", "Sales User", + "Supplier", "Support Team"): + p.doclist.append({ + "doctype": "UserRole", + "parentfield": "user_roles", + "role": role + }) + + p.save() + webnotes.conn.commit() + +def make_demo_login_page(): + webnotes.conn.set_value("Website Settings", None, "home_page", "") + + webnotes.conn.sql("""delete from `tabWeb Page` where name='demo-login'""") + p = webnotes.new_bean("Web Page") + p.doc.title = "Demo Login" + p.doc.published = 1 + p.doc.description = "ERPNext Demo Login" + + with open(os.path.join(os.path.dirname(__file__), "demo-login.html"), "r") as dfile: + p.doc.main_section = dfile.read() + + p.doc.insert_code = 1 + with open(os.path.join(os.path.dirname(__file__), "demo-login.js"), "r") as dfile: + p.doc.javascript = dfile.read() + + p.doc.insert_style = 1 + with open(os.path.join(os.path.dirname(__file__), "demo-login.css"), "r") as dfile: + p.doc.css = dfile.read() + + p.insert() + + webnotes.conn.set_value("Website Settings", None, "home_page", "demo-login") + + webnotes.conn.commit() + +def make_demo_on_login_script(): + webnotes.conn.sql("""delete from `tabCustom Script` where dt='Control Panel'""") + s = webnotes.new_bean("Custom Script") + s.doc.dt = "Control Panel" + s.doc.script_type = "Server" + with open(os.path.join(os.path.dirname(__file__), "demo_control_panel.py"), "r") as dfile: + s.doc.script = dfile.read() + +if __name__=="__main__": + webnotes.connect() + webnotes.mute_emails = 1 + make_demo_app() + make_demo_user() + make_demo_login_page() + make_demo_on_login_script() \ No newline at end of file diff --git a/website/doctype/website_settings/website_settings.js b/website/doctype/website_settings/website_settings.js index 0d0dab68c0..21b55be5ea 100644 --- a/website/doctype/website_settings/website_settings.js +++ b/website/doctype/website_settings/website_settings.js @@ -4,6 +4,14 @@ // update parent select $.extend(cur_frm.cscript, { + refresh: function(doc) { + cur_frm.add_custom_button("Auto Build Website", function() { + cur_frm.call({ + doc: cur_frm.doc, + method: "make_website" + }) + }, 'icon-magic') + }, onload_post_render: function(doc) { this.set_parent_label_options(); }, diff --git a/website/doctype/website_settings/website_settings.py b/website/doctype/website_settings/website_settings.py index 3b27c7ccc1..5d6c874d70 100644 --- a/website/doctype/website_settings/website_settings.py +++ b/website/doctype/website_settings/website_settings.py @@ -13,6 +13,26 @@ class DocType: self.set_home_page() self.validate_top_bar_items() self.validate_footer_items() + + def make_website(self): + # set item pages + for name in webnotes.conn.sql_list("""select name from tabItem where + ifnull(show_in_website, 0)=0 and is_sales_item ='Yes' """): + webnotes.msgprint("Setting 'Show in Website' for:" + name) + item = webnotes.bean("Item", name) + item.doc.show_in_website = 1 + item.doc.website_warehouse = item.doc.default_warehouse + item.doc.website_image = item.doc.image + item.save() + + # set item group pages + for name in webnotes.conn.sql_list("""select name from `tabItem Group` where + ifnull(show_in_website, 0)=0 and exists (select name from tabItem where + ifnull(show_in_website, 0)=1)"""): + webnotes.msgprint("Setting 'Show in Website' for:" + name) + item_group = webnotes.bean("Item Group", name) + item_group.doc.show_in_website = 1 + item_group.save() def validate_top_bar_items(self): """validate url in top bar items""" From 3c92b218760ec2f37735a16b1d042889358d8861 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Mon, 26 Aug 2013 16:40:25 +0530 Subject: [PATCH 13/13] [fix] [demo] extend sys path for make_erpnext_demo --- utilities/demo/make_erpnext_demo.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/utilities/demo/make_erpnext_demo.py b/utilities/demo/make_erpnext_demo.py index fde05f6a9b..0a8a9351d8 100644 --- a/utilities/demo/make_erpnext_demo.py +++ b/utilities/demo/make_erpnext_demo.py @@ -1,3 +1,7 @@ +if __name__=="__main__": + import sys + sys.path.extend([".", "lib", "app"]) + import webnotes, os def make_demo_app():