From 6773bc251273855b5352c332116c13e68c0e8847 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Tue, 17 Sep 2013 11:56:17 +0530 Subject: [PATCH 01/41] [pos] [minor] added pos in sales order for testing --- .../doctype/sales_invoice/sales_invoice.js | 82 +++++++++---------- .../p03_buying_selling_for_price_list.py | 2 +- public/js/transaction.js | 58 ++++++++++++- selling/doctype/sales_order/sales_order.js | 1 + 4 files changed, 95 insertions(+), 48 deletions(-) diff --git a/accounts/doctype/sales_invoice/sales_invoice.js b/accounts/doctype/sales_invoice/sales_invoice.js index 60f73b5a191..73958fb6721 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.js +++ b/accounts/doctype/sales_invoice/sales_invoice.js @@ -82,10 +82,6 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte cur_frm.cscript.sales_order_btn(); cur_frm.cscript.delivery_note_btn(); } - - // Show POS button only if it enabled from features setup - if(cint(sys_defaults.fs_pos_view)===1) - cur_frm.cscript.pos_btn(); }, sales_order_btn: function() { @@ -125,53 +121,53 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte }); }, - pos_btn: function() { - if(cur_frm.$pos_btn) - cur_frm.$pos_btn.remove(); + // 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"; + // if(!cur_frm.pos_active) { + // var btn_label = wn._("POS View"), + // icon = "icon-desktop"; - cur_frm.cscript.sales_order_btn(); - cur_frm.cscript.delivery_note_btn(); - } else { - var btn_label = wn._("Invoice View"), - icon = "icon-file-text"; + // cur_frm.cscript.sales_order_btn(); + // cur_frm.cscript.delivery_note_btn(); + // } else { + // var btn_label = wn._("Invoice View"), + // icon = "icon-file-text"; - if (cur_frm.doc.docstatus===0) { - this.$delivery_note_btn.remove(); - this.$sales_order_btn.remove(); - } - } + // if (cur_frm.doc.docstatus===0) { + // this.$delivery_note_btn.remove(); + // this.$sales_order_btn.remove(); + // } + // } - cur_frm.$pos_btn = cur_frm.add_custom_button(btn_label, function() { - cur_frm.cscript.toggle_pos(); - cur_frm.cscript.pos_btn(); - }, icon); - }, + // 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) { - 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; + // toggle_pos: function(show) { + // 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); - } + // // 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; + // // 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(); - } - }, + // // refresh + // if(cur_frm.pos_active) + // cur_frm.pos.refresh(); + // } + // }, tc_name: function() { this.get_terms(); diff --git a/patches/june_2013/p03_buying_selling_for_price_list.py b/patches/june_2013/p03_buying_selling_for_price_list.py index c251712437a..7d222c8e8a5 100644 --- a/patches/june_2013/p03_buying_selling_for_price_list.py +++ b/patches/june_2013/p03_buying_selling_for_price_list.py @@ -22,6 +22,6 @@ def execute(): webnotes.conn.set_value("Price List", price_list, "buying_or_selling", buying_or_selling) except MySQLdb.OperationalError, e: if e.args[0] == 1054: - webnotes.conn.set_value("Price List", price_list, "buying_or_selling", "Selling") + webnotes.conn.sql("""update `tabItem Price` set buying_or_selling='Selling' """) else: raise e \ No newline at end of file diff --git a/public/js/transaction.js b/public/js/transaction.js index 387140472c7..f7caded328a 100644 --- a/public/js/transaction.js +++ b/public/js/transaction.js @@ -62,6 +62,56 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ erpnext.hide_company(); this.show_item_wise_taxes(); this.set_dynamic_labels(); + + // Show POS button only if it is enabled from features setup + if(cint(sys_defaults.fs_pos_view)===1 && this.frm.doctype!="Material Request") + this.pos_btn(); + }, + + pos_btn: function() { + if(this.$pos_btn) + this.$pos_btn.remove(); + + if(!this.pos_active) { + var btn_label = wn._("POS View"), + icon = "icon-desktop"; + } else { + var btn_label = wn._(this.frm.doctype) + wn._(" View"), + icon = "icon-file-text"; + + + if (this.frm.doc.docstatus===0) { + this.frm.clear_custom_buttons(); + } + } + var me = this; + + this.$pos_btn = this.frm.add_custom_button(btn_label, function() { + me.toggle_pos(); + me.pos_btn(); + }, icon); + }, + + toggle_pos: function(show) { + if (!this.frm.doc.selling_price_list) + msgprint(wn._("Please select Price List")) + else { + if((show===true && this.pos_active) || (show===false && !this.pos_active)) return; + + // make pos + if(!this.pos) { + this.frm.layout.add_view("pos"); + this.frm.pos = new erpnext.POS(this.frm.layout.views.pos, this.frm); + } + + // toggle view + this.frm.layout.set_view(this.pos_active ? "" : "pos"); + this.pos_active = !this.pos_active; + + // refresh + if(this.pos_active) + this.frm.pos.refresh(); + } }, validate: function() { @@ -418,10 +468,10 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ (this.frm.doc.currency != company_currency && this.frm.doc.conversion_rate != 1.0)) : false; - // if(!valid_conversion_rate) { - // wn.throw(wn._("Please enter valid") + " " + wn._(conversion_rate_label) + - // " 1 " + this.frm.doc.currency + " = [?] " + company_currency); - // } + if(!valid_conversion_rate) { + wn.throw(wn._("Please enter valid") + " " + wn._(conversion_rate_label) + + " 1 " + this.frm.doc.currency + " = [?] " + company_currency); + } }, calculate_taxes_and_totals: function() { diff --git a/selling/doctype/sales_order/sales_order.js b/selling/doctype/sales_order/sales_order.js index 33699f05d84..161e10fe4e5 100644 --- a/selling/doctype/sales_order/sales_order.js +++ b/selling/doctype/sales_order/sales_order.js @@ -12,6 +12,7 @@ cur_frm.cscript.sales_team_fname = "sales_team"; wn.require('app/selling/doctype/sales_common/sales_common.js'); 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/accounts/doctype/sales_invoice/pos.js'); erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend({ refresh: function(doc, dt, dn) { From a550e7443fa9c1a6ff6f0224db0764dcf7271179 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Tue, 17 Sep 2013 18:52:00 +0530 Subject: [PATCH 02/41] [pos] moved pos realted code from sales_invoice.js to transaction.js --- accounts/doctype/sales_invoice/pos.js | 23 ++++++++++--------- .../doctype/sales_invoice/sales_invoice.js | 2 +- public/js/transaction.js | 5 ---- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/accounts/doctype/sales_invoice/pos.js b/accounts/doctype/sales_invoice/pos.js index 8837aed14b0..67c4b93186a 100644 --- a/accounts/doctype/sales_invoice/pos.js +++ b/accounts/doctype/sales_invoice/pos.js @@ -96,6 +96,7 @@ erpnext.POS = Class.extend({ }, make_customer: function() { var me = this; + console.log(this.frm); this.customer = wn.ui.form.make_control({ df: { "fieldtype": "Link", @@ -109,7 +110,7 @@ erpnext.POS = Class.extend({ this.customer.make_input(); this.customer.$input.on("change", function() { if(!me.customer.autocomplete_open) - wn.model.set_value("Sales Invoice", me.frm.docname, "customer", this.value); + wn.model.set_value(this.frm.doctype, me.frm.docname, "customer", this.value); }); }, make_item_group: function() { @@ -221,8 +222,8 @@ erpnext.POS = Class.extend({ // 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) { + $.each(wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name, "entries", + this.frm.doctype), function(i, d) { if (d.item_code == item_code) caught = true; }); @@ -233,15 +234,15 @@ erpnext.POS = Class.extend({ me.update_qty(item_code, 1); } else { - var child = wn.model.add_child(me.frm.doc, "Sales Invoice Item", "entries"); + var child = wn.model.add_child(me.frm.doc, this.frm.doctype + " Item", "entries"); child.item_code = item_code; me.frm.cscript.item_code(me.frm.doc, child.doctype, child.name); } }, update_qty: function(item_code, qty, textbox_qty) { var me = this; - $.each(wn.model.get_children("Sales Invoice Item", this.frm.doc.name, "entries", - "Sales Invoice"), function(i, d) { + $.each(wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name, "entries", + this.frm.doctype), function(i, d) { if (d.item_code == item_code) { if (textbox_qty) { if (qty == 0 && d.item_code == item_code) @@ -265,8 +266,8 @@ erpnext.POS = Class.extend({ // add items 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) { + $.each(wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name, "entries", + this.frm.doctype), function(i, d) { $(repl('\ %(item_code)s%(item_name)s\ Date: Wed, 18 Sep 2013 18:35:12 +0530 Subject: [PATCH 03/41] [pos] pos.js included in all selling & purchase cycle --- .../purchase_invoice/purchase_invoice.js | 1 + accounts/doctype/sales_invoice/pos.js | 67 +++++++++++-------- accounts/doctype/sales_invoice/pos.py | 15 +++-- .../doctype/sales_invoice/sales_invoice.css | 15 ----- .../doctype/sales_invoice/sales_invoice.js | 1 + .../doctype/purchase_order/purchase_order.js | 1 + .../supplier_quotation/supplier_quotation.js | 1 + public/js/startup.css | 17 +++++ public/js/transaction.js | 7 +- selling/doctype/quotation/quotation.js | 1 + stock/doctype/delivery_note/delivery_note.js | 1 + .../purchase_receipt/purchase_receipt.js | 1 + 12 files changed, 78 insertions(+), 50 deletions(-) delete mode 100644 accounts/doctype/sales_invoice/sales_invoice.css diff --git a/accounts/doctype/purchase_invoice/purchase_invoice.js b/accounts/doctype/purchase_invoice/purchase_invoice.js index 2428a7dae91..fb5569a5f0c 100644 --- a/accounts/doctype/purchase_invoice/purchase_invoice.js +++ b/accounts/doctype/purchase_invoice/purchase_invoice.js @@ -8,6 +8,7 @@ cur_frm.cscript.other_fname = "purchase_tax_details"; wn.provide("erpnext.accounts"); wn.require('app/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js'); wn.require('app/buying/doctype/purchase_common/purchase_common.js'); +wn.require('app/accounts/doctype/sales_invoice/pos.js'); erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({ onload: function() { diff --git a/accounts/doctype/sales_invoice/pos.js b/accounts/doctype/sales_invoice/pos.js index 67c4b93186a..ee34440b35a 100644 --- a/accounts/doctype/sales_invoice/pos.js +++ b/accounts/doctype/sales_invoice/pos.js @@ -7,7 +7,7 @@ erpnext.POS = Class.extend({ this.frm = frm; this.wrapper.html('
\
\ -
\ +
\
\
\
\ @@ -88,29 +88,31 @@ erpnext.POS = Class.extend({ }); }, make: function() { - this.make_customer(); + this.make_party(); this.make_item_group(); this.make_search(); this.make_barcode(); this.make_item_list(); }, - make_customer: function() { + make_party: function() { var me = this; - console.log(this.frm); - this.customer = wn.ui.form.make_control({ + this.party = wn.meta.has_field(cur_frm.doc.doctype, "customer") ?"Customer" : "Supplier"; + + this.party_field = wn.ui.form.make_control({ df: { "fieldtype": "Link", - "options": "Customer", - "label": "Customer", - "fieldname": "pos_customer", - "placeholder": "Customer" + "options": this.party, + "label": this.party, + "fieldname": "pos_party", + "placeholder": this.party }, - parent: this.wrapper.find(".customer-area") + parent: this.wrapper.find(".party-area") }); - this.customer.make_input(); - this.customer.$input.on("change", function() { - if(!me.customer.autocomplete_open) - wn.model.set_value(this.frm.doctype, me.frm.docname, "customer", this.value); + this.party_field.make_input(); + this.party_field.$input.on("change", function() { + if(!me.party_field.autocomplete_open) + wn.model.set_value(me.frm.doctype, me.frm.docname, + me.party.toLowerCase(), this.value); }); }, make_item_group: function() { @@ -169,10 +171,17 @@ erpnext.POS = Class.extend({ }, make_item_list: function() { var me = this; + var price_list = wn.meta.has_field(this.frm.doc.doctype, "selling_price_list") ? + this.frm.doc.selling_price_list : this.frm.doc.buying_price_list; + + var sales_or_purchase = wn.meta.has_field(this.frm.doc.doctype, "selling_price_list") ? + "Sales" : "Purchase"; + wn.call({ method: 'accounts.doctype.sales_invoice.pos.get_items', args: { - price_list: cur_frm.doc.selling_price_list, + sales_or_purchase: sales_or_purchase, + price_list: price_list, item_group: this.item_group.$input.val(), item: this.search.$input.val() }, @@ -203,8 +212,8 @@ erpnext.POS = Class.extend({ // if form is local then allow this function if (cur_frm.doc.docstatus===0) { $("div.pos-item").on("click", function() { - if(!cur_frm.doc.customer) { - msgprint("Please select customer first."); + if(!cur_frm.doc[me.party.toLowerCase()]) { + msgprint("Please select " + me.party + " first."); return; } me.add_to_cart($(this).attr("data-item_code")); @@ -222,8 +231,8 @@ erpnext.POS = Class.extend({ // check whether the item is already added if (no_of_items != 0) { - $.each(wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name, "entries", - this.frm.doctype), function(i, d) { + $.each(wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name, + this.frm.cscript.fname, this.frm.doctype), function(i, d) { if (d.item_code == item_code) caught = true; }); @@ -234,15 +243,16 @@ erpnext.POS = Class.extend({ me.update_qty(item_code, 1); } else { - var child = wn.model.add_child(me.frm.doc, this.frm.doctype + " Item", "entries"); + var child = wn.model.add_child(me.frm.doc, this.frm.doctype + " Item", + this.frm.cscript.fname); child.item_code = item_code; me.frm.cscript.item_code(me.frm.doc, child.doctype, child.name); } }, update_qty: function(item_code, qty, textbox_qty) { var me = this; - $.each(wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name, "entries", - this.frm.doctype), function(i, d) { + $.each(wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name, + this.frm.cscript.fname, this.frm.doctype), function(i, d) { if (d.item_code == item_code) { if (textbox_qty) { if (qty == 0 && d.item_code == item_code) @@ -260,14 +270,14 @@ erpnext.POS = Class.extend({ }, refresh: function() { var me = this; - this.customer.set_input(this.frm.doc.customer); + this.party_field.set_input(this.frm.doc[this.party.toLowerCase()]); this.barcode.set_input(""); // add items var $items = me.wrapper.find("#cart tbody").empty(); - $.each(wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name, "entries", - this.frm.doctype), function(i, d) { + $.each(wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name, + this.frm.cscript.fname, this.frm.doctype), function(i, d) { $(repl('\ %(item_code)s%(item_name)s\ Date: Thu, 19 Sep 2013 16:14:16 +0530 Subject: [PATCH 04/41] [fix] set qty=1 for all purchase cycle --- buying/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buying/utils.py b/buying/utils.py index f4fb2f3ff87..179db9bf464 100644 --- a/buying/utils.py +++ b/buying/utils.py @@ -65,7 +65,7 @@ def _get_basic_details(args, item_bean): out = webnotes._dict({ "description": item.description_html or item.description, - "qty": 0.0, + "qty": 1.0, "uom": item.stock_uom, "conversion_factor": 1.0, "warehouse": args.warehouse or item.default_warehouse, From e9470815523489006445247435cc24eb350a9757 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Thu, 19 Sep 2013 19:09:15 +0530 Subject: [PATCH 05/41] [pos] pos view in all sales & purchase cycle finished --- accounts/doctype/sales_invoice/pos.js | 71 +++++++++++-------- .../doctype/sales_invoice/sales_invoice.txt | 5 +- buying/utils.py | 2 +- 3 files changed, 46 insertions(+), 32 deletions(-) diff --git a/accounts/doctype/sales_invoice/pos.js b/accounts/doctype/sales_invoice/pos.js index ee34440b35a..c76db1394f9 100644 --- a/accounts/doctype/sales_invoice/pos.js +++ b/accounts/doctype/sales_invoice/pos.js @@ -71,7 +71,18 @@ erpnext.POS = Class.extend({
\
\ '); - + + if (wn.meta.has_field(cur_frm.doc.doctype, "customer")) { + this.party = "Customer"; + this.price_list = this.frm.doc.selling_price_list; + this.sales_or_purchase = "Sales"; + } + else if (wn.meta.has_field(cur_frm.doc.doctype, "supplier")) { + this.party = "Supplier"; + this.price_list = this.frm.doc.buying_price_list; + this.sales_or_purchase = "Purchase"; + } + this.make(); var me = this; @@ -95,9 +106,7 @@ erpnext.POS = Class.extend({ this.make_item_list(); }, make_party: function() { - var me = this; - this.party = wn.meta.has_field(cur_frm.doc.doctype, "customer") ?"Customer" : "Supplier"; - + var me = this; this.party_field = wn.ui.form.make_control({ df: { "fieldtype": "Link", @@ -170,18 +179,12 @@ erpnext.POS = Class.extend({ }); }, make_item_list: function() { - var me = this; - var price_list = wn.meta.has_field(this.frm.doc.doctype, "selling_price_list") ? - this.frm.doc.selling_price_list : this.frm.doc.buying_price_list; - - var sales_or_purchase = wn.meta.has_field(this.frm.doc.doctype, "selling_price_list") ? - "Sales" : "Purchase"; - + var me = this; wn.call({ method: 'accounts.doctype.sales_invoice.pos.get_items', args: { - sales_or_purchase: sales_or_purchase, - price_list: price_list, + sales_or_purchase: this.sales_or_purchase, + price_list: this.price_list, item_group: this.item_group.$input.val(), item: this.search.$input.val() }, @@ -216,7 +219,8 @@ erpnext.POS = Class.extend({ msgprint("Please select " + me.party + " first."); return; } - me.add_to_cart($(this).attr("data-item_code")); + else + me.add_to_cart($(this).attr("data-item_code")); }); } } @@ -227,8 +231,8 @@ erpnext.POS = Class.extend({ var caught = false; // get no_of_items - no_of_items = me.wrapper.find("#cart tbody").length; - + var no_of_items = me.wrapper.find("#cart tbody tr").length; + // check whether the item is already added if (no_of_items != 0) { $.each(wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name, @@ -288,15 +292,15 @@ erpnext.POS = Class.extend({ item_code: d.item_code, 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) + rate: format_currency(d.ref_rate, cur_frm.doc.currency), + amount: format_currency(d.export_amount, cur_frm.doc.currency) } )).appendTo($items); }); // taxes - var taxes = wn.model.get_children("Sales Taxes and Charges", this.frm.doc.name, "other_charges", - this.frm.doctype); + var taxes = wn.model.get_children(this.sales_or_purchase + " Taxes and Charges", + this.frm.doc.name, this.frm.cscript.other_fname, this.frm.doctype); $(".tax-table") .toggle((taxes && taxes.length) ? true : false) .find("tbody").empty(); @@ -308,15 +312,15 @@ erpnext.POS = Class.extend({ ', { description: d.description, rate: d.rate, - tax_amount: format_currency(d.tax_amount, me.frm.doc.price_list_currency) + tax_amount: format_currency(d.tax_amount, me.frm.doc.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)); + cur_frm.doc.currency)); this.wrapper.find(".grand-total").text(format_currency(this.frm.doc.grand_total_export, - cur_frm.doc.price_list_currency)); + cur_frm.doc.currency)); // if form is local then only run all these functions if (cur_frm.doc.docstatus===0) { @@ -331,7 +335,7 @@ erpnext.POS = Class.extend({ }); // on td click toggle the highlighting of row - $("#cart tbody tr td").on("click", function() { + me.wrapper.find("#cart tbody tr td").on("click", function() { var row = $(this).closest("tr"); if (row.attr("data-selected") == "false") { row.attr("class", "warning"); @@ -345,18 +349,26 @@ erpnext.POS = Class.extend({ }); + this.make_item_list(); me.refresh_delete_btn(); cur_frm.pos.barcode.$input.focus(); } // if form is submitted & cancelled then disable all input box & buttons - if (cur_frm.doc.docstatus>=1 && cint(cur_frm.doc.is_pos)) { + if (cur_frm.doc.docstatus>=1) { me.wrapper.find('input, button').each(function () { $(this).prop('disabled', true); }); $(".delete-items").hide(); $(".make-payment").hide(); } + + // Show Make Payment button only in Sales Invoice + if (this.frm.doctype != "Sales Invoice") + $(".make-payment").hide(); + + if (this.frm.doctype == "Quotation") + $(".party-area").toggle(cur_frm.doc.quotation_to=="Customer" ? true : false) }, refresh_delete_btn: function() { $(".delete-items").toggle($(".item-cart .warning").length ? true : false); @@ -381,16 +393,17 @@ erpnext.POS = Class.extend({ remove_selected_item: function() { var me = this; var selected_items = []; - var no_of_items = $("#cart tbody tr").length; + var no_of_items = me.wrapper.find("#cart tbody tr").length; for(var x=0; x<=no_of_items - 1; x++) { - var row = $("#cart tbody tr:eq(" + x + ")"); + var row = me.wrapper.find("#cart tbody tr:eq(" + x + ")"); if(row.attr("data-selected") == "true") { selected_items.push(row.attr("id")); } } - + var child = wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name, this.frm.cscript.fname, this.frm.doctype); + $.each(child, function(i, d) { for (var i in selected_items) { if (d.item_code == selected_items[i]) { @@ -405,7 +418,7 @@ erpnext.POS = Class.extend({ }, make_payment: function() { var me = this; - var no_of_items = $("#cart tbody tr").length; + var no_of_items = me.wrapper.find("#cart tbody tr").length; var mode_of_payment = []; if (no_of_items == 0) diff --git a/accounts/doctype/sales_invoice/sales_invoice.txt b/accounts/doctype/sales_invoice/sales_invoice.txt index f921f242234..00c6c2cc5c5 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.txt +++ b/accounts/doctype/sales_invoice/sales_invoice.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-24 19:29:05", "docstatus": 0, - "modified": "2013-09-01 05:26:13", + "modified": "2013-09-19 11:42:13", "modified_by": "Administrator", "owner": "Administrator" }, @@ -180,6 +180,7 @@ "search_index": 1 }, { + "default": "Today", "description": "Enter the date by which payments from customer is expected against this invoice.", "doctype": "DocField", "fieldname": "due_date", @@ -411,7 +412,7 @@ "doctype": "DocField", "fieldname": "other_charges", "fieldtype": "Table", - "label": "Taxes and Charges1", + "label": "Sales Taxes and Charges", "oldfieldname": "other_charges", "oldfieldtype": "Table", "options": "Sales Taxes and Charges", diff --git a/buying/utils.py b/buying/utils.py index f4fb2f3ff87..179db9bf464 100644 --- a/buying/utils.py +++ b/buying/utils.py @@ -65,7 +65,7 @@ def _get_basic_details(args, item_bean): out = webnotes._dict({ "description": item.description_html or item.description, - "qty": 0.0, + "qty": 1.0, "uom": item.stock_uom, "conversion_factor": 1.0, "warehouse": args.warehouse or item.default_warehouse, From f624ffa40abcf5aca9c4d0c6295f5bb00c856ca9 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Mon, 23 Sep 2013 12:27:16 +0530 Subject: [PATCH 06/41] [pos] refresh() to be called at minimum --- accounts/doctype/sales_invoice/pos.js | 8 +-- .../doctype/sales_invoice/sales_invoice.js | 50 +------------------ public/js/transaction.js | 2 +- 3 files changed, 6 insertions(+), 54 deletions(-) diff --git a/accounts/doctype/sales_invoice/pos.js b/accounts/doctype/sales_invoice/pos.js index c76db1394f9..4ef239744b6 100644 --- a/accounts/doctype/sales_invoice/pos.js +++ b/accounts/doctype/sales_invoice/pos.js @@ -106,7 +106,7 @@ erpnext.POS = Class.extend({ this.make_item_list(); }, make_party: function() { - var me = this; + var me = this; this.party_field = wn.ui.form.make_control({ df: { "fieldtype": "Link", @@ -179,7 +179,7 @@ erpnext.POS = Class.extend({ }); }, make_item_list: function() { - var me = this; + var me = this; wn.call({ method: 'accounts.doctype.sales_invoice.pos.get_items', args: { @@ -349,7 +349,6 @@ erpnext.POS = Class.extend({ }); - this.make_item_list(); me.refresh_delete_btn(); cur_frm.pos.barcode.$input.focus(); } @@ -368,7 +367,8 @@ erpnext.POS = Class.extend({ $(".make-payment").hide(); if (this.frm.doctype == "Quotation") - $(".party-area").toggle(cur_frm.doc.quotation_to=="Customer" ? true : false) + if (cur_frm.doc.quotation_to=="Customer") + this.party_field.remove(); }, refresh_delete_btn: function() { $(".delete-items").toggle($(".item-cart .warning").length ? true : false); diff --git a/accounts/doctype/sales_invoice/sales_invoice.js b/accounts/doctype/sales_invoice/sales_invoice.js index e07ed2816d3..13cbc634dd2 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.js +++ b/accounts/doctype/sales_invoice/sales_invoice.js @@ -121,54 +121,6 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte }); }); }, - - // 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"; - - // cur_frm.cscript.sales_order_btn(); - // cur_frm.cscript.delivery_note_btn(); - // } else { - // var btn_label = wn._("Invoice View"), - // icon = "icon-file-text"; - - // if (cur_frm.doc.docstatus===0) { - // this.$delivery_note_btn.remove(); - // this.$sales_order_btn.remove(); - // } - // } - - // 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) { - // 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(); - // } - // }, tc_name: function() { this.get_terms(); @@ -176,7 +128,6 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte is_pos: function() { cur_frm.cscript.hide_fields(this.frm.doc); - if(cint(this.frm.doc.is_pos)) { if(!this.frm.doc.company) { this.frm.set_value("is_pos", 0); @@ -194,6 +145,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte }); } } + }, debit_to: function() { diff --git a/public/js/transaction.js b/public/js/transaction.js index a38e3a777cc..1a1c98ca6bf 100644 --- a/public/js/transaction.js +++ b/public/js/transaction.js @@ -98,7 +98,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ if((show===true && this.pos_active) || (show===false && !this.pos_active)) return; // make pos - if(!this.pos) { + if(!this.frm.pos) { this.frm.layout.add_view("pos"); this.frm.pos = new erpnext.POS(this.frm.layout.views.pos, this.frm); } From 10dce341c823d107d81246a87c07a82bcf1ca90b Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Wed, 25 Sep 2013 11:09:33 +0530 Subject: [PATCH 07/41] [pos] pos view fixed for all purchase & sales cycle --- .../purchase_invoice/purchase_invoice.py | 25 ++++----- accounts/doctype/sales_invoice/pos.js | 52 ++++++++++++++----- accounts/doctype/sales_invoice/pos.py | 6 ++- .../purchase_common/purchase_common.js | 3 +- public/js/transaction.js | 23 ++++++++ selling/doctype/sales_common/sales_common.js | 3 +- selling/utils/__init__.py | 1 + utilities/transaction_base.py | 1 + 8 files changed, 83 insertions(+), 31 deletions(-) diff --git a/accounts/doctype/purchase_invoice/purchase_invoice.py b/accounts/doctype/purchase_invoice/purchase_invoice.py index 05383235614..ad7ebd90de9 100644 --- a/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -62,19 +62,20 @@ class DocType(BuyingController): "purchase_receipt_details") def get_credit_to(self): - acc_head = sql("""select name, credit_days from `tabAccount` - where (name = %s or (master_name = %s and master_type = 'supplier')) - and docstatus != 2 and company = %s""", - (cstr(self.doc.supplier) + " - " + self.company_abbr, - self.doc.supplier, self.doc.company)) - ret = {} - if acc_head and acc_head[0][0]: - ret['credit_to'] = acc_head[0][0] - if not self.doc.due_date: - ret['due_date'] = add_days(cstr(self.doc.posting_date), acc_head and cint(acc_head[0][1]) or 0) - elif not acc_head: - msgprint("%s does not have an Account Head in %s. You must first create it from the Supplier Master" % (self.doc.supplier, self.doc.company)) + if self.doc.supplier: + acc_head = sql("""select name, credit_days from `tabAccount` + where (name = %s or (master_name = %s and master_type = 'supplier')) + and docstatus != 2 and company = %s""", + (cstr(self.doc.supplier) + " - " + self.company_abbr, + self.doc.supplier, self.doc.company)) + + if acc_head and acc_head[0][0]: + ret['credit_to'] = acc_head[0][0] + if not self.doc.due_date: + ret['due_date'] = add_days(cstr(self.doc.posting_date), acc_head and cint(acc_head[0][1]) or 0) + elif not acc_head: + msgprint("%s does not have an Account Head in %s. You must first create it from the Supplier Master" % (self.doc.supplier, self.doc.company)) return ret def set_supplier_defaults(self): diff --git a/accounts/doctype/sales_invoice/pos.js b/accounts/doctype/sales_invoice/pos.js index 4ef239744b6..ca5618b3454 100644 --- a/accounts/doctype/sales_invoice/pos.js +++ b/accounts/doctype/sales_invoice/pos.js @@ -132,7 +132,7 @@ erpnext.POS = Class.extend({ "options": "Item Group", "label": "Item Group", "fieldname": "pos_item_group", - "placeholder": "Filter by Item Group" + "placeholder": "Item Group" }, parent: this.wrapper.find(".item-group-area") }); @@ -150,7 +150,7 @@ erpnext.POS = Class.extend({ "options": "Item", "label": "Item", "fieldname": "pos_item", - "placeholder": "Select Item" + "placeholder": "Item" }, parent: this.wrapper.find(".search-area") }); @@ -167,7 +167,7 @@ erpnext.POS = Class.extend({ "fieldtype": "Data", "label": "Barcode", "fieldname": "pos_barcode", - "placeholder": "Select Barcode" + "placeholder": "Barcode" }, parent: this.wrapper.find(".barcode-area") }); @@ -215,7 +215,9 @@ erpnext.POS = Class.extend({ // if form is local then allow this function if (cur_frm.doc.docstatus===0) { $("div.pos-item").on("click", function() { - if(!cur_frm.doc[me.party.toLowerCase()]) { + if(!cur_frm.doc[me.party.toLowerCase()] && ((me.frm.doctype == "Quotation" && + cur_frm.doc.quotation_to == "Customer") + || me.frm.doctype != "Quotation")) { msgprint("Please select " + me.party + " first."); return; } @@ -282,6 +284,16 @@ erpnext.POS = Class.extend({ $.each(wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name, this.frm.cscript.fname, this.frm.doctype), function(i, d) { + + if (me.sales_or_purchase == "Sales") { + item_amount = d.export_amount; + rate = d.export_rate; + } + else { + item_amount = d.import_amount; + rate = d.import_rate; + } + $(repl('\ %(item_code)s%(item_name)s\ " + d.item_name), qty: d.qty, - rate: format_currency(d.ref_rate, cur_frm.doc.currency), - amount: format_currency(d.export_amount, cur_frm.doc.currency) + rate: format_currency(rate, cur_frm.doc.currency), + amount: format_currency(item_amount, cur_frm.doc.currency) } )).appendTo($items); }); @@ -312,15 +324,24 @@ erpnext.POS = Class.extend({ ', { description: d.description, rate: d.rate, - tax_amount: format_currency(d.tax_amount, me.frm.doc.currency) + tax_amount: format_currency(flt(d.tax_amount)/flt(me.frm.doc.conversion_rate), + me.frm.doc.currency) })).appendTo(".tax-table tbody"); }); // set totals - this.wrapper.find(".net-total").text(format_currency(this.frm.doc.net_total_export, - cur_frm.doc.currency)); - this.wrapper.find(".grand-total").text(format_currency(this.frm.doc.grand_total_export, - cur_frm.doc.currency)); + if (this.sales_or_purchase == "Sales") { + this.wrapper.find(".net-total").text(format_currency(this.frm.doc.net_total_export, + cur_frm.doc.currency)); + this.wrapper.find(".grand-total").text(format_currency(this.frm.doc.grand_total_export, + cur_frm.doc.currency)); + } + else { + this.wrapper.find(".net-total").text(format_currency(this.frm.doc.net_total_import, + cur_frm.doc.currency)); + this.wrapper.find(".grand-total").text(format_currency(this.frm.doc.grand_total_import, + cur_frm.doc.currency)); + } // if form is local then only run all these functions if (cur_frm.doc.docstatus===0) { @@ -366,9 +387,12 @@ erpnext.POS = Class.extend({ if (this.frm.doctype != "Sales Invoice") $(".make-payment").hide(); - if (this.frm.doctype == "Quotation") - if (cur_frm.doc.quotation_to=="Customer") - this.party_field.remove(); + // If quotation to is not Customer then remove party + if (this.frm.doctype == "Quotation") { + this.party_field.$wrapper.remove(); + if (cur_frm.doc.quotation_to == "Customer") + this.make_party(); + } }, refresh_delete_btn: function() { $(".delete-items").toggle($(".item-cart .warning").length ? true : false); diff --git a/accounts/doctype/sales_invoice/pos.py b/accounts/doctype/sales_invoice/pos.py index d919c1b548c..44fe40d8de9 100644 --- a/accounts/doctype/sales_invoice/pos.py +++ b/accounts/doctype/sales_invoice/pos.py @@ -3,7 +3,6 @@ from __future__ import unicode_literals import webnotes -from webnotes import msgprint, errprint @webnotes.whitelist() def get_items(price_list, sales_or_purchase, item=None, item_group=None): @@ -36,6 +35,11 @@ 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_item_from_serial_no(serial_no): + return webnotes.conn.sql("""select name, item_code from `tabSerial No` where + name=%s""", (serial_no), 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/buying/doctype/purchase_common/purchase_common.js b/buying/doctype/purchase_common/purchase_common.js index 2dfe65515a8..433a76fba7c 100644 --- a/buying/doctype/purchase_common/purchase_common.js +++ b/buying/doctype/purchase_common/purchase_common.js @@ -108,8 +108,7 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({ var item = wn.model.get_doc(cdt, cdn); if(item.item_code) { if(!this.validate_company_and_party("supplier")) { - item.item_code = null; - refresh_field("item_code", item.name, item.parentfield); + cur_frm.fields_dict[me.frm.cscript.fname].grid.grid_rows[item.idx - 1].remove(); } else { return this.frm.call({ method: "buying.utils.get_item_details", diff --git a/public/js/transaction.js b/public/js/transaction.js index 1a1c98ca6bf..e12d1084e98 100644 --- a/public/js/transaction.js +++ b/public/js/transaction.js @@ -232,6 +232,29 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ tax_rate: function(doc, cdt, cdn) { this.calculate_taxes_and_totals(); }, + + // serial_no: function(doc, cdt, cdn) { + // var me = this; + // var item = wn.model.get_doc(cdt, cdn); + // if (!item.item_code) { + // wn.call({ + // method: 'accounts.doctype.sales_invoice.pos.get_item_from_serial_no', + // args: {serial_no: this.serial_no.$input.val()}, + // callback: function(r) { + // if (r.message) { + // var item_code = r.message[0].item_code; + // var child = wn.model.add_child(me.frm.doc, this.frm.doctype + " Item", + // this.frm.cscript.fname); + // child.item_code = item_code; + // me.frm.cscript.item_code(me.frm.doc, child.doctype, child.name); + // } + // else + // msgprint(wn._("Invalid Serial No.")); + // me.refresh(); + // } + // }); + // } + // }, row_id: function(doc, cdt, cdn) { var tax = wn.model.get_doc(cdt, cdn); diff --git a/selling/doctype/sales_common/sales_common.js b/selling/doctype/sales_common/sales_common.js index dc58377e4bf..c87e823dbab 100644 --- a/selling/doctype/sales_common/sales_common.js +++ b/selling/doctype/sales_common/sales_common.js @@ -162,8 +162,7 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ var item = wn.model.get_doc(cdt, cdn); if(item.item_code || item.barcode) { if(!this.validate_company_and_party("customer")) { - item.item_code = null; - refresh_field("item_code", item.name, item.parentfield); + cur_frm.fields_dict[me.frm.cscript.fname].grid.grid_rows[item.idx - 1].remove(); } else { return this.frm.call({ method: "selling.utils.get_item_details", diff --git a/selling/utils/__init__.py b/selling/utils/__init__.py index 224944dd884..801d82bf40e 100644 --- a/selling/utils/__init__.py +++ b/selling/utils/__init__.py @@ -34,6 +34,7 @@ def get_item_details(args): "plc_conversion_rate": 1.0 } """ + if isinstance(args, basestring): args = json.loads(args) args = webnotes._dict(args) diff --git a/utilities/transaction_base.py b/utilities/transaction_base.py index 2535db7ab57..57591fd321b 100644 --- a/utilities/transaction_base.py +++ b/utilities/transaction_base.py @@ -425,6 +425,7 @@ def get_address_territory(address_doc): def validate_conversion_rate(currency, conversion_rate, conversion_rate_label, company): """common validation for currency and price list currency""" + if conversion_rate == 0: msgprint(conversion_rate_label + _(' cannot be 0'), raise_exception=True) From ce94ab87ea45309ad1cc7e4c1018f99ddfb717b1 Mon Sep 17 00:00:00 2001 From: Priya Date: Wed, 25 Sep 2013 17:20:41 +0530 Subject: [PATCH 08/41] [docs] stock reconciliation --- .../docs.user.accounts.opening_stock.md | 25 ++++++++++++++++++- docs/user/docs.user.md | 2 +- docs/user/stock/docs.user.stock.md | 1 + 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/docs/user/accounts/docs.user.accounts.opening_stock.md b/docs/user/accounts/docs.user.accounts.opening_stock.md index 3ba5025747a..b0927bd8652 100644 --- a/docs/user/accounts/docs.user.accounts.opening_stock.md +++ b/docs/user/accounts/docs.user.accounts.opening_stock.md @@ -17,5 +17,28 @@ To make a Stock Reconciliation, go to: and follow the steps mentioned on the page. -![Stock Reconciliation](img/stock-reconciliation1.png) +#### Step 1: Download Template + +![Stock Reconciliation](img/stock-reconciliation-1.png) + +#### Step 2: Enter Data in csv file. + + +![Stock Reconciliation](img/stock-reconciliation-csv-1.png) + +The csv format is case-sensitive. Thus special care should be taken to avoid spelling errors or wrong names. Even if you do not list some quantities or valuation rates, the file will still process the data. + +#### Step 3: Upload the csv file with data + +![Stock Reconciliation](img/stock-reconciliation-2.png) + +
+ +#### Step 4: Attach the uploaded file. + +![Stock Reconciliation](img/stock-reconciliation-3.png) + + + +After reviewing saved Reconciliation Data, submit the Stock Reconciliation. On successful submission, the data will be updated in the system. To check the uploaded data go to Stock and view Stock Level Report. \ No newline at end of file diff --git a/docs/user/docs.user.md b/docs/user/docs.user.md index d15a573e1a2..d9e7f2aac00 100644 --- a/docs/user/docs.user.md +++ b/docs/user/docs.user.md @@ -85,6 +85,7 @@ Contents 1. [Purchase Receipt](docs.user.stock.purchase_receipt.html) 1. [Delivery Note](docs.user.stock.delivery_note.html) 1. [Stock Entry / Material Transfer](docs.user.stock.stock_entry.html) + 1. [Opening Stock](docs.user.accounts.opening_stock.html) 1. [Material Issue](docs.user.stock.material_issue.html) 1. [Sales Return](docs.user.stock.sales_return.html) 1. [Purchase Return](docs.user.stock.purchase_return.html) @@ -100,7 +101,6 @@ Contents 1. [Payment Entry](docs.user.accounts.payments.html) 1. [Journal Voucher](docs.user.accounts.journal_voucher.html) 1. [Opening Entry](docs.user.accounts.opening_entry.html) - 1. [Opening Stock](docs.user.accounts.opening_stock.html) 1. [Period Closing](docs.user.accounts.closing.html) 1. [Accounting Reports](docs.user.accounts.reports.html) 1. [Point of Sale (POS) Invoice](docs.user.accounts.pos.html) diff --git a/docs/user/stock/docs.user.stock.md b/docs/user/stock/docs.user.stock.md index 08f16f84308..a8c74c9175c 100644 --- a/docs/user/stock/docs.user.stock.md +++ b/docs/user/stock/docs.user.stock.md @@ -9,6 +9,7 @@ "docs.user.stock.purchase_receipt", "docs.user.stock.delivery_note", "docs.user.stock.stock_entry", + "docs.user.stock.opening_stock", "docs.user.stock.material_issue", "docs.user.stock.sales_return", "docs.user.stock.purchase_return", From 1ec5109a1a52a213b0e0a4e495afa09d6c206d58 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 25 Sep 2013 19:58:32 +0530 Subject: [PATCH 09/41] Reduce ordered qty in Purchase Receipt based on PO warehouse --- accounts/doctype/gl_entry/gl_entry.py | 2 +- .../purchase_order/test_purchase_order.py | 51 +++++++++++++++- .../purchase_receipt/purchase_receipt.py | 60 +++++++++++-------- stock/doctype/warehouse/warehouse.py | 8 +-- utilities/transaction_base.py | 3 +- 5 files changed, 90 insertions(+), 34 deletions(-) diff --git a/accounts/doctype/gl_entry/gl_entry.py b/accounts/doctype/gl_entry/gl_entry.py index 8338a5b153e..db6de44f095 100644 --- a/accounts/doctype/gl_entry/gl_entry.py +++ b/accounts/doctype/gl_entry/gl_entry.py @@ -117,7 +117,7 @@ def check_negative_balance(account, adv_adj=False): flt(balance[0][0]) or -1*flt(balance[0][0]) if flt(balance) < 0: - webnotes.throw(_("Negative balance is not allowed for account ") + self.doc.account) + webnotes.throw(_("Negative balance is not allowed for account ") + account) def check_freezing_date(posting_date, adv_adj=False): """ diff --git a/buying/doctype/purchase_order/test_purchase_order.py b/buying/doctype/purchase_order/test_purchase_order.py index e160babc59a..cef5e4a207b 100644 --- a/buying/doctype/purchase_order/test_purchase_order.py +++ b/buying/doctype/purchase_order/test_purchase_order.py @@ -6,9 +6,10 @@ from __future__ import unicode_literals import unittest import webnotes import webnotes.defaults +from webnotes.utils import flt class TestPurchaseOrder(unittest.TestCase): - def test_make_purchase_receipt(self): + def test_make_purchase_receipt(self): from buying.doctype.purchase_order.purchase_order import make_purchase_receipt po = webnotes.bean(copy=test_records[0]).insert() @@ -18,6 +19,7 @@ class TestPurchaseOrder(unittest.TestCase): po = webnotes.bean("Purchase Order", po.doc.name) po.submit() + pr = make_purchase_receipt(po.doc.name) pr[0]["supplier_warehouse"] = "_Test Warehouse 1 - _TC" @@ -25,7 +27,52 @@ class TestPurchaseOrder(unittest.TestCase): self.assertEquals(len(pr), len(test_records[0])) pr[0].naming_series = "_T-Purchase Receipt-" - webnotes.bean(pr).insert() + pr_bean = webnotes.bean(pr) + pr_bean.insert() + + def test_ordered_qty(self): + webnotes.conn.sql("delete from tabBin") + + from buying.doctype.purchase_order.purchase_order import make_purchase_receipt + + po = webnotes.bean(copy=test_records[0]).insert() + + self.assertRaises(webnotes.ValidationError, make_purchase_receipt, + po.doc.name) + + po = webnotes.bean("Purchase Order", po.doc.name) + po.doc.is_subcontracted = "No" + po.doclist[1].item_code = "_Test Item" + po.submit() + + self.assertEquals(webnotes.conn.get_value("Bin", {"item_code": "_Test Item", + "warehouse": "_Test Warehouse - _TC"}, "ordered_qty"), 10) + + pr = make_purchase_receipt(po.doc.name) + + self.assertEquals(pr[0]["doctype"], "Purchase Receipt") + self.assertEquals(len(pr), len(test_records[0])) + + pr[0].naming_series = "_T-Purchase Receipt-" + pr[1].qty = 4.0 + pr_bean = webnotes.bean(pr) + pr_bean.insert() + pr_bean.submit() + + self.assertEquals(flt(webnotes.conn.get_value("Bin", {"item_code": "_Test Item", + "warehouse": "_Test Warehouse - _TC"}, "ordered_qty")), 6.0) + + webnotes.conn.set_value('Item', '_Test Item', 'tolerance', 50) + + pr1 = make_purchase_receipt(po.doc.name) + pr1[0].naming_series = "_T-Purchase Receipt-" + pr1[1].qty = 8 + pr1_bean = webnotes.bean(pr1) + pr1_bean.insert() + pr1_bean.submit() + + self.assertEquals(flt(webnotes.conn.get_value("Bin", {"item_code": "_Test Item", + "warehouse": "_Test Warehouse - _TC"}, "ordered_qty")), 0.0) def test_make_purchase_invocie(self): from buying.doctype.purchase_order.purchase_order import make_purchase_invoice diff --git a/stock/doctype/purchase_receipt/purchase_receipt.py b/stock/doctype/purchase_receipt/purchase_receipt.py index 278becd7e15..7d663b87786 100644 --- a/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/stock/doctype/purchase_receipt/purchase_receipt.py @@ -117,8 +117,7 @@ class DocType(BuyingController): }, "Purchase Order Item": { "ref_dn_field": "prevdoc_detail_docname", - "compare_fields": [["project_name", "="], ["warehouse", "="], - ["uom", "="], ["item_code", "="]], + "compare_fields": [["project_name", "="], ["uom", "="], ["item_code", "="]], "is_child_table": True } }) @@ -165,34 +164,43 @@ class DocType(BuyingController): self.bk_flush_supp_wh(sl_entries) self.make_sl_entries(sl_entries) - - def update_ordered_qty(self, is_cancelled="No"): - pc_obj = get_obj('Purchase Common') + + def update_ordered_qty(self): stock_items = self.get_stock_items() - for d in getlist(self.doclist, 'purchase_receipt_details'): + for d in self.doclist.get({"parentfield": "purchase_receipt_details"}): if d.item_code in stock_items and d.warehouse \ and cstr(d.prevdoc_doctype) == 'Purchase Order': - pr_qty = flt(d.qty) * flt(d.conversion_factor) - - # get qty and pending_qty of prevdoc - curr_ref_qty = pc_obj.get_qty(d.doctype, 'prevdoc_detail_docname', - d.prevdoc_detail_docname, 'Purchase Order Item', - 'Purchase Order - Purchase Receipt', self.doc.name) - max_qty, qty, curr_qty = flt(curr_ref_qty.split('~~~')[1]), \ - flt(curr_ref_qty.split('~~~')[0]), 0 - - if flt(qty) + flt(pr_qty) > flt(max_qty): - curr_qty = (flt(max_qty) - flt(qty)) * flt(d.conversion_factor) + + already_received_qty = self.get_already_received_qty(d.prevdoc_docname, + d.prevdoc_detail_docname) + po_qty, ordered_warehouse = self.get_po_qty_and_warehouse(d.prevdoc_detail_docname) + + if not ordered_warehouse: + webnotes.throw(_("Warehouse is missing in Purchase Order")) + + if already_received_qty + d.qty > po_qty: + ordered_qty = - (po_qty - already_received_qty) * flt(d.conversion_factor) else: - curr_qty = flt(pr_qty) - - args = { + ordered_qty = - flt(d.qty) * flt(d.conversion_factor) + + update_bin({ "item_code": d.item_code, - "warehouse": d.warehouse, + "warehouse": ordered_warehouse, "posting_date": self.doc.posting_date, - "ordered_qty": (is_cancelled=="Yes" and -1 or 1)*flt(curr_qty) - } - update_bin(args) + "ordered_qty": flt(ordered_qty) if self.doc.docstatus==1 else -flt(ordered_qty) + }) + + def get_already_received_qty(self, po, po_detail): + qty = webnotes.conn.sql("""select sum(qty) from `tabPurchase Receipt Item` + where prevdoc_detail_docname = %s and docstatus = 1 + and prevdoc_doctype='Purchase Order' and prevdoc_docname=%s + and parent != %s""", (po_detail, po, self.doc.name)) + return qty and flt(qty[0][0]) or 0.0 + + def get_po_qty_and_warehouse(self, po_detail): + po_qty, po_warehouse = webnotes.conn.get_value("Purchase Order Item", po_detail, + ["qty", "warehouse"]) + return po_qty, po_warehouse def bk_flush_supp_wh(self, sl_entries): for d in getlist(self.doclist, 'pr_raw_material_details'): @@ -201,7 +209,7 @@ class DocType(BuyingController): sl_entries.append(self.get_sl_entries(d, { "item_code": d.rm_item_code, "warehouse": self.doc.supplier_warehouse, - "actual_qty": -1*flt(consumed_qty), + "actual_qty": -1*flt(d.consumed_qty), "incoming_rate": 0 })) @@ -281,7 +289,7 @@ class DocType(BuyingController): webnotes.conn.set(self.doc,'status','Cancelled') - self.update_ordered_qty(is_cancelled="Yes") + self.update_ordered_qty() self.update_stock() self.update_serial_nos(cancel=True) diff --git a/stock/doctype/warehouse/warehouse.py b/stock/doctype/warehouse/warehouse.py index c2b3284608a..58cf11bfdfc 100644 --- a/stock/doctype/warehouse/warehouse.py +++ b/stock/doctype/warehouse/warehouse.py @@ -59,10 +59,7 @@ class DocType: else: webnotes.throw(_("Please enter account group under which account \ for warehouse ") + self.doc.name +_(" will be created")) - - def on_rename(self, new, old): - webnotes.conn.set_value("Account", {"account_type": "Warehouse", "master_name": old}, - "master_name", new) + def merge_warehouses(self): webnotes.conn.auto_commit_on_many_writes = 1 @@ -207,6 +204,9 @@ class DocType: sql("delete from `tabStock Ledger Entry` where warehouse = %s", self.doc.name) def on_rename(self, newdn, olddn, merge=False): + webnotes.conn.set_value("Account", {"account_type": "Warehouse", "master_name": olddn}, + "master_name", newdn) + if merge: from stock.stock_ledger import update_entries_after for item_code in webnotes.conn.sql("""select item_code from `tabBin` diff --git a/utilities/transaction_base.py b/utilities/transaction_base.py index 2535db7ab57..0655567c243 100644 --- a/utilities/transaction_base.py +++ b/utilities/transaction_base.py @@ -143,7 +143,8 @@ class TransactionBase(StatusUpdater): self.doc.fields.update(self.get_lead_defaults()) def get_customer_address(self, args): - args = load_json(args) + args = load_json(args) + webnotes.errprint(args) ret = { 'customer_address' : args["address"], 'address_display' : get_address_display(args["address"]), From 16ec981bfd2600dcacf6bb8cb482cf5174b44485 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 25 Sep 2013 20:00:22 +0530 Subject: [PATCH 10/41] [cleanup] [minor] fetch lead details in opportunity --- selling/doctype/lead/lead.js | 11 +-- selling/doctype/lead/lead.py | 4 + selling/doctype/opportunity/opportunity.js | 18 +++- selling/doctype/opportunity/opportunity.txt | 100 ++++++++++---------- 4 files changed, 69 insertions(+), 64 deletions(-) diff --git a/selling/doctype/lead/lead.js b/selling/doctype/lead/lead.js index a3ae7838672..3c6fda7922c 100644 --- a/selling/doctype/lead/lead.js +++ b/selling/doctype/lead/lead.js @@ -33,16 +33,7 @@ erpnext.LeadController = wn.ui.form.Controller.extend({ var doc = this.frm.doc; erpnext.hide_naming_series(); this.frm.clear_custom_buttons(); - - this.frm.dashboard.reset(doc); - if(!doc.__islocal) { - if(doc.status=="Converted") { - this.frm.dashboard.set_headline_alert(wn._("Converted"), "alert-success", "icon-ok-sign"); - } else { - this.frm.dashboard.set_headline_alert(wn._(doc.status), "alert-info", "icon-exclamation-sign"); - } - } - + this.frm.__is_customer = this.frm.__is_customer || this.frm.doc.__is_customer; if(!this.frm.doc.__islocal && !this.frm.__is_customer) { this.frm.add_custom_button("Create Customer", this.create_customer); diff --git a/selling/doctype/lead/lead.py b/selling/doctype/lead/lead.py index da11410f24f..316481cbaa7 100644 --- a/selling/doctype/lead/lead.py +++ b/selling/doctype/lead/lead.py @@ -126,6 +126,10 @@ def make_opportunity(source_name, target_doclist=None): "campaign_name": "campaign", "doctype": "enquiry_from", "name": "lead", + "lead_name": "contact_display", + "company_name": "customer_name", + "email_id": "contact_email", + "mobile_no": "contact_mobile" } }}, target_doclist) diff --git a/selling/doctype/opportunity/opportunity.js b/selling/doctype/opportunity/opportunity.js index 1ec3f3fc4c0..25f28bf3fbf 100644 --- a/selling/doctype/opportunity/opportunity.js +++ b/selling/doctype/opportunity/opportunity.js @@ -53,6 +53,11 @@ erpnext.selling.Opportunity = wn.ui.form.Controller.extend({ this.frm.set_query("contact_by", erpnext.queries.profile); } + this.frm.set_query("customer_address", function() { + if(me.frm.doc.lead) return {filters: { lead: me.frm.doc.lead } }; + else if(me.frm.doc.customer) return {filters: { customer: me.frm.doc.customer } }; + }); + this.frm.set_query("item_code", "enquiry_details", function() { return { query: "controllers.queries.item_query", @@ -63,7 +68,6 @@ erpnext.selling.Opportunity = wn.ui.form.Controller.extend({ $.each([["lead", "lead"], ["customer", "customer"], - ["customer_address", "customer_filter"], ["contact_person", "customer_filter"], ["territory", "not_a_group_filter"]], function(i, opts) { me.frm.set_query(opts[0], erpnext.queries[opts[1]]); @@ -151,8 +155,14 @@ cur_frm.cscript.lead_cust_show = function(doc,cdt,cdn){ } } -cur_frm.cscript.customer_address = cur_frm.cscript.contact_person = function(doc,dt,dn) { - if(doc.customer) return get_server_fields('get_customer_address', JSON.stringify({customer: doc.customer, address: doc.customer_address, contact: doc.contact_person}),'', doc, dt, dn, 1); +cur_frm.cscript.customer_address = cur_frm.cscript.contact_person = function(doc, dt, dn) { + args = { + address: doc.customer_address, + contact: doc.contact_person + } + if(doc.customer) args.update({customer: doc.customer}); + + return get_server_fields('get_customer_address', JSON.stringify(args),'', doc, dt, dn, 1); } cur_frm.cscript.lead = function(doc, cdt, cdn) { @@ -163,7 +173,7 @@ cur_frm.cscript.lead = function(doc, cdt, cdn) { source_name: cur_frm.doc.lead }) - unhide_field(['customer_name', 'address_display','contact_mobile', + unhide_field(['customer_name', 'address_display','contact_mobile', 'customer_address', 'contact_email', 'territory']); } diff --git a/selling/doctype/opportunity/opportunity.txt b/selling/doctype/opportunity/opportunity.txt index a904f566439..aeedd08bb80 100644 --- a/selling/doctype/opportunity/opportunity.txt +++ b/selling/doctype/opportunity/opportunity.txt @@ -2,7 +2,7 @@ { "creation": "2013-03-07 18:50:30", "docstatus": 0, - "modified": "2013-09-10 10:52:49", + "modified": "2013-09-25 19:32:29", "modified_by": "Administrator", "owner": "Administrator" }, @@ -190,34 +190,16 @@ "options": "icon-bullhorn", "read_only": 0 }, - { - "doctype": "DocField", - "fieldname": "contact_person", - "fieldtype": "Link", - "in_filter": 1, - "label": "Contact Person", - "options": "Contact", - "print_hide": 1, - "read_only": 0 - }, { "doctype": "DocField", "fieldname": "customer_address", "fieldtype": "Link", "in_filter": 1, - "label": "Customer Address", + "label": "Customer / Lead Address", "options": "Address", "print_hide": 1, "read_only": 0 }, - { - "doctype": "DocField", - "fieldname": "customer_name", - "fieldtype": "Data", - "label": "Customer Name", - "print_hide": 0, - "read_only": 1 - }, { "doctype": "DocField", "fieldname": "address_display", @@ -228,12 +210,60 @@ "oldfieldtype": "Small Text", "read_only": 1 }, + { + "description": "To manage Territory, click here", + "doctype": "DocField", + "fieldname": "territory", + "fieldtype": "Link", + "in_filter": 1, + "label": "Territory", + "options": "Territory", + "print_hide": 1, + "read_only": 0, + "reqd": 0, + "search_index": 1 + }, + { + "depends_on": "eval:doc.enquiry_from==\"Customer\"", + "description": "To manage Territory, click here", + "doctype": "DocField", + "fieldname": "customer_group", + "fieldtype": "Link", + "hidden": 0, + "in_filter": 1, + "label": "Customer Group", + "oldfieldname": "customer_group", + "oldfieldtype": "Link", + "options": "Customer Group", + "print_hide": 1, + "read_only": 0, + "reqd": 0, + "search_index": 1 + }, { "doctype": "DocField", "fieldname": "column_break3", "fieldtype": "Column Break", "read_only": 0 }, + { + "doctype": "DocField", + "fieldname": "customer_name", + "fieldtype": "Data", + "label": "Customer Name", + "print_hide": 0, + "read_only": 1 + }, + { + "doctype": "DocField", + "fieldname": "contact_person", + "fieldtype": "Link", + "in_filter": 1, + "label": "Contact Person", + "options": "Contact", + "print_hide": 1, + "read_only": 0 + }, { "doctype": "DocField", "fieldname": "contact_display", @@ -255,36 +285,6 @@ "label": "Contact Mobile No", "read_only": 1 }, - { - "depends_on": "eval:doc.enquiry_from==\"Customer\"", - "description": "To manage Territory, click here", - "doctype": "DocField", - "fieldname": "customer_group", - "fieldtype": "Link", - "hidden": 0, - "in_filter": 1, - "label": "Customer Group", - "oldfieldname": "customer_group", - "oldfieldtype": "Link", - "options": "Customer Group", - "print_hide": 1, - "read_only": 0, - "reqd": 0, - "search_index": 1 - }, - { - "description": "To manage Territory, click here", - "doctype": "DocField", - "fieldname": "territory", - "fieldtype": "Link", - "in_filter": 1, - "label": "Territory", - "options": "Territory", - "print_hide": 1, - "read_only": 0, - "reqd": 0, - "search_index": 1 - }, { "description": "Filing in Additional Information about the Opportunity will help you analyze your data better.", "doctype": "DocField", From 38567e02e16efe7dec751157ca8a2a3e41e1d678 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 26 Sep 2013 12:09:17 +0530 Subject: [PATCH 11/41] [fix] [minor] toggle fields based on permission in expense claim --- hr/doctype/expense_claim/expense_claim.js | 34 ++++++++++++++++------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/hr/doctype/expense_claim/expense_claim.js b/hr/doctype/expense_claim/expense_claim.js index 65c557947f8..f7895b10eb0 100644 --- a/hr/doctype/expense_claim/expense_claim.js +++ b/hr/doctype/expense_claim/expense_claim.js @@ -58,11 +58,12 @@ cur_frm.cscript.onload = function(doc,cdt,cdn) { query:"controllers.queries.employee_query" } } - + var exp_approver = doc.exp_approver; return cur_frm.call({ method:"hr.utils.get_expense_approver_list", callback: function(r) { cur_frm.set_df_property("exp_approver", "options", r.message); + if(exp_approver) cur_frm.set_value("exp_approver", exp_approver); } }); } @@ -79,26 +80,39 @@ cur_frm.cscript.clear_sanctioned = function(doc) { } cur_frm.cscript.refresh = function(doc,cdt,cdn){ + cur_frm.cscript.set_help(doc); + + if(!doc.__islocal) { + cur_frm.toggle_enable("exp_approver", (doc.owner==user && doc.approval_status=="Draft")); + cur_frm.toggle_enable("approval_status", (doc.exp_approver==user && doc.docstatus==0)); + + if(!doc.__islocal && user!=doc.exp_approver && cur_frm.frm_head.appframe.buttons.Submit) + cur_frm.frm_head.appframe.buttons.Submit.toggle(false); + + if(doc.docstatus==0 && doc.exp_approver==user && doc.approval_status=="Approved") + cur_frm.savesubmit(); + + if(doc.docstatus==1 && wn.model.can_create("Journal Voucher")) + cur_frm.add_custom_button("Make Bank Voucher", cur_frm.cscript.make_bank_voucher); + } +} + +cur_frm.cscript.set_help = function(doc) { cur_frm.set_intro(""); if(doc.__islocal && !in_list(user_roles, "HR User")) { cur_frm.set_intro("Fill the form and save it") } else { if(doc.docstatus==0 && doc.approval_status=="Draft") { if(user==doc.exp_approver) { - cur_frm.set_intro("You are the Expense Approver for this record. Please Update the 'Status' and Save"); - cur_frm.toggle_enable("approval_status", true); + cur_frm.set_intro("You are the Expense Approver for this record. \ + Please Update the 'Status' and Save"); } else { - cur_frm.set_intro("Expense Claim is pending approval. Only the Expense Approver can update status."); - cur_frm.toggle_enable("approval_status", false); - if(!doc.__islocal && cur_frm.frm_head.appframe.buttons.Submit) - cur_frm.frm_head.appframe.buttons.Submit.toggle(false); + cur_frm.set_intro("Expense Claim is pending approval. \ + Only the Expense Approver can update status."); } } else { if(doc.approval_status=="Approved") { cur_frm.set_intro("Expense Claim has been approved."); - if(doc.docstatus==0) cur_frm.savesubmit(); - if(doc.docstatus==1) cur_frm.add_custom_button("Make Bank Voucher", - cur_frm.cscript.make_bank_voucher); } else if(doc.approval_status=="Rejected") { cur_frm.set_intro("Expense Claim has been rejected."); } From 9f2899616528e97f9fa5b8418a45488f3d26eca2 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 26 Sep 2013 12:18:40 +0530 Subject: [PATCH 12/41] [fix] [minor] retain leave approver after setting options --- hr/doctype/leave_application/leave_application.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hr/doctype/leave_application/leave_application.js b/hr/doctype/leave_application/leave_application.js index 4c7d356c159..5969f4dc4fb 100755 --- a/hr/doctype/leave_application/leave_application.js +++ b/hr/doctype/leave_application/leave_application.js @@ -10,6 +10,8 @@ cur_frm.cscript.onload = function(doc, dt, dn) { cur_frm.set_value("status", "Open"); cur_frm.cscript.calculate_total_days(doc, dt, dn); } + + var leave_approver = doc.leave_approver; return cur_frm.call({ method:"hr.utils.get_leave_approver_list", callback: function(r) { @@ -17,6 +19,7 @@ cur_frm.cscript.onload = function(doc, dt, dn) { function(profile) { return {value: profile, label: wn.user_info(profile).fullname}; })); + if(leave_approver) cur_frm.set_value("leave_approver", leave_approver); cur_frm.cscript.get_leave_balance(cur_frm.doc); } }); From 16ec14f9ab07f374fcb420ced09d1afdef17cf8e Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 26 Sep 2013 14:08:09 +0530 Subject: [PATCH 13/41] [fix] set missing values on creation of stock entry from material request --- stock/doctype/material_request/material_request.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/stock/doctype/material_request/material_request.py b/stock/doctype/material_request/material_request.py index f0022655091..249062f29d1 100644 --- a/stock/doctype/material_request/material_request.py +++ b/stock/doctype/material_request/material_request.py @@ -347,9 +347,16 @@ def make_supplier_quotation(source_name, target_doclist=None): @webnotes.whitelist() def make_stock_entry(source_name, target_doclist=None): from webnotes.model.mapper import get_mapped_doclist - - def set_purpose(source, target): + + def update_item(obj, target, source_parent): + target.conversion_factor = 1 + target.qty = flt(obj.qty) - flt(obj.ordered_qty) + target.transfer_qty = flt(obj.qty) - flt(obj.ordered_qty) + + def set_missing_values(source, target): target[0].purpose = "Material Transfer" + se = webnotes.bean(target) + se.run_method("get_stock_and_rate") doclist = get_mapped_doclist("Material Request", source_name, { "Material Request": { @@ -369,6 +376,6 @@ def make_stock_entry(source_name, target_doclist=None): }, "postprocess": update_item } - }, target_doclist, set_purpose) + }, target_doclist, set_missing_values) return [d.fields for d in doclist] \ No newline at end of file From 6ec4b0c52a27a994eb2f27e5205cb1b4ff0b4dc6 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 26 Sep 2013 15:45:44 +0530 Subject: [PATCH 14/41] [fix] [minor] display product image in shopping cart --- portal/templates/includes/cart.js | 5 ++--- selling/utils/cart.py | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/portal/templates/includes/cart.js b/portal/templates/includes/cart.js index 5ff6e3fb72f..bd3f56533c5 100644 --- a/portal/templates/includes/cart.js +++ b/portal/templates/includes/cart.js @@ -9,7 +9,6 @@ $(document).ready(function() { type: "POST", method: "selling.utils.cart.get_cart_quotation", callback: function(r) { - console.log(r); $("#cart-container").removeClass("hide"); $(".progress").remove(); if(r.exc) { @@ -126,8 +125,8 @@ $.extend(erpnext.cart, { }, render_item_row: function($cart_items, doc) { - doc.image_html = doc.image ? - '
' : + doc.image_html = doc.website_image ? + '
' : '{% include "app/stock/doctype/item/templates/includes/product_missing_image.html" %}'; if(doc.description === doc.item_name) doc.description = ""; diff --git a/selling/utils/cart.py b/selling/utils/cart.py index fc7d062d0d8..7e7fb2e1035 100644 --- a/selling/utils/cart.py +++ b/selling/utils/cart.py @@ -286,7 +286,7 @@ def apply_cart_settings(party=None, quotation=None): cart_settings = webnotes.get_obj("Shopping Cart Settings") billing_territory = get_address_territory(quotation.doc.customer_address) or \ - party.territory + party.territory or "All Territories" set_price_list_and_rate(quotation, cart_settings, billing_territory) From ca77574a6666b3edaff025cb8f21e3e83c882f1f Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 26 Sep 2013 16:16:44 +0530 Subject: [PATCH 15/41] [fix] [minor] only post sl entries if stock item exists --- stock/stock_ledger.py | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/stock/stock_ledger.py b/stock/stock_ledger.py index a3af5ade818..197aa0d5ab1 100644 --- a/stock/stock_ledger.py +++ b/stock/stock_ledger.py @@ -11,29 +11,31 @@ import json class NegativeStockError(webnotes.ValidationError): pass def make_sl_entries(sl_entries, is_amended=None): - from stock.utils import update_bin + if sl_entries: + from stock.utils import update_bin - cancel = True if sl_entries[0].get("is_cancelled") == "Yes" else False - if cancel: - set_as_cancel(sl_entries[0].get('voucher_no'), sl_entries[0].get('voucher_type')) + cancel = True if sl_entries[0].get("is_cancelled") == "Yes" else False + if cancel: + set_as_cancel(sl_entries[0].get('voucher_no'), sl_entries[0].get('voucher_type')) - for sle in sl_entries: - sle_id = None - if sle.get('is_cancelled') == 'Yes': - sle['actual_qty'] = -flt(sle['actual_qty']) + for sle in sl_entries: + sle_id = None + if sle.get('is_cancelled') == 'Yes': + sle['actual_qty'] = -flt(sle['actual_qty']) - if sle.get("actual_qty"): - sle_id = make_entry(sle) + if sle.get("actual_qty"): + sle_id = make_entry(sle) - args = sle.copy() - args.update({ - "sle_id": sle_id, - "is_amended": is_amended - }) - update_bin(args) + args = sle.copy() + args.update({ + "sle_id": sle_id, + "is_amended": is_amended + }) + update_bin(args) - if cancel: - delete_cancelled_entry(sl_entries[0].get('voucher_type'), sl_entries[0].get('voucher_no')) + if cancel: + delete_cancelled_entry(sl_entries[0].get('voucher_type'), + sl_entries[0].get('voucher_no')) def set_as_cancel(voucher_type, voucher_no): webnotes.conn.sql("""update `tabStock Ledger Entry` set is_cancelled='Yes', From a1f7f2abfd4e45b70a249fb171b3eaf7ceda37d0 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 26 Sep 2013 16:59:32 +0530 Subject: [PATCH 16/41] [minor] update lead status as Opportunity Made when opportunity submitted --- selling/doctype/lead/lead.txt | 4 ++-- selling/doctype/opportunity/opportunity.py | 14 +++++++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/selling/doctype/lead/lead.txt b/selling/doctype/lead/lead.txt index d96880bc755..408ad451250 100644 --- a/selling/doctype/lead/lead.txt +++ b/selling/doctype/lead/lead.txt @@ -2,7 +2,7 @@ { "creation": "2013-04-10 11:45:37", "docstatus": 0, - "modified": "2013-09-19 10:38:58", + "modified": "2013-09-26 16:30:36", "modified_by": "Administrator", "owner": "Administrator" }, @@ -111,7 +111,7 @@ "no_copy": 1, "oldfieldname": "status", "oldfieldtype": "Select", - "options": "\nOpen\nReplied\nAttempted to Contact\nContact in Future\nContacted\nInterested\nNot interested\nLead Lost\nConverted\nPassive", + "options": "\nOpen\nReplied\nAttempted to Contact\nContact in Future\nContacted\nOpportunity Made\nInterested\nNot interested\nLead Lost\nConverted\nPassive", "reqd": 1, "search_index": 1 }, diff --git a/selling/doctype/opportunity/opportunity.py b/selling/doctype/opportunity/opportunity.py index b265356a4d5..c8c41e3f39d 100644 --- a/selling/doctype/opportunity/opportunity.py +++ b/selling/doctype/opportunity/opportunity.py @@ -128,12 +128,12 @@ class DocType(TransactionBase): from accounts.utils import validate_fiscal_year validate_fiscal_year(self.doc.transaction_date, self.doc.fiscal_year, "Opportunity Date") - - if not self.doc.status: - self.doc.status = "Draft" + self.doc.status = "Draft" def on_submit(self): webnotes.conn.set(self.doc, 'status', 'Submitted') + if self.doc.lead and webnotes.conn.get_value("Lead", self.doc.lead, "status")!="Converted": + webnotes.conn.set_value("Lead", self.doc.lead, "status", "Opportunity Made") def on_cancel(self): chk = sql("select t1.name from `tabQuotation` t1, `tabQuotation Item` t2 where t2.parent = t1.name and t1.docstatus=1 and (t1.status!='Order Lost' and t1.status!='Cancelled') and t2.prevdoc_docname = %s",self.doc.name) @@ -142,6 +142,14 @@ class DocType(TransactionBase): raise Exception else: webnotes.conn.set(self.doc, 'status', 'Cancelled') + if self.doc.lead and webnotes.conn.get_value("Lead", self.doc.lead, + "status")!="Converted": + if webnotes.conn.get_value("Communication", {"parent": self.doc.lead}): + status = "Contacted" + else: + status = "Open" + + webnotes.conn.set_value("Lead", self.doc.lead, "status", status) def declare_enquiry_lost(self,arg): chk = sql("select t1.name from `tabQuotation` t1, `tabQuotation Item` t2 where t2.parent = t1.name and t1.docstatus=1 and (t1.status!='Order Lost' and t1.status!='Cancelled') and t2.prevdoc_docname = %s",self.doc.name) From 6060cc4896d434a037b42be8e61643ab75d2550f Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 26 Sep 2013 17:59:05 +0530 Subject: [PATCH 17/41] [fix] [minor] fetch project on selection of task in time log --- projects/doctype/time_log/time_log.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/projects/doctype/time_log/time_log.js b/projects/doctype/time_log/time_log.js index 7a03955e2a9..ab21a3151d9 100644 --- a/projects/doctype/time_log/time_log.js +++ b/projects/doctype/time_log/time_log.js @@ -9,4 +9,6 @@ erpnext.projects.TimeLog = wn.ui.form.Controller.extend({ } }); -cur_frm.cscript = new erpnext.projects.TimeLog({frm: cur_frm}); \ No newline at end of file +cur_frm.cscript = new erpnext.projects.TimeLog({frm: cur_frm}); + +cur_frm.add_fetch('task','project','project'); \ No newline at end of file From 250059097c8471a2ad47d11f7d87194a367b6fad Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 26 Sep 2013 18:36:35 +0530 Subject: [PATCH 18/41] [fix] [minor] set employee name blank while creating new employee --- hr/doctype/employee/employee.js | 1 + 1 file changed, 1 insertion(+) diff --git a/hr/doctype/employee/employee.js b/hr/doctype/employee/employee.js index 05aec3efa34..01200e7d22c 100644 --- a/hr/doctype/employee/employee.js +++ b/hr/doctype/employee/employee.js @@ -14,6 +14,7 @@ erpnext.hr.EmployeeController = wn.ui.form.Controller.extend({ onload: function() { this.frm.toggle_display(["esic_card_no", "gratuity_lic_id", "pan_number", "pf_number"], wn.control_panel.country==="India"); + if(this.frm.doc.__islocal) this.frm.set_value("employee_name", ""); }, refresh: function() { From 6111b1edb610f89dc24f8d48ec305d141a7c30b7 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Thu, 26 Sep 2013 17:49:53 -0300 Subject: [PATCH 19/41] Fix Translation in Sales Order.js I'll be fixing some points that I miss translation. --- selling/doctype/sales_order/sales_order.js | 24 +++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/selling/doctype/sales_order/sales_order.js b/selling/doctype/sales_order/sales_order.js index 33699f05d84..402099259fc 100644 --- a/selling/doctype/sales_order/sales_order.js +++ b/selling/doctype/sales_order/sales_order.js @@ -26,34 +26,34 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( cur_frm.dashboard.add_progress(cint(doc.per_billed) + wn._("% Billed"), doc.per_billed); - cur_frm.add_custom_button('Send SMS', cur_frm.cscript.send_sms); + cur_frm.add_custom_button(wn._('Send SMS'), cur_frm.cscript.send_sms); // delivery note if(flt(doc.per_delivered, 2) < 100 && doc.order_type=='Sales') - cur_frm.add_custom_button('Make Delivery', this.make_delivery_note); + cur_frm.add_custom_button(wn._('Make Delivery'), this.make_delivery_note); // maintenance if(flt(doc.per_delivered, 2) < 100 && (doc.order_type !='Sales')) { - cur_frm.add_custom_button('Make Maint. Visit', this.make_maintenance_visit); - cur_frm.add_custom_button('Make Maint. Schedule', + cur_frm.add_custom_button(wn._('Make Maint. Visit'), this.make_maintenance_visit); + cur_frm.add_custom_button(wn._('Make Maint. Schedule'), this.make_maintenance_schedule); } // indent if(!doc.order_type || (doc.order_type == 'Sales')) - cur_frm.add_custom_button('Make ' + wn._('Material Request'), + cur_frm.add_custom_button(wn._('Make ') + wn._('Material Request'), this.make_material_request); // sales invoice if(flt(doc.per_billed, 2) < 100) - cur_frm.add_custom_button('Make Invoice', this.make_sales_invoice); + cur_frm.add_custom_button(wn._('Make Invoice'), this.make_sales_invoice); // stop if(flt(doc.per_delivered, 2) < 100 || doc.per_billed < 100) - cur_frm.add_custom_button('Stop!', cur_frm.cscript['Stop Sales Order']); + cur_frm.add_custom_button(wn._('Stop!'), cur_frm.cscript['Stop Sales Order']); } else { // un-stop - cur_frm.dashboard.set_headline_alert("Stopped", "alert-danger", "icon-stop"); - cur_frm.add_custom_button('Unstop', cur_frm.cscript['Unstop Sales Order']); + cur_frm.dashboard.set_headline_alert(wn._("Stopped"), "alert-danger", "icon-stop"); + cur_frm.add_custom_button(wn._('Unstop'), cur_frm.cscript['Unstop Sales Order']); } } @@ -157,7 +157,7 @@ cur_frm.fields_dict['project_name'].get_query = function(doc, cdt, cdn) { cur_frm.cscript['Stop Sales Order'] = function() { var doc = cur_frm.doc; - var check = confirm("Are you sure you want to STOP " + doc.name); + var check = confirm(wn._("Are you sure you want to STOP ") + doc.name); if (check) { return $c('runserverobj', { @@ -172,7 +172,7 @@ cur_frm.cscript['Stop Sales Order'] = function() { cur_frm.cscript['Unstop Sales Order'] = function() { var doc = cur_frm.doc; - var check = confirm("Are you sure you want to UNSTOP " + doc.name); + var check = confirm(wn._("Are you sure you want to UNSTOP ") + doc.name); if (check) { return $c('runserverobj', { @@ -188,4 +188,4 @@ cur_frm.cscript.on_submit = function(doc, cdt, cdn) { if(cint(wn.boot.notification_settings.sales_order)) { cur_frm.email_doc(wn.boot.notification_settings.sales_order_message); } -}; \ No newline at end of file +}; From 18762925bcbd9591c275610cc4ec34dc184a51f3 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Thu, 26 Sep 2013 17:54:46 -0300 Subject: [PATCH 20/41] Fix translation in Customer.js I'll be fixing some points that I miss translation. --- selling/doctype/customer/customer.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/selling/doctype/customer/customer.js b/selling/doctype/customer/customer.js index 4e2f42c7340..d2c632530b3 100644 --- a/selling/doctype/customer/customer.js +++ b/selling/doctype/customer/customer.js @@ -45,7 +45,7 @@ cur_frm.cscript.setup_dashboard = function(doc) { cur_frm.dashboard.reset(doc); if(doc.__islocal) return; - cur_frm.dashboard.set_headline('Loading...') + cur_frm.dashboard.set_headline(''+ wn._('Loading...')+ '') cur_frm.dashboard.add_doctype_badge("Opportunity", "customer"); cur_frm.dashboard.add_doctype_badge("Quotation", "customer"); @@ -99,7 +99,7 @@ cur_frm.cscript.make_contact = function() { return "select name, first_name, last_name, email_id, phone, mobile_no, department, designation, is_primary_contact from tabContact where customer='"+cur_frm.docname+"' and docstatus != 2 order by is_primary_contact desc" }, as_dict: 1, - no_results_message: 'No contacts created', + no_results_message: wn._('No contacts created'), render_row: cur_frm.cscript.render_contact_row, }); // note: render_contact_row is defined in contact_control.js @@ -119,4 +119,4 @@ cur_frm.fields_dict.lead_name.get_query = function(doc,cdt,cdn) { return{ query:"controllers.queries.lead_query" } -} \ No newline at end of file +} From 2428e8d1b7ce13c5b60bb38bd590e6466d678c31 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Fri, 27 Sep 2013 12:32:26 +0530 Subject: [PATCH 21/41] [pos] [minor] fix for cur_frm --- accounts/doctype/sales_invoice/pos.js | 40 +++++++++++++------------- selling/doctype/quotation/quotation.js | 6 ++-- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/accounts/doctype/sales_invoice/pos.js b/accounts/doctype/sales_invoice/pos.js index ca5618b3454..e19652d25f5 100644 --- a/accounts/doctype/sales_invoice/pos.js +++ b/accounts/doctype/sales_invoice/pos.js @@ -213,10 +213,10 @@ erpnext.POS = Class.extend({ }); // if form is local then allow this function - if (cur_frm.doc.docstatus===0) { + if (me.frm.doc.docstatus===0) { $("div.pos-item").on("click", function() { - if(!cur_frm.doc[me.party.toLowerCase()] && ((me.frm.doctype == "Quotation" && - cur_frm.doc.quotation_to == "Customer") + if(!me.frm.doc[me.party.toLowerCase()] && ((me.frm.doctype == "Quotation" && + me.frm.doc.quotation_to == "Customer") || me.frm.doctype != "Quotation")) { msgprint("Please select " + me.party + " first."); return; @@ -304,8 +304,8 @@ erpnext.POS = Class.extend({ item_code: d.item_code, item_name: d.item_name===d.item_code ? "" : ("
" + d.item_name), qty: d.qty, - rate: format_currency(rate, cur_frm.doc.currency), - amount: format_currency(item_amount, cur_frm.doc.currency) + rate: format_currency(rate, me.frm.doc.currency), + amount: format_currency(item_amount, me.frm.doc.currency) } )).appendTo($items); }); @@ -332,19 +332,19 @@ erpnext.POS = Class.extend({ // set totals if (this.sales_or_purchase == "Sales") { this.wrapper.find(".net-total").text(format_currency(this.frm.doc.net_total_export, - cur_frm.doc.currency)); + me.frm.doc.currency)); this.wrapper.find(".grand-total").text(format_currency(this.frm.doc.grand_total_export, - cur_frm.doc.currency)); + me.frm.doc.currency)); } else { this.wrapper.find(".net-total").text(format_currency(this.frm.doc.net_total_import, - cur_frm.doc.currency)); + me.frm.doc.currency)); this.wrapper.find(".grand-total").text(format_currency(this.frm.doc.grand_total_import, - cur_frm.doc.currency)); + me.frm.doc.currency)); } // if form is local then only run all these functions - if (cur_frm.doc.docstatus===0) { + if (this.frm.doc.docstatus===0) { $("input.qty").on("focus", function() { $(this).select(); }); @@ -371,11 +371,11 @@ erpnext.POS = Class.extend({ }); me.refresh_delete_btn(); - cur_frm.pos.barcode.$input.focus(); + this.frm.pos.barcode.$input.focus(); } // if form is submitted & cancelled then disable all input box & buttons - if (cur_frm.doc.docstatus>=1) { + if (this.frm.doc.docstatus>=1) { me.wrapper.find('input, button').each(function () { $(this).prop('disabled', true); }); @@ -390,7 +390,7 @@ erpnext.POS = Class.extend({ // If quotation to is not Customer then remove party if (this.frm.doctype == "Quotation") { this.party_field.$wrapper.remove(); - if (cur_frm.doc.quotation_to == "Customer") + if (this.frm.doc.quotation_to == "Customer") this.make_party(); } }, @@ -435,8 +435,8 @@ erpnext.POS = Class.extend({ } } }); - cur_frm.fields_dict[this.frm.cscript.fname].grid.refresh(); - cur_frm.script_manager.trigger("calculate_taxes_and_totals"); + this.frm.fields_dict[this.frm.cscript.fname].grid.refresh(); + this.frm.script_manager.trigger("calculate_taxes_and_totals"); me.frm.dirty(); me.refresh(); }, @@ -470,15 +470,15 @@ erpnext.POS = Class.extend({ "total_amount": $(".grand-total").text() }); dialog.show(); - cur_frm.pos.barcode.$input.focus(); + me.frm.pos.barcode.$input.focus(); dialog.get_input("total_amount").prop("disabled", true); 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.cscript.mode_of_payment(cur_frm.doc); - cur_frm.save(); + me.frm.set_value("mode_of_payment", dialog.get_values().mode_of_payment); + me.frm.set_value("paid_amount", dialog.get_values().total_amount); + me.frm.cscript.mode_of_payment(me.frm.doc); + me.frm.save(); dialog.hide(); me.refresh(); }; diff --git a/selling/doctype/quotation/quotation.js b/selling/doctype/quotation/quotation.js index 33ba0933bb2..e20308f18ee 100644 --- a/selling/doctype/quotation/quotation.js +++ b/selling/doctype/quotation/quotation.js @@ -83,12 +83,12 @@ erpnext.selling.QuotationController = erpnext.selling.SellingController.extend({ }, validate_company_and_party: function(party_field) { - if(this.frm.doc.quotation_to == "Lead") { - return true; - } else if(!this.frm.doc.quotation_to) { + if(!this.frm.doc.quotation_to) { msgprint(wn._("Please select a value for" + " " + wn.meta.get_label(this.frm.doc.doctype, "quotation_to", this.frm.doc.name))); return false; + } else if (this.frm.doc.quotation_to == "Lead") { + return true; } else { return this._super(party_field); } From a3d12bde9d1977c60b5671c006f40102c1887824 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 27 Sep 2013 16:33:22 +0530 Subject: [PATCH 22/41] [fix] [minor] gross profit report --- accounts/report/gross_profit/gross_profit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accounts/report/gross_profit/gross_profit.py b/accounts/report/gross_profit/gross_profit.py index d9c20d5ccc7..9917b69697f 100644 --- a/accounts/report/gross_profit/gross_profit.py +++ b/accounts/report/gross_profit/gross_profit.py @@ -55,7 +55,7 @@ def get_stock_ledger_entries(filters): from `tabStock Ledger Entry`""" if filters.get("company"): - query += """ and company=%(company)s""" + query += """ where company=%(company)s""" query += " order by item_code desc, warehouse desc, posting_date desc, posting_time desc, name desc" From 2ba61236c1caae841faa477b71431cec485c4d1e Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Fri, 27 Sep 2013 21:08:37 +0530 Subject: [PATCH 23/41] [price list] make new grid --- setup/doctype/price_list/price_list.js | 301 +++++++++++++++++++++++++ 1 file changed, 301 insertions(+) diff --git a/setup/doctype/price_list/price_list.js b/setup/doctype/price_list/price_list.js index f3adc727579..6dfbd0f1eef 100644 --- a/setup/doctype/price_list/price_list.js +++ b/setup/doctype/price_list/price_list.js @@ -5,4 +5,305 @@ $.extend(cur_frm.cscript, { onload: function() { erpnext.add_for_territory(); }, +}); + +cur_frm.cscript.refresh = function(doc, cdt, cdn) { + cur_frm.cscript.show_item_prices(); +} + +cur_frm.cscript.show_item_prices = function() { + var counter = 0; + var item_price = wn.model.get("Item Price", {parent: cur_frm.doc.name}); + + new wn.ui.form.TableGrid({ + parent: cur_frm.fields_dict.item_prices.wrapper, + frm: cur_frm, + table_field: wn.model.get("DocField", {parent:"Price List", fieldname:"item_prices"})[0] + }); +} + +wn.ui.form.TableGrid = Class.extend({ + init: function(opts) { + $.extend(this, opts); + this.fields = wn.model.get("DocField", {parent: this.table_field.options}); + this.make_table(); + }, + make_table: function() { + var me = this; + // Creating table & assigning attributes + var grid_table = document.createElement("table"); + $(grid_table).attr("class", "table table-hover table-bordered grid"); + + // Appending header & rows to table + + $(this.make_table_headers()).appendTo(grid_table); + $(this.make_table_rows()).appendTo(grid_table); + + // Creating button to add new row + var btn_div = document.createElement("div"); + var new_row_btn = document.createElement("button"); + $new_row_btn = $(new_row_btn); + $new_row_btn.attr({ + "class": "btn btn-success table-new-row", + "title": "Add new row" + }); + var btn_icon = document.createElement("i"); + $(btn_icon).attr("class", "icon-plus"); + $(btn_icon).appendTo(new_row_btn); + $new_row_btn.append(" Add new row"); + $new_row_btn.appendTo(btn_div); + + // Appending table & button to parent + var $grid_table = $(grid_table).appendTo($(this.parent)); + var $btn_div = $(btn_div).appendTo($(this.parent)); + + $btn_div.on("click", ".table-new-row", function() { + me.make_dialog(); + return false; + }); + + $grid_table.on("click", ".table-row", function() { + me.make_dialog(this); + return false; + }); + }, + make_table_headers: function() { + var me = this; + var header = document.createElement("thead"); + + // Creating header row + var row = document.createElement("tr"); + $(row).attr({ + "class": "active", + "style": "height:50px" + }); + $(row).appendTo(header); + + // Creating head first cell + var th = document.createElement("th"); + $(th).attr({ + "width": "8%", + "style": "vertical-align:middle", + "class": "text-center" + }); + $(th).html("#"); + $(th).appendTo(row); + + // Make other headers with label as heading + $.each(this.fields, function(i, obj) { + if (obj.in_list_view===1) + var th = document.createElement("th"); + $(th).attr("style", "vertical-align:middle"); + $(th).html(obj.label); + $(th).appendTo(row); + }); + + return header; + }, + make_table_rows: function() { + var me = this; + + // Creating table body + var table_body = document.createElement("tbody"); + $(table_body).attr("style", "cursor:pointer"); + + $.each(wn.model.get_children(this.table_field.options, this.frm.doc.name, + this.table_field.fieldname, this.frm.doctype), function(index, d) { + + // Creating table row + var tr = document.createElement("tr"); + $(tr).attr({ + "class": "table-row", + "data-idx": d.idx + }); + + // Creating table data & appending to row + var td = document.createElement("td"); + $(td).attr("class", "text-center"); + $(td).html(d.idx); + $(td).appendTo(tr); + + $.each(me.fields, function(i, obj) { + if (obj.in_list_view===1) { + var td = document.createElement("td"); + $(td).attr({ + "data-fieldtype": obj.fieldtype, + "data-fieldname": obj.fieldname, + "data-fieldvalue": d[obj.fieldname], + "data-doc_name": d["name"] + }); + $(td).html(d[obj.fieldname]); + + // if field is currency then add style & change text + if (obj.fieldtype=="Currency") { + $(td).attr("style", "text-align:right"); + $(td).html(format_currency(d[obj.fieldname], me.frm.doc.currency)); + } + + // Append td to row + $(td).appendTo(tr); + } + }); + + // Append row to table body + $(tr).appendTo(table_body); + }); + + return table_body; + }, + make_dialog: function(row) { + var me = this; + + this.dialog = new wn.ui.Dialog({ + title: this.table_field.options, + fields: this.fields + }); + + this.dialog.set_values(this.make_dialog_values(row)); + + $a(this.dialog.body, 'div', '', '', this.make_dialog_buttons()); + this.dialog.show(); + + this.dialog.$wrapper.find('button.update').on('click', function() { + me.update_row(row); + }); + + this.dialog.$wrapper.find('button.delete').on('click', function() { + me.delete_row(row); + }); + return row; + }, + // make_dialog_fields: function() { + // var me = this; + // var fields = []; + + // $.each(this.fields, function(i, obj) { + // var dialog_field = { + // fieldtype: obj.fieldtype, + // fieldname: obj.fieldname, + // label: obj.label + // } + + // // check if fields has options + // if (obj.options) { + // var options = {options: obj.options} + // $.extend(dialog_field, options); + // } + + // // check if field is mandatory + // if (obj.reqd == 1) { + // var reqd = {reqd: obj.reqd} + // $.extend(dialog_field, reqd); + // } + + // fields.push(obj); + // }); + + // return fields; + // }, + make_dialog_values: function(row) { + var me = this; + var dialog_values = {}; + + $.each(this.fields, function(i, item) { + dialog_values[item.fieldname] = $(row).find('td[data-fieldname="'+ item.fieldname +'"]').data('fieldvalue'); + }); + + return dialog_values; + }, + make_dialog_buttons: function() { + var me = this; + var buttons = ''; + + // if user can delete then only add the delete button in dialog + if (wn.model.can_delete(me.frm.doc.doctype)) + buttons += ' '; + + return buttons; + }, + update_row: function(row) { + var me = this; + + if (!row) { + me.add_new_row(); + } + else { + $.each(me.fields, function(i, item) { + var $td = $(row).find('td[data-fieldname="'+ item.fieldname +'"]'); + var val = me.dialog.get_values()[item.fieldname]; + + wn.model.set_value(me.table_field.options, $td.attr('data-doc_name'), + item.fieldname, me.dialog.get_values()[item.fieldname]); + $td.attr('data-fieldvalue', val); + + // If field type is currency the update with format currency + if ($td.attr('data-fieldtype') == "Currency") + $td.html(format_currency(val, me.frm.doc.currency)); + else + $td.html(val); + }); + } + + this.dialog.hide(); + }, + delete_row: function(row) { + var me = this; + var doc_name = $(row).find('td:last').attr('data-doc_name'); + wn.model.clear_doc(me.table_field.options, doc_name); + $(row).remove(); + + // Re-assign idx + $.each($(this.parent).find(".grid tbody tr"), function(idx, data) { + $(data).attr("data-idx", idx + 1); + var $td = $(data).find('td:first'); + $td.html(idx + 1); + }); + this.dialog.hide(); + }, + add_new_row: function() { + var me = this; + var row = $(this.parent).find(".grid tbody tr"); + + // Creating new row + var new_row = document.createElement("tr"); + $(new_row).attr({ + "class": "table-row", + "data-idx": row.length + 1 + }); + + // Creating first table data + var td = document.createElement("td"); + $(td).attr("class", "text-center"); + $(td).html(row.length + 1); + $(td).appendTo(new_row); + + var child = wn.model.add_child(this.frm.doc, this.table_field.options, + this.table_field.fieldname); + + $.each(this.fields, function(i, obj) { + if (obj.in_list_view===1) { + child[obj.fieldname] = me.dialog.get_values()[obj.fieldname]; + + var td = document.createElement("td"); + $(td).attr({ + "data-fieldtype": obj.fieldtype, + "data-fieldname": obj.fieldname, + "data-fieldvalue": child[obj.fieldname], + "data-doc_name": child["name"] + }); + $(td).html(child[obj.fieldname]); + + // if field is currency then add style & change text + if (obj.fieldtype=="Currency") { + $(td).attr("style", "text-align:right"); + $(td).html(format_currency(child[obj.fieldname], me.frm.doc.currency)); + } + + // Append td to row + $(td).appendTo(new_row); + } + }); + + $(new_row).appendTo($(this.parent).find(".grid tbody")); + } }); \ No newline at end of file From d1972dd4caa8f56400442436decf5ca44deb544e Mon Sep 17 00:00:00 2001 From: Priya Date: Mon, 30 Sep 2013 10:44:13 +0530 Subject: [PATCH 24/41] [docs] new pages on doctype and markup --- docs/user/buying/docs.user.buying.supplier.md | 8 + .../buying/docs.user.buying.supplier_type.md | 6 +- docs/user/docs.user.md | 4 + .../docs.user.knowledge.accounting.md | 72 ++--- .../docs.user.knowledge.attachment_csv.md | 16 ++ .../knowledge/docs.user.knowledge.doctype.md | 267 ++++++++++++++++++ .../knowledge/docs.user.knowledge.markdown.md | 84 ++++++ docs/user/knowledge/docs.user.knowledge.md | 8 +- .../selling/docs.user.selling.customer.md | 4 +- .../user/setup/docs.user.setup.data_import.md | 6 +- docs/user/stock/docs.user.stock.item.md | 6 +- 11 files changed, 432 insertions(+), 49 deletions(-) create mode 100644 docs/user/knowledge/docs.user.knowledge.attachment_csv.md create mode 100644 docs/user/knowledge/docs.user.knowledge.doctype.md create mode 100644 docs/user/knowledge/docs.user.knowledge.markdown.md diff --git a/docs/user/buying/docs.user.buying.supplier.md b/docs/user/buying/docs.user.buying.supplier.md index e477fa2beda..3707fbe8523 100644 --- a/docs/user/buying/docs.user.buying.supplier.md +++ b/docs/user/buying/docs.user.buying.supplier.md @@ -20,7 +20,15 @@ You can create a new Supplier via: > Tip: When you select a Supplier in any transaction, one Contact and Address gets pre-selected. This is the “Default Contact or Address”. So make sure you set your defaults correctly! +### Integration with Accounts +In ERPNext, there is a separate Account record for each Supplier, of Each company. + +When you create a new Supplier, ERPNext will automatically create an Account Ledger for the Supplier under “Accounts Receivable” in the Company set in the Supplier record. + +> Advanced Tip: If you want to change the Account Group under which the Supplier Account is created, you can set it in the Company master. + +If you want to create an Account in another Company, just change the Company value and “Save” the Supplier again. > Buying > Contact > New Contact diff --git a/docs/user/buying/docs.user.buying.supplier_type.md b/docs/user/buying/docs.user.buying.supplier_type.md index deaf01fcfcd..3871991d638 100644 --- a/docs/user/buying/docs.user.buying.supplier_type.md +++ b/docs/user/buying/docs.user.buying.supplier_type.md @@ -3,9 +3,11 @@ "_label": "Supplier Type" } --- +A supplier may be distinguished from a contractor or subcontractor, who commonly adds specialized input to deliverables. A supplier is also known as a vendor. There are different types of suppliers based on their goods and products. -Based on what the suppliers supply, they are classified into different categories called Supplier Type. -There can be different types of suppliers. You can create your own category of Supplier Type. +ERPNext allows you to create your own categories of suppliers. These categories are known as Supplier Type. For Example, if your suppliers are mainly pharmaceutical companies and FMCG distributors, You can create a new Type for them and name them accordingly. + +Based on what the suppliers supply, they are classified into different categories called Supplier Type. There can be different types of suppliers. You can create your own category of Supplier Type. > Buying > Supplier Type > New Supplier Type diff --git a/docs/user/docs.user.md b/docs/user/docs.user.md index d9e7f2aac00..c45ca30a221 100644 --- a/docs/user/docs.user.md +++ b/docs/user/docs.user.md @@ -151,3 +151,7 @@ Contents 1. [Fiscal Year](docs.user.knowledge.fiscal_year.html) 1. [Accounting Knowledge](docs.user.knowledge.accounting.html) 1. [Accounting Entries](docs.user.knowledge.accounting_entries.html) + 1. [DocType Definitions](docs.user.knowledge.doctype.html) + 1. [Attachment and CSV Files](docs.user.knowledge.attachment_csv.html) + 1. [Format using Markdown](docs.user.knowledge.markdown.html) + diff --git a/docs/user/knowledge/docs.user.knowledge.accounting.md b/docs/user/knowledge/docs.user.knowledge.accounting.md index 17304984cb0..995d38cfe97 100644 --- a/docs/user/knowledge/docs.user.knowledge.accounting.md +++ b/docs/user/knowledge/docs.user.knowledge.accounting.md @@ -22,34 +22,34 @@ Accounting Entries The balance of account can be increased / decreased, depending on account type and transaction type. - +
- - - + + + - - - + + + - - - + + + - - - + + + - - - + + +
Account TypeTransaction TypeEffect on account balanceAccount TypeTransaction TypeEffect on account balance
DebitDebitIncreasesDebitDebitIncreases
DebitCreditDecreasesDebitCreditDecreases
CreditCreditIncreasesCreditCreditIncreases
CreditDebitDecreasesCreditDebitDecreases
@@ -62,48 +62,48 @@ This means that every accounting entry has two parts, one debit and one credit a As the company will receive a payment from customer, the customer is considered as an asset account. For booking income, company maintains an account called "Sales of Laptop". So, entries will be done in the following manner: - +
- - - + + + - - - + + + - - - + + +
AccountDebitCreditAccountDebitCredit
Customer A50000Customer A50000
Sales of Laptop50000Sales of Laptop50000
Customer A has made the payment, so customer balance should decreased based on the paid amount, which will increase "Cash" balance. - +
- - - + + + - - - + + + - - - + + +
AccountDebitCreditAccountDebitCredit
Customer A50000Customer A50000
Cash50000Cash50000
diff --git a/docs/user/knowledge/docs.user.knowledge.attachment_csv.md b/docs/user/knowledge/docs.user.knowledge.attachment_csv.md new file mode 100644 index 00000000000..311934d7f47 --- /dev/null +++ b/docs/user/knowledge/docs.user.knowledge.attachment_csv.md @@ -0,0 +1,16 @@ +--- +{ + "_label": "Attachement and CSV files" +} +--- + +#### How to Attach files? + +When you open a form, on the right sidebar, you will see a section to attach files. Click on “Add” and select the file you want to attach. Click on “Upload” and you are set. + +#### What is a CSV file? + +A CSV (Comma Separated Value) file is a data file that you can upload into ERPNext to update various data. Any spreadsheet file from popular spreadsheet applications like MS Excel or Open Office Spreadsheet can be saved as a CSV file. + +If you are using Microsoft Excel and using non-English characters, make sure to save your file encoded as UTF-8. For older versions of Excel, there is no clear way of saving as UTF-8. So save your file as a CSV, then open it in Notepad, and save as “UTF-8”. (Sorry blame Microsoft for this!) + diff --git a/docs/user/knowledge/docs.user.knowledge.doctype.md b/docs/user/knowledge/docs.user.knowledge.doctype.md new file mode 100644 index 00000000000..a2550d4f95f --- /dev/null +++ b/docs/user/knowledge/docs.user.knowledge.doctype.md @@ -0,0 +1,267 @@ +--- +{ + "_label": "DocType" +} +--- + + + +ERPNext is a based on a “metadata” (data about data) framework that helps define all the different types of documents in the system. The basic building block of ERPNext is a DocType. + +A DocType represents both a table in the database and a form from which a user can enter data. + +Many DocTypes are single tables, but some work in groups. For example, Quotation has a “Quotation” DocType and a “Quotation Item” doctype for the Items table, among others. DocTypes contain a collection of fields called DocFields that form the basis of the columns in the database and the layout of the form. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ColumnDescription
NameName of the record
OwnerCreator and Owner of the record
Created onDate and Time of Creation
Modified On Date and Time of Modification
DocstatusStatus of the record
+ 0 = Saved/Draft
+ 1 = Submitted
+ 2 = Cancelled/Deleted +
ParentName of the Parent
Parent TypeType of Parent
Parent FieldSpecifying the relationship with the parent (there can be multiple child relationships with the same DocType).
Index(idx)Index (sequence) of the record in the child table.
+ +#### Single DocType + +There are a certain type of DocTypes that are “Single”, i.e. they have no table associated and have only one record of its fields. DocTypes such as Global Defaults, Production Planning Tool are “Single” DocTypes. + +#### Field Columns + +In the fields table, there are many columns, here is an explanation of the columns of the field table. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ColumnDescription
LabelField Label (that appears in the form).
TypeField Type
NameColumn name in the database, must be code friendly with no white spaces, special characters and capital letters.
optionsField settings:
+ For Select: List of options (each on a new line).
+ For Link: DocType that is “linked”.
+ For HTML: HTML Content +
Perm LevelPermission level (number) of the field. You can group fields by numbers, called levels, and apply rules on the levels.
WidthWidth of the field (in pixels) - useful for “Table” types.
ReqdChecked if field is mandatory (required).
In FilterChecked if field appears as a standard filter in old style reports.
HiddenChecked if field is hidden.
Print HideChecked if field is hidden in Print Formats.
Report HideChecked if field is hidden in old style reports.
Allow on SubmitChecked if this field can be edited after the document is “Submitted”.
Depends OnThe fieldname of the field that will decide whether this field will be shown or hidden. It is useful to hide un-necessary fields.
DescriptionDescription of the field
DefaultDefault value when a new record is created.
+ Note: “user” will set the current user as default and “today” will set today’s date (if the field is a Date field).
+ +#### Field Types and Options + +Here is a list of the different types of fields used to make / customize forms in ERPNext. + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDescriptionOptions/Setting
DataSingle line text field with 180 characters
SelectSelect from a pre-determined items in a drop-down.The “Options” contains the drop-down items, each on a new row
LinkLink an existing document / recordOptions contains the name of the type of document (DocType)
CurrencyNumber with 2 decimal places, that will be shown separated by commas for thousands etc. in Print.e.g. 1,000,000.00
FloatNumber with 6 decimal places.e.g. 3.141593
IntInteger (no decimals)e.g. 100
DateDateFormat can be selected in Global Defaults
TimeTime
Text
TextMulti-line text box without formatting features
Text editorMulti-line text box with formatting toolbar etc
CodeCode EditorOptions can include the type of language for syntax formatting. + Eg JS / Python / HTML
Table (Grid)
TableTable of child items linked to the record.Options contains the name of the DocType of the child table. For example “Sales Invoice Item” for “Sales Invoice”
Layout
Section BreakBreak into a new horizontal section.The layout in ERPNext is evaluated from top to bottom.
Column BreakBreak into a new vertical column.
HTMLAdd a static text / help / link etc in HTMLOptions contains the HTML.
Action
ButtonButton[for developers only]
+ + + + + + + \ No newline at end of file diff --git a/docs/user/knowledge/docs.user.knowledge.markdown.md b/docs/user/knowledge/docs.user.knowledge.markdown.md new file mode 100644 index 00000000000..b2f76be5831 --- /dev/null +++ b/docs/user/knowledge/docs.user.knowledge.markdown.md @@ -0,0 +1,84 @@ +--- +{ + "_label": "Format Using Markdown" +} +--- + +Markdown is a simple way of writing text to format your content. Markdown allows you easy ways to format. + +1. Headings (h1 (largest), h2, h3, h4 and so on) +1. Paragraphs +1. Lists (numbered or bulleted) +1. Hyper links (links to other pages) +1. Images +1. Code +1. Embed HTML (HTML tags within your text) + +#### Headings + +Headings are specified by adding a `#` (hash) at the beginning of the line. The more the number of hashes, the smaller the heading: + + # This is a large heading. + + ### This is a smaller heading. + +#### Paragraphs + +To start a new paragraph, just make sure that there is an empty line at the beginning and end of the paragraph. + +To format text as **bold** or with _italics_ format as follows: + + **This text** is **bold** and _this one_ is with _italics_ + +#### Lists + +To define numbered lists, start your link with a number and a dot (.) and ensure there is a blank line before and after the list. The numbers are automatically generated so it does not matter what number you put: + + 1. list 1st item + 1. second item + 1. and so on + 1. and so forth + +To define bulleted lists, start your items with a hyphen (-) + + - item 1 + - item 2 + - item 3 + +To nest lists within one another, put four spaces to indent your inner list as follows: + + 1. item 1 + 1. item 2 + - sub item 1 + - sub item 2 + 1. item 3 + +#### Links (to other pages) + +Links to other pages can be defined by adding your text in box brackets [] followed by the link in round brackets () + + [This is an external link](http://example.com) + [A link within the site](my-page.html) + +#### Images + +Images can be added by adding an exclamation ! before the link. + + ![A flower](files/flower.gif) + + +#### Code + +To add a code block, just leave a blank line before and after the block and make sure all code line are indented by four spaces: + + This is normal text + + This is a code block + +#### HTML + +You can embed any kind of HTML tags within your code. Any content written within HTML tags will not be formatted. + +[Detailed description of the markdown format](http://daringfireball.net/projects/markdown/syntax) + + diff --git a/docs/user/knowledge/docs.user.knowledge.md b/docs/user/knowledge/docs.user.knowledge.md index 5d98cdd4596..11dc9957ac1 100644 --- a/docs/user/knowledge/docs.user.knowledge.md +++ b/docs/user/knowledge/docs.user.knowledge.md @@ -4,8 +4,12 @@ "_toc": [ "docs.user.knowledge.fiscal_year", "docs.user.knowledge.accounting", - "docs.user.knowledge.accounting_entries" + "docs.user.knowledge.accounting_entries", + "docs.user.knowledge.doctype", + "docs.user.knowledge.attachment_csv", + "docs.user.knowledge.markdown" ] } --- -Knowledge Library contains definitions and explanations of various management concepts. This page is created for users who wish to elaborate their conceptual knowledge. \ No newline at end of file +Knowledge Library contains definitions and explanations of various management concepts. This page is created for users who wish to elaborate their conceptual knowledge. + diff --git a/docs/user/selling/docs.user.selling.customer.md b/docs/user/selling/docs.user.selling.customer.md index 108f20da831..5336ac61a11 100644 --- a/docs/user/selling/docs.user.selling.customer.md +++ b/docs/user/selling/docs.user.selling.customer.md @@ -4,7 +4,9 @@ "_title_image": "img/customers.png" } --- -You can either directly create your Customers via +A customer, who is sometimes known as a client, buyer, or purchaser is the one who receives goods, services, products, or ideas, from a seller for a monetary consideration. A customer can also receive goods or services from a vendor or a supplier for other valuable considerations. + + You can either directly create your Customers via > Selling > Customer diff --git a/docs/user/setup/docs.user.setup.data_import.md b/docs/user/setup/docs.user.setup.data_import.md index eec6b65e453..b40573ed43a 100644 --- a/docs/user/setup/docs.user.setup.data_import.md +++ b/docs/user/setup/docs.user.setup.data_import.md @@ -3,7 +3,7 @@ "_label": "Data Import Tool" } --- -The Data Import Tool is a great way to upload (or edit) bulk data, specially master data, into the system. To start the tool go to: +The Data Import Tool is a great way to upload (or edit) bulk data, specially master data, into the system. To Open the data import tool, you either go to Setup or go to the Transaction you want to Import. If Data Import is allowed, you will see an Import Button: @@ -15,7 +15,7 @@ The tool has two sections, one to download a template and the second to upload t ### 1. Downloading The Template -Data in ERPNext is stored in tables, much like a spreadsheet with columns and rows of data. Each entity in ERPNext can have multiple child tables associated with it too. The child tables are linked to the parent tables and are implemented where are multiple values for any property. For example an Item can have multiple prices, An Invoice has multiple Items and so on. +Data in ERPNext is stored in tables, much like a spreadsheet with columns and rows of data. Each entity in ERPNext can have multiple child tables associated with it too. The child tables are linked to the parent tables and are implemented where there are multiple values for any property. For example an Item can have multiple prices, An Invoice has multiple Items and so on. You can import each table separately, or all at a time. In the child table, you must mention the parent of the row in the “parent” column so that ERPNext knows which Item’s price or tax you are trying to set if you are importing separately. @@ -36,7 +36,7 @@ Then export your template or save it as a **Comma Separated Values** (CSV) file. ### 3. Upload the .csv File -Finally attach the .csv file in the section section click on the "Upload and Import" button. +Finally attach the .csv file in the section. Click on the "Upload and Import" button. ![Attach and Upload](img/import-5.png) diff --git a/docs/user/stock/docs.user.stock.item.md b/docs/user/stock/docs.user.stock.item.md index c98afd29dd8..5ac78d7e51a 100644 --- a/docs/user/stock/docs.user.stock.item.md +++ b/docs/user/stock/docs.user.stock.item.md @@ -27,11 +27,7 @@ To upload an image for your icon that will appear in all transactions, save the ![Item Properties](img/item-add-image.png) -### Item Pricing - -Item Price and Price Lists: ERPNext lets you maintain multiple selling prices for an Item using Price Lists. A Price List is a place where different rate plans can be stored. It’s a name you can give to a set of Item prices. In case you have different zones (based on the shipping costs), for different currencies etc, you can maintain different Price Lists. A Price List is formed when you create different Item Prices. To import Item Price see [Importing Data](docs.user.data_import.md). - -## Inventory : Warehouse and Stock Setting +### Inventory : Warehouse and Stock Setting In ERPNext, you can select different type of Warehouses to stock your different Items. This can be selected based on Item types. It could be Fixed Asset Item, Stock Item or even Manufacturing Item. From d086d724b638a80e501abf4746ce3ebcab4c0e81 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Mon, 30 Sep 2013 11:37:44 +0530 Subject: [PATCH 25/41] [price_list] new grid finished with fixes --- setup/doctype/price_list/price_list.js | 37 +++++--------------------- 1 file changed, 7 insertions(+), 30 deletions(-) diff --git a/setup/doctype/price_list/price_list.js b/setup/doctype/price_list/price_list.js index 6dfbd0f1eef..0057773d57d 100644 --- a/setup/doctype/price_list/price_list.js +++ b/setup/doctype/price_list/price_list.js @@ -12,8 +12,12 @@ cur_frm.cscript.refresh = function(doc, cdt, cdn) { } cur_frm.cscript.show_item_prices = function() { - var counter = 0; var item_price = wn.model.get("Item Price", {parent: cur_frm.doc.name}); + var show = item_price && item_price.length; + + cur_frm.toggle_display("item_prices", show); + $(cur_frm.fields_dict.item_prices.wrapper).empty(); + if (!show) return; new wn.ui.form.TableGrid({ parent: cur_frm.fields_dict.item_prices.wrapper, @@ -159,7 +163,8 @@ wn.ui.form.TableGrid = Class.extend({ fields: this.fields }); - this.dialog.set_values(this.make_dialog_values(row)); + if (row) + this.dialog.set_values(this.make_dialog_values(row)); $a(this.dialog.body, 'div', '', '', this.make_dialog_buttons()); this.dialog.show(); @@ -173,34 +178,6 @@ wn.ui.form.TableGrid = Class.extend({ }); return row; }, - // make_dialog_fields: function() { - // var me = this; - // var fields = []; - - // $.each(this.fields, function(i, obj) { - // var dialog_field = { - // fieldtype: obj.fieldtype, - // fieldname: obj.fieldname, - // label: obj.label - // } - - // // check if fields has options - // if (obj.options) { - // var options = {options: obj.options} - // $.extend(dialog_field, options); - // } - - // // check if field is mandatory - // if (obj.reqd == 1) { - // var reqd = {reqd: obj.reqd} - // $.extend(dialog_field, reqd); - // } - - // fields.push(obj); - // }); - - // return fields; - // }, make_dialog_values: function(row) { var me = this; var dialog_values = {}; From 7d36fc821bba65928c8a9537720fb119e6bb4122 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Mon, 30 Sep 2013 12:44:00 +0530 Subject: [PATCH 26/41] [fix] [minor] new grid fix to hide other grid --- setup/doctype/price_list/price_list.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/setup/doctype/price_list/price_list.js b/setup/doctype/price_list/price_list.js index 0057773d57d..a190710d4e5 100644 --- a/setup/doctype/price_list/price_list.js +++ b/setup/doctype/price_list/price_list.js @@ -13,11 +13,9 @@ cur_frm.cscript.refresh = function(doc, cdt, cdn) { cur_frm.cscript.show_item_prices = function() { var item_price = wn.model.get("Item Price", {parent: cur_frm.doc.name}); - var show = item_price && item_price.length; - - cur_frm.toggle_display("item_prices", show); + + cur_frm.toggle_display("item_prices", true); $(cur_frm.fields_dict.item_prices.wrapper).empty(); - if (!show) return; new wn.ui.form.TableGrid({ parent: cur_frm.fields_dict.item_prices.wrapper, From 9cb2cdbce6635d034eb09e05d8c09d2fcb7a88e4 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Mon, 30 Sep 2013 15:43:00 +0530 Subject: [PATCH 27/41] [price_list] [minor] fix of new grid --- setup/doctype/price_list/price_list.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/setup/doctype/price_list/price_list.js b/setup/doctype/price_list/price_list.js index a190710d4e5..cbca413f0ce 100644 --- a/setup/doctype/price_list/price_list.js +++ b/setup/doctype/price_list/price_list.js @@ -181,7 +181,7 @@ wn.ui.form.TableGrid = Class.extend({ var dialog_values = {}; $.each(this.fields, function(i, item) { - dialog_values[item.fieldname] = $(row).find('td[data-fieldname="'+ item.fieldname +'"]').data('fieldvalue'); + dialog_values[item.fieldname] = $(row).find('td[data-fieldname="'+ item.fieldname +'"]').attr('data-fieldvalue'); }); return dialog_values; @@ -206,9 +206,9 @@ wn.ui.form.TableGrid = Class.extend({ $.each(me.fields, function(i, item) { var $td = $(row).find('td[data-fieldname="'+ item.fieldname +'"]'); var val = me.dialog.get_values()[item.fieldname]; - + wn.model.set_value(me.table_field.options, $td.attr('data-doc_name'), - item.fieldname, me.dialog.get_values()[item.fieldname]); + item.fieldname, val); $td.attr('data-fieldvalue', val); // If field type is currency the update with format currency @@ -279,6 +279,10 @@ wn.ui.form.TableGrid = Class.extend({ } }); + // refresh field to push to grid rows + refresh_field(this.table_field.fieldname); + + // append row to tbody of grid $(new_row).appendTo($(this.parent).find(".grid tbody")); } }); \ No newline at end of file From eb8753e8b6419d6d50765d42975d3fcf800db078 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Mon, 30 Sep 2013 15:56:36 +0530 Subject: [PATCH 28/41] [fix] [minor] new grid to hide delete button on new row & added description --- setup/doctype/price_list/price_list.js | 6 +++--- setup/doctype/price_list/price_list.txt | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/setup/doctype/price_list/price_list.js b/setup/doctype/price_list/price_list.js index cbca413f0ce..397e9826ad6 100644 --- a/setup/doctype/price_list/price_list.js +++ b/setup/doctype/price_list/price_list.js @@ -164,7 +164,7 @@ wn.ui.form.TableGrid = Class.extend({ if (row) this.dialog.set_values(this.make_dialog_values(row)); - $a(this.dialog.body, 'div', '', '', this.make_dialog_buttons()); + $a(this.dialog.body, 'div', '', '', this.make_dialog_buttons(row)); this.dialog.show(); this.dialog.$wrapper.find('button.update').on('click', function() { @@ -186,12 +186,12 @@ wn.ui.form.TableGrid = Class.extend({ return dialog_values; }, - make_dialog_buttons: function() { + make_dialog_buttons: function(row) { var me = this; var buttons = ''; // if user can delete then only add the delete button in dialog - if (wn.model.can_delete(me.frm.doc.doctype)) + if (wn.model.can_delete(me.frm.doc.doctype) && row) buttons += ' '; return buttons; diff --git a/setup/doctype/price_list/price_list.txt b/setup/doctype/price_list/price_list.txt index 46905a65918..343331dd0c6 100644 --- a/setup/doctype/price_list/price_list.txt +++ b/setup/doctype/price_list/price_list.txt @@ -2,7 +2,7 @@ { "creation": "2013-01-25 11:35:09", "docstatus": 0, - "modified": "2013-09-06 15:03:38", + "modified": "2013-09-30 15:50:52", "modified_by": "Administrator", "owner": "Administrator" }, @@ -85,6 +85,7 @@ "reqd": 1 }, { + "description": "To change row values, click on the respective row", "doctype": "DocField", "fieldname": "item_prices_section", "fieldtype": "Section Break", From 300ae0cdf4444129f789a4b45cb4037e890951d5 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 30 Sep 2013 17:57:22 +0530 Subject: [PATCH 29/41] [fix] [minor] dont call is_pos trigger in onload of pos invoice --- accounts/doctype/sales_invoice/sales_invoice.js | 6 ++++-- accounts/doctype/sales_invoice/sales_invoice.py | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/accounts/doctype/sales_invoice/sales_invoice.js b/accounts/doctype/sales_invoice/sales_invoice.js index 6639e65e6c5..4f8dda8fbe2 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.js +++ b/accounts/doctype/sales_invoice/sales_invoice.js @@ -29,8 +29,10 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte // toggle to pos view if is_pos is 1 in user_defaults if ((cint(wn.defaults.get_user_defaults("is_pos"))===1 || cur_frm.doc.is_pos) && cint(wn.defaults.get_user_defaults("fs_pos_view"))===1) { - this.frm.set_value("is_pos", 1); - this.is_pos(); + if(this.frm.doc.__islocal) { + this.frm.set_value("is_pos", 1); + this.is_pos(); + } cur_frm.cscript.toggle_pos(true); } diff --git a/accounts/doctype/sales_invoice/sales_invoice.py b/accounts/doctype/sales_invoice/sales_invoice.py index 12deed73a87..2eb9ae84cb0 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.py +++ b/accounts/doctype/sales_invoice/sales_invoice.py @@ -195,7 +195,7 @@ class DocType(SellingController): pos = get_pos_settings(self.doc.company) if pos: - if not for_validate: + if not for_validate and not self.doc.customer: self.doc.customer = pos.customer self.set_customer_defaults() From cadc6e1b2be2563bd3afed150bd76d8313f7cb54 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 30 Sep 2013 17:57:37 +0530 Subject: [PATCH 30/41] [fix] [minor] dont call is_pos trigger in onload of pos invoice --- setup/doctype/price_list/price_list.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/setup/doctype/price_list/price_list.js b/setup/doctype/price_list/price_list.js index a190710d4e5..cbca413f0ce 100644 --- a/setup/doctype/price_list/price_list.js +++ b/setup/doctype/price_list/price_list.js @@ -181,7 +181,7 @@ wn.ui.form.TableGrid = Class.extend({ var dialog_values = {}; $.each(this.fields, function(i, item) { - dialog_values[item.fieldname] = $(row).find('td[data-fieldname="'+ item.fieldname +'"]').data('fieldvalue'); + dialog_values[item.fieldname] = $(row).find('td[data-fieldname="'+ item.fieldname +'"]').attr('data-fieldvalue'); }); return dialog_values; @@ -206,9 +206,9 @@ wn.ui.form.TableGrid = Class.extend({ $.each(me.fields, function(i, item) { var $td = $(row).find('td[data-fieldname="'+ item.fieldname +'"]'); var val = me.dialog.get_values()[item.fieldname]; - + wn.model.set_value(me.table_field.options, $td.attr('data-doc_name'), - item.fieldname, me.dialog.get_values()[item.fieldname]); + item.fieldname, val); $td.attr('data-fieldvalue', val); // If field type is currency the update with format currency @@ -279,6 +279,10 @@ wn.ui.form.TableGrid = Class.extend({ } }); + // refresh field to push to grid rows + refresh_field(this.table_field.fieldname); + + // append row to tbody of grid $(new_row).appendTo($(this.parent).find(".grid tbody")); } }); \ No newline at end of file From 4233ae2258a1f60edb9e5cc331fc79312e2c08c8 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Mon, 30 Sep 2013 18:18:19 +0530 Subject: [PATCH 31/41] [pos] pos related fixes --- accounts/doctype/sales_invoice/pos.js | 32 ++++++++++++++++----------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/accounts/doctype/sales_invoice/pos.js b/accounts/doctype/sales_invoice/pos.js index e19652d25f5..0dba40fabcb 100644 --- a/accounts/doctype/sales_invoice/pos.js +++ b/accounts/doctype/sales_invoice/pos.js @@ -214,7 +214,7 @@ erpnext.POS = Class.extend({ // if form is local then allow this function if (me.frm.doc.docstatus===0) { - $("div.pos-item").on("click", function() { + $(me.wrapper).find("div.pos-item").on("click", function() { if(!me.frm.doc[me.party.toLowerCase()] && ((me.frm.doctype == "Quotation" && me.frm.doc.quotation_to == "Customer") || me.frm.doctype != "Quotation")) { @@ -313,7 +313,7 @@ erpnext.POS = Class.extend({ // taxes var taxes = wn.model.get_children(this.sales_or_purchase + " Taxes and Charges", this.frm.doc.name, this.frm.cscript.other_fname, this.frm.doctype); - $(".tax-table") + $(this.wrapper).find(".tax-table") .toggle((taxes && taxes.length) ? true : false) .find("tbody").empty(); @@ -345,18 +345,18 @@ erpnext.POS = Class.extend({ // if form is local then only run all these functions if (this.frm.doc.docstatus===0) { - $("input.qty").on("focus", function() { + $(this.wrapper).find("input.qty").on("focus", function() { $(this).select(); }); // append quantity to the respective item after change from input box - $("input.qty").on("change", function() { + $(this.wrapper).find("input.qty").on("change", function() { var item_code = $(this).closest("tr")[0].id; me.update_qty(item_code, $(this).val(), true); }); // on td click toggle the highlighting of row - me.wrapper.find("#cart tbody tr td").on("click", function() { + $(this.wrapper).find("#cart tbody tr td").on("click", function() { var row = $(this).closest("tr"); if (row.attr("data-selected") == "false") { row.attr("class", "warning"); @@ -376,16 +376,22 @@ erpnext.POS = Class.extend({ // if form is submitted & cancelled then disable all input box & buttons if (this.frm.doc.docstatus>=1) { - me.wrapper.find('input, button').each(function () { + $(this.wrapper).find('input, button').each(function () { $(this).prop('disabled', true); }); - $(".delete-items").hide(); - $(".make-payment").hide(); + $(this.wrapper).find(".delete-items").hide(); + $(this.wrapper).find(".make-payment").hide(); + } + else { + $(this.wrapper).find('input, button').each(function () { + $(this).prop('disabled', false); + }); + $(this.wrapper).find(".make-payment").show(); } // Show Make Payment button only in Sales Invoice if (this.frm.doctype != "Sales Invoice") - $(".make-payment").hide(); + $(this.wrapper).find(".make-payment").hide(); // If quotation to is not Customer then remove party if (this.frm.doctype == "Quotation") { @@ -395,7 +401,7 @@ erpnext.POS = Class.extend({ } }, refresh_delete_btn: function() { - $(".delete-items").toggle($(".item-cart .warning").length ? true : false); + $(this.wrapper).find(".delete-items").toggle($(".item-cart .warning").length ? true : false); }, add_item_thru_barcode: function() { var me = this; @@ -417,9 +423,9 @@ erpnext.POS = Class.extend({ remove_selected_item: function() { var me = this; var selected_items = []; - var no_of_items = me.wrapper.find("#cart tbody tr").length; + var no_of_items = $(this.wrapper).find("#cart tbody tr").length; for(var x=0; x<=no_of_items - 1; x++) { - var row = me.wrapper.find("#cart tbody tr:eq(" + x + ")"); + var row = $(this.wrapper).find("#cart tbody tr:eq(" + x + ")"); if(row.attr("data-selected") == "true") { selected_items.push(row.attr("id")); } @@ -442,7 +448,7 @@ erpnext.POS = Class.extend({ }, make_payment: function() { var me = this; - var no_of_items = me.wrapper.find("#cart tbody tr").length; + var no_of_items = $(this.wrapper).find("#cart tbody tr").length; var mode_of_payment = []; if (no_of_items == 0) From 67a9ea68008c6a73e89bdd18fd75d8b135714299 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Mon, 30 Sep 2013 19:05:36 +0530 Subject: [PATCH 32/41] [price_list] [minor] move header of new grid to right if currency --- setup/doctype/price_list/price_list.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/setup/doctype/price_list/price_list.js b/setup/doctype/price_list/price_list.js index 397e9826ad6..2c24d7ec89d 100644 --- a/setup/doctype/price_list/price_list.js +++ b/setup/doctype/price_list/price_list.js @@ -93,11 +93,16 @@ wn.ui.form.TableGrid = Class.extend({ // Make other headers with label as heading $.each(this.fields, function(i, obj) { - if (obj.in_list_view===1) - var th = document.createElement("th"); + var th = document.createElement("th"); + + // If currency then move header to right + if (obj.fieldtype == "Currency") + $(th).attr("style", "vertical-align:middle; text-align:right;"); + else $(th).attr("style", "vertical-align:middle"); - $(th).html(obj.label); - $(th).appendTo(row); + + $(th).html(obj.label); + $(th).appendTo(row); }); return header; From d780baeacc92c4c8c83fde464de75982a503f2cd Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 1 Oct 2013 11:22:51 +0530 Subject: [PATCH 33/41] [fix] [minor] fixes in old patch --- patches/august_2013/p02_rename_price_list.py | 1 + 1 file changed, 1 insertion(+) diff --git a/patches/august_2013/p02_rename_price_list.py b/patches/august_2013/p02_rename_price_list.py index 41efb273069..0a1929925ba 100644 --- a/patches/august_2013/p02_rename_price_list.py +++ b/patches/august_2013/p02_rename_price_list.py @@ -6,6 +6,7 @@ import webnotes def execute(): webnotes.reload_doc("selling", "doctype", "shopping_cart_price_list") + webnotes.reload_doc("setup", "doctype", "item_price") for t in [ ("Supplier Quotation", "price_list_name", "buying_price_list"), From 49e71400acfadfe0b14ec0ada1e4541ffddf88b0 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 1 Oct 2013 15:20:06 +0530 Subject: [PATCH 34/41] [patch] [minor] fix wrong customers in pos --- patches/patch_list.py | 1 + .../september_2013/p05_fix_customer_in_pos.py | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 patches/september_2013/p05_fix_customer_in_pos.py diff --git a/patches/patch_list.py b/patches/patch_list.py index 7041ba88585..6d1a084f68e 100644 --- a/patches/patch_list.py +++ b/patches/patch_list.py @@ -218,4 +218,5 @@ patch_list = [ "execute:webnotes.bean('Style Settings').save() #2013-09-19", "execute:webnotes.conn.set_value('Accounts Settings', None, 'frozen_accounts_modifier', 'Accounts Manager') # 2013-09-24", "patches.september_2013.p04_unsubmit_serial_nos", + "patches.september_2013.p05_fix_customer_in_pos", ] \ No newline at end of file diff --git a/patches/september_2013/p05_fix_customer_in_pos.py b/patches/september_2013/p05_fix_customer_in_pos.py new file mode 100644 index 00000000000..60210dab24e --- /dev/null +++ b/patches/september_2013/p05_fix_customer_in_pos.py @@ -0,0 +1,22 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import webnotes +def execute(): + si_list = webnotes.conn.sql("""select name, debit_to from `tabSales Invoice` + where ifnull(is_pos, 1)=1 and docstatus=1 and modified > '2013-09-03'""", as_dict=1) + + for si in si_list: + if not webnotes.conn.get_value("GL Entry", {"voucher_type": "Sales Invoice", + "voucher_no": si.name, "account": si.debit_to}): + debit_to = webnotes.conn.sql("""select account from `tabGL Entry` gle + where voucher_type='Sales Invoice' and voucher_no=%s + and (select master_type from tabAccount where name=gle.account)='Customer' + """, si.name) + if debit_to: + si_bean = webnotes.bean("Sales Invoice", si.name) + si_bean.doc.debit_to = debit_to[0][0] + si_bean.doc.customer = None + si_bean.run_method("set_customer_defaults") + si_bean.update_after_submit() \ No newline at end of file From b6177cbb5b38c88624eefb09f921e69d30157d41 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Tue, 1 Oct 2013 17:11:39 +0530 Subject: [PATCH 35/41] [minor] change filename to unicode after os.walk and os.listdir --- setup/doctype/backup_manager/backup_dropbox.py | 1 + setup/doctype/backup_manager/backup_googledrive.py | 1 + setup/doctype/company/charts/import_from_openerp.py | 2 ++ 3 files changed, 4 insertions(+) diff --git a/setup/doctype/backup_manager/backup_dropbox.py b/setup/doctype/backup_manager/backup_dropbox.py index 8d163539522..b4a8f66d4c0 100644 --- a/setup/doctype/backup_manager/backup_dropbox.py +++ b/setup/doctype/backup_manager/backup_dropbox.py @@ -96,6 +96,7 @@ def backup_to_dropbox(): error_log = [] path = os.path.join(get_base_path(), "public", "files") for filename in os.listdir(path): + filename = cstr(filename) if filename in ignore_list: continue diff --git a/setup/doctype/backup_manager/backup_googledrive.py b/setup/doctype/backup_manager/backup_googledrive.py index 5d7b6ad0fa1..440d907f2ed 100644 --- a/setup/doctype/backup_manager/backup_googledrive.py +++ b/setup/doctype/backup_manager/backup_googledrive.py @@ -85,6 +85,7 @@ def backup_to_gdrive(): webnotes.conn.close() path = os.path.join(get_base_path(), "public", "files") for filename in os.listdir(path): + filename = cstr(filename) found = False filepath = os.path.join(path, filename) ext = filename.split('.')[-1] diff --git a/setup/doctype/company/charts/import_from_openerp.py b/setup/doctype/company/charts/import_from_openerp.py index 894c2d739d8..ef800086c94 100644 --- a/setup/doctype/company/charts/import_from_openerp.py +++ b/setup/doctype/company/charts/import_from_openerp.py @@ -9,6 +9,7 @@ from __future__ import unicode_literals import os, json from xml.etree import ElementTree as ET from webnotes.utils.datautils import read_csv_content +from webnotes.utils import cstr path = "/Users/rmehta/Downloads/openerp/openerp/addons" chart_roots = [] @@ -108,6 +109,7 @@ def find_charts(): basename = os.path.basename(basepath) if basename.startswith("l10n"): for fname in files: + fname = cstr(fname) filepath = os.path.join(basepath, fname) if fname.endswith(".xml"): tree = ET.parse(filepath) From cf3011839f6ab28f9f1d75759bdd3c9fa30b8914 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 1 Oct 2013 18:14:16 +0530 Subject: [PATCH 36/41] [fix] [minor] bind onclick function based on docstatus in pos --- accounts/doctype/sales_invoice/pos.js | 12 ++++++------ accounts/doctype/sales_invoice/sales_invoice.js | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/accounts/doctype/sales_invoice/pos.js b/accounts/doctype/sales_invoice/pos.js index 0dba40fabcb..c68b9915c88 100644 --- a/accounts/doctype/sales_invoice/pos.js +++ b/accounts/doctype/sales_invoice/pos.js @@ -213,8 +213,8 @@ erpnext.POS = Class.extend({ }); // if form is local then allow this function - if (me.frm.doc.docstatus===0) { - $(me.wrapper).find("div.pos-item").on("click", function() { + $(me.wrapper).find("div.pos-item").on("click", function() { + if(me.frm.doc.docstatus==0) { if(!me.frm.doc[me.party.toLowerCase()] && ((me.frm.doctype == "Quotation" && me.frm.doc.quotation_to == "Customer") || me.frm.doctype != "Quotation")) { @@ -223,8 +223,8 @@ erpnext.POS = Class.extend({ } else me.add_to_cart($(this).attr("data-item_code")); - }); - } + } + }); } }); }, @@ -371,7 +371,7 @@ erpnext.POS = Class.extend({ }); me.refresh_delete_btn(); - this.frm.pos.barcode.$input.focus(); + this.barcode.$input.focus(); } // if form is submitted & cancelled then disable all input box & buttons @@ -476,7 +476,7 @@ erpnext.POS = Class.extend({ "total_amount": $(".grand-total").text() }); dialog.show(); - me.frm.pos.barcode.$input.focus(); + me.barcode.$input.focus(); dialog.get_input("total_amount").prop("disabled", true); diff --git a/accounts/doctype/sales_invoice/sales_invoice.js b/accounts/doctype/sales_invoice/sales_invoice.js index 4f8dda8fbe2..5220c0fa20c 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.js +++ b/accounts/doctype/sales_invoice/sales_invoice.js @@ -29,11 +29,10 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte // toggle to pos view if is_pos is 1 in user_defaults if ((cint(wn.defaults.get_user_defaults("is_pos"))===1 || cur_frm.doc.is_pos) && cint(wn.defaults.get_user_defaults("fs_pos_view"))===1) { - if(this.frm.doc.__islocal) { + if(this.frm.doc.__islocal && !this.frm.doc.amended_from) { this.frm.set_value("is_pos", 1); - this.is_pos(); + this.is_pos(function() {cur_frm.cscript.toggle_pos(true);}); } - cur_frm.cscript.toggle_pos(true); } // if document is POS then change default print format to "POS Invoice" @@ -128,7 +127,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte this.get_terms(); }, - is_pos: function() { + is_pos: function(callback_fn) { cur_frm.cscript.hide_fields(this.frm.doc); if(cint(this.frm.doc.is_pos)) { if(!this.frm.doc.company) { @@ -142,6 +141,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte callback: function(r) { if(!r.exc) { me.frm.script_manager.trigger("update_stock"); + if(callback_fn) callback_fn() } } }); From 2ebbe95e0464e0a273bdcd057ed3f69bc144ad8a Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 2 Oct 2013 12:44:59 +0530 Subject: [PATCH 37/41] [minor] [fix] item prices html table --- setup/doctype/price_list/price_list.js | 248 ++++++++++-------------- setup/doctype/price_list/price_list.txt | 8 +- 2 files changed, 112 insertions(+), 144 deletions(-) diff --git a/setup/doctype/price_list/price_list.js b/setup/doctype/price_list/price_list.js index 2c24d7ec89d..1dd9ec53de8 100644 --- a/setup/doctype/price_list/price_list.js +++ b/setup/doctype/price_list/price_list.js @@ -14,46 +14,42 @@ cur_frm.cscript.refresh = function(doc, cdt, cdn) { cur_frm.cscript.show_item_prices = function() { var item_price = wn.model.get("Item Price", {parent: cur_frm.doc.name}); - cur_frm.toggle_display("item_prices", true); - $(cur_frm.fields_dict.item_prices.wrapper).empty(); + $(cur_frm.fields_dict.item_prices_html.wrapper).empty(); new wn.ui.form.TableGrid({ - parent: cur_frm.fields_dict.item_prices.wrapper, + parent: cur_frm.fields_dict.item_prices_html.wrapper, frm: cur_frm, - table_field: wn.model.get("DocField", {parent:"Price List", fieldname:"item_prices"})[0] + table_field: wn.meta.get_docfield("Price List", "item_prices", cur_frm.doc.name) }); } wn.ui.form.TableGrid = Class.extend({ init: function(opts) { $.extend(this, opts); - this.fields = wn.model.get("DocField", {parent: this.table_field.options}); + this.fields = wn.meta.get_docfields("Item Price", cur_frm.doc.name); this.make_table(); }, make_table: function() { var me = this; // Creating table & assigning attributes var grid_table = document.createElement("table"); - $(grid_table).attr("class", "table table-hover table-bordered grid"); + grid_table.className = "table table-hover table-bordered grid"; // Appending header & rows to table - - $(this.make_table_headers()).appendTo(grid_table); - $(this.make_table_rows()).appendTo(grid_table); + grid_table.appendChild(this.make_table_headers()); + grid_table.appendChild(this.make_table_rows()); // Creating button to add new row var btn_div = document.createElement("div"); var new_row_btn = document.createElement("button"); - $new_row_btn = $(new_row_btn); - $new_row_btn.attr({ - "class": "btn btn-success table-new-row", - "title": "Add new row" - }); + new_row_btn.className = "btn btn-success table-new-row"; + new_row_btn.title = "Add new row"; + var btn_icon = document.createElement("i"); - $(btn_icon).attr("class", "icon-plus"); - $(btn_icon).appendTo(new_row_btn); - $new_row_btn.append(" Add new row"); - $new_row_btn.appendTo(btn_div); + btn_icon.className = "icon-plus"; + new_row_btn.appendChild(btn_icon); + new_row_btn.innerHTML += " Add new row"; + btn_div.appendChild(new_row_btn); // Appending table & button to parent var $grid_table = $(grid_table).appendTo($(this.parent)); @@ -75,35 +71,33 @@ wn.ui.form.TableGrid = Class.extend({ // Creating header row var row = document.createElement("tr"); - $(row).attr({ - "class": "active", - "style": "height:50px" - }); - $(row).appendTo(header); - + row.className = "active"; + // row.style = "height:50px"; + + // Creating head first cell var th = document.createElement("th"); - $(th).attr({ - "width": "8%", - "style": "vertical-align:middle", - "class": "text-center" - }); - $(th).html("#"); - $(th).appendTo(row); + th.width = "8%"; + th.className = "text-center"; + th.innerHTML = "#"; + row.appendChild(th); // Make other headers with label as heading - $.each(this.fields, function(i, obj) { - var th = document.createElement("th"); + for(var i=0, l=this.fields.length; i Date: Wed, 2 Oct 2013 15:16:22 +0530 Subject: [PATCH 38/41] [minor] [fix] item price grid --- setup/doctype/price_list/price_list.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/setup/doctype/price_list/price_list.js b/setup/doctype/price_list/price_list.js index 1dd9ec53de8..e1cb52130d7 100644 --- a/setup/doctype/price_list/price_list.js +++ b/setup/doctype/price_list/price_list.js @@ -33,7 +33,7 @@ wn.ui.form.TableGrid = Class.extend({ var me = this; // Creating table & assigning attributes var grid_table = document.createElement("table"); - grid_table.className = "table table-hover table-bordered grid"; + grid_table.className = "table table-hover table-bordered table-grid"; // Appending header & rows to table grid_table.appendChild(this.make_table_headers()); @@ -72,8 +72,6 @@ wn.ui.form.TableGrid = Class.extend({ // Creating header row var row = document.createElement("tr"); row.className = "active"; - // row.style = "height:50px"; - // Creating head first cell var th = document.createElement("th"); @@ -106,7 +104,6 @@ wn.ui.form.TableGrid = Class.extend({ // Creating table body var table_body = document.createElement("tbody"); - table_body.style = "cursor: pointer"; var item_prices = wn.model.get_children(this.table_field.options, this.frm.doc.name, this.table_field.fieldname, this.frm.doctype); @@ -210,8 +207,7 @@ wn.ui.form.TableGrid = Class.extend({ $(row).remove(); // Re-assign idx - $.each($(this.parent).find(".grid tbody tr"), function(idx, data) { - $(data).attr("data-idx", idx + 1); + $.each($(this.parent).find("tbody tr"), function(idx, data) { var $td = $(data).find('td:first'); $td.html(idx + 1); }); @@ -221,7 +217,6 @@ wn.ui.form.TableGrid = Class.extend({ add_new_row: function(d) { var tr = document.createElement("tr"); tr.className = "table-row"; - tr.setAttribute("data-idx", d.idx); tr.setAttribute("data-docname", d.name); // Creating table data & appending to row From c49986f092ab145205adc47e3aeae6dd0da550e8 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 2 Oct 2013 16:14:30 +0530 Subject: [PATCH 39/41] [minor] [fix] price list table --- setup/doctype/price_list/price_list.css | 7 +++++++ setup/doctype/price_list/price_list.js | 7 +++++++ 2 files changed, 14 insertions(+) create mode 100644 setup/doctype/price_list/price_list.css diff --git a/setup/doctype/price_list/price_list.css b/setup/doctype/price_list/price_list.css new file mode 100644 index 00000000000..61b069442f8 --- /dev/null +++ b/setup/doctype/price_list/price_list.css @@ -0,0 +1,7 @@ +.table-grid tbody tr { + cursor: pointer; +} + +.table-grid thead tr { + height: 50px; +} \ No newline at end of file diff --git a/setup/doctype/price_list/price_list.js b/setup/doctype/price_list/price_list.js index e1cb52130d7..67090bcbc16 100644 --- a/setup/doctype/price_list/price_list.js +++ b/setup/doctype/price_list/price_list.js @@ -188,6 +188,13 @@ wn.ui.form.TableGrid = Class.extend({ if(!docname && row) docname = $(row).attr("data-docname"); $.each(me.fields, function(i, df) { var val = me.dialog.get_values()[df.fieldname]; + + if(["Currency", "Float"].indexOf(df.fieldtype)!==-1) { + val = flt(val); + } else if(["Int", "Check"].indexOf(df.fieldtype)!==-1) { + val = cint(val); + } + wn.model.set_value(me.table_field.options, docname, df.fieldname, val); From a1d1c980bc041485f843f8899ab1504e4a315098 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 2 Oct 2013 16:29:45 +0530 Subject: [PATCH 40/41] [minor] fixes in stock balance report, bin uom and sle is_cancelled --- patches/october_2013/__init__.py | 0 patches/october_2013/fix_is_cancelled_in_sle.py | 13 +++++++++++++ patches/patch_list.py | 1 + public/js/stock_grid_report.js | 6 ++++-- stock/doctype/bin/bin.py | 2 +- .../stock_reconciliation/stock_reconciliation.py | 1 + stock/page/stock_balance/stock_balance.js | 7 ++++--- 7 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 patches/october_2013/__init__.py create mode 100644 patches/october_2013/fix_is_cancelled_in_sle.py diff --git a/patches/october_2013/__init__.py b/patches/october_2013/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/patches/october_2013/fix_is_cancelled_in_sle.py b/patches/october_2013/fix_is_cancelled_in_sle.py new file mode 100644 index 00000000000..050c1e68cd1 --- /dev/null +++ b/patches/october_2013/fix_is_cancelled_in_sle.py @@ -0,0 +1,13 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import webnotes + +def execute(): + webnotes.conn.sql("""update `tabStock Ledger Entry` set is_cancelled = 'No' + where ifnull(is_cancelled, '') = ''""") + + webnotes.conn.sql("""update tabBin b set b.stock_uom = + (select i.stock_uom from tabItem i where i.name = b.item_code) + where b.created_on>='2013-09-01'""") \ No newline at end of file diff --git a/patches/patch_list.py b/patches/patch_list.py index 6d1a084f68e..f228acf97e7 100644 --- a/patches/patch_list.py +++ b/patches/patch_list.py @@ -219,4 +219,5 @@ patch_list = [ "execute:webnotes.conn.set_value('Accounts Settings', None, 'frozen_accounts_modifier', 'Accounts Manager') # 2013-09-24", "patches.september_2013.p04_unsubmit_serial_nos", "patches.september_2013.p05_fix_customer_in_pos", + "patches.october_2013.fix_is_cancelled_in_sle", ] \ No newline at end of file diff --git a/public/js/stock_grid_report.js b/public/js/stock_grid_report.js index 8b79b5e1eea..46370d27f60 100644 --- a/public/js/stock_grid_report.js +++ b/public/js/stock_grid_report.js @@ -29,6 +29,8 @@ erpnext.StockGridReport = wn.views.TreeGridReport.extend({ if(add_qty) wh.fifo_stack.push([add_qty, sl.incoming_rate, sl.posting_date]); + + if(sl.serial_no) value_diff = this.get_serialized_value_diff(sl); } else { // outgoing if(sl.serial_no) { @@ -98,7 +100,7 @@ erpnext.StockGridReport = wn.views.TreeGridReport.extend({ $.each(sl.serial_no.trim().split("\n"), function(i, sr) { if(sr) { - value_diff += flt(me.serialized_buying_rates[sr.trim()]); + value_diff += flt(me.serialized_buying_rates[sr.trim().toLowerCase()]); } }); @@ -112,7 +114,7 @@ erpnext.StockGridReport = wn.views.TreeGridReport.extend({ if(sle.qty > 0 && sle.serial_no) { $.each(sle.serial_no.trim().split("\n"), function(i, sr) { if(sr && sle.incoming_rate !== undefined) { - serialized_buying_rates[sr.trim()] = flt(sle.incoming_rate); + serialized_buying_rates[sr.trim().toLowerCase()] = flt(sle.incoming_rate); } }); } diff --git a/stock/doctype/bin/bin.py b/stock/doctype/bin/bin.py index 788642fe4f9..c419cad43bb 100644 --- a/stock/doctype/bin/bin.py +++ b/stock/doctype/bin/bin.py @@ -16,7 +16,7 @@ class DocType: self.doclist = doclist def validate(self): - if not self.doc.stock_uom: + if self.doc.fields.get("__islocal") or not self.doc.stock_uom: self.doc.stock_uom = webnotes.conn.get_value('Item', self.doc.item_code, 'stock_uom') self.validate_mandatory() diff --git a/stock/doctype/stock_reconciliation/stock_reconciliation.py b/stock/doctype/stock_reconciliation/stock_reconciliation.py index 465edc490ad..9feb57e716b 100644 --- a/stock/doctype/stock_reconciliation/stock_reconciliation.py +++ b/stock/doctype/stock_reconciliation/stock_reconciliation.py @@ -246,6 +246,7 @@ class DocType(StockController): "stock_uom": webnotes.conn.get_value("Item", row.item_code, "stock_uom"), "voucher_detail_no": row.voucher_detail_no, "fiscal_year": self.doc.fiscal_year, + "is_cancelled": "No" }) args.update(opts) self.make_sl_entries([args]) diff --git a/stock/page/stock_balance/stock_balance.js b/stock/page/stock_balance/stock_balance.js index 1bc5d1c6bc0..b45a610be88 100644 --- a/stock/page/stock_balance/stock_balance.js +++ b/stock/page/stock_balance/stock_balance.js @@ -126,10 +126,11 @@ erpnext.StockBalance = erpnext.StockAnalytics.extend({ } else { item.inflow_value += value_diff; } - } - item.closing_qty += qty_diff; - item.closing_value += value_diff; + item.closing_qty += qty_diff; + item.closing_value += value_diff; + } + } else { break; } From efa94ce1bf092b7b4150aed1ca2ce1611fb7f203 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 2 Oct 2013 16:40:14 +0530 Subject: [PATCH 41/41] [fix] [minor] fixe in patch --- patches/october_2013/fix_is_cancelled_in_sle.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patches/october_2013/fix_is_cancelled_in_sle.py b/patches/october_2013/fix_is_cancelled_in_sle.py index 050c1e68cd1..cb51b5d7ca1 100644 --- a/patches/october_2013/fix_is_cancelled_in_sle.py +++ b/patches/october_2013/fix_is_cancelled_in_sle.py @@ -10,4 +10,4 @@ def execute(): webnotes.conn.sql("""update tabBin b set b.stock_uom = (select i.stock_uom from tabItem i where i.name = b.item_code) - where b.created_on>='2013-09-01'""") \ No newline at end of file + where b.creation>='2013-09-01'""") \ No newline at end of file