From 59de1e23bc5ccc1f4a068d7ec19066961592fd41 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 21 Jan 2015 17:50:09 +0530 Subject: [PATCH 1/5] POS fix: setting discount amount --- erpnext/accounts/doctype/sales_invoice/pos.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/sales_invoice/pos.js b/erpnext/accounts/doctype/sales_invoice/pos.js index e7cbcb761e..bee83fc000 100644 --- a/erpnext/accounts/doctype/sales_invoice/pos.js +++ b/erpnext/accounts/doctype/sales_invoice/pos.js @@ -114,7 +114,7 @@ erpnext.POS = Class.extend({ }); this.wrapper.find('input.discount-amount').on("change", function() { - frappe.model.set_value(me.frm.doctype, me.frm.docname, "discount_amount", this.value); + frappe.model.set_value(me.frm.doctype, me.frm.docname, "discount_amount", flt(this.value)); }); this.call_function("remove-items", function() {me.remove_selected_items();}); From 4ccd8d33267c0af9bb06731d52f151d6a520b77e Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 23 Jan 2015 12:18:01 +0530 Subject: [PATCH 2/5] Allow nagative batch balance from landed cost voucher --- .../stock/doctype/stock_ledger_entry/stock_ledger_entry.py | 7 +++---- erpnext/stock/stock_ledger.py | 5 +++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py index 6202e9451a..58a4412852 100644 --- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py @@ -32,16 +32,15 @@ class StockLedgerEntry(Document): #check for item quantity available in stock def actual_amt_check(self): - if self.batch_no: + if self.batch_no and not self.get("allow_negative_stock"): batch_bal_after_transaction = flt(frappe.db.sql("""select sum(actual_qty) from `tabStock Ledger Entry` where warehouse=%s and item_code=%s and batch_no=%s""", (self.warehouse, self.item_code, self.batch_no))[0][0]) if batch_bal_after_transaction < 0: - frappe.throw(_("Negative balance {0} in Batch {1} for Item {2} at Warehouse {3} on {4} {5}") - .format(batch_bal_after_transaction - self.actual_qty, self.batch_no, self.item_code, self.warehouse, - formatdate(self.posting_date), self.posting_time)) + frappe.throw(_("Stock balance in Batch {0} will become negative {1} for Item {2} at Warehouse {3}") + .format(self.batch_no, batch_bal_after_transaction, self.item_code, self.warehouse)) def validate_mandatory(self): mandatory = ['warehouse','posting_date','voucher_type','voucher_no','company'] diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index 7bbf8fc3c5..97a1f82157 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -28,7 +28,7 @@ def make_sl_entries(sl_entries, is_amended=None, allow_negative_stock=False): sle['actual_qty'] = -flt(sle['actual_qty']) if sle.get("actual_qty") or sle.get("voucher_type")=="Stock Reconciliation": - sle_id = make_entry(sle) + sle_id = make_entry(sle, allow_negative_stock) args = sle.copy() args.update({ @@ -46,10 +46,11 @@ def set_as_cancel(voucher_type, voucher_no): where voucher_no=%s and voucher_type=%s""", (now(), frappe.session.user, voucher_type, voucher_no)) -def make_entry(args): +def make_entry(args, allow_negative_stock=False): args.update({"doctype": "Stock Ledger Entry"}) sle = frappe.get_doc(args) sle.ignore_permissions = 1 + sle.allow_negative_stock=allow_negative_stock sle.insert() sle.submit() return sle.name From f0b0464cceba39c62e1bdc2017db8e9c777983c8 Mon Sep 17 00:00:00 2001 From: Neil Trini Lasrado Date: Thu, 22 Jan 2015 15:02:21 +0530 Subject: [PATCH 3/5] patch for is_batch_item --- erpnext/patches.txt | 1 + erpnext/patches/v4_2/set_item_batch.py | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 erpnext/patches/v4_2/set_item_batch.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 2773d69d78..8978a3b19b 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -92,3 +92,4 @@ execute:frappe.delete_doc("DocType", "Contact Control") erpnext.patches.v4_2.recalculate_bom_costs erpnext.patches.v4_2.discount_amount erpnext.patches.v4_2.update_landed_cost_voucher +erpnext.patches.v4_2.set_item_batch diff --git a/erpnext/patches/v4_2/set_item_batch.py b/erpnext/patches/v4_2/set_item_batch.py new file mode 100644 index 0000000000..990be6905f --- /dev/null +++ b/erpnext/patches/v4_2/set_item_batch.py @@ -0,0 +1,20 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + item_list = frappe.db.sql("""select name from tabItem""", as_dict=1) + for d in item_list: + count_stock_entries = frappe.db.sql("""select count(name) from `tabStock Entry Detail` where item_code= %s""",d.get("name"))[0][0] + + count_batch_entries = frappe.db.sql("""select count(name) from `tabStock Entry Detail` where \ + item_code= %s and batch_no = '' """,d.get("name"))[0][0] + + if count_stock_entries > 0: + if count_stock_entries == count_batch_entries: + frappe.db.sql("""update `tabItem` set has_batch_no = 'Yes' where name = %s""",d.get("name")) + + if count_batch_entries == 0: + frappe.db.sql("""update `tabItem` set has_batch_no = 'No' where name = %s""",d.get("name")) From 40a9f6f8e9ab0678dfe9a03c4aff378f623ec48b Mon Sep 17 00:00:00 2001 From: Neil Trini Lasrado Date: Fri, 23 Jan 2015 15:30:46 +0530 Subject: [PATCH 4/5] patch fix --- erpnext/patches/v4_2/set_item_batch.py | 65 ++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 10 deletions(-) diff --git a/erpnext/patches/v4_2/set_item_batch.py b/erpnext/patches/v4_2/set_item_batch.py index 990be6905f..3e84a59e00 100644 --- a/erpnext/patches/v4_2/set_item_batch.py +++ b/erpnext/patches/v4_2/set_item_batch.py @@ -5,16 +5,61 @@ from __future__ import unicode_literals import frappe def execute(): - item_list = frappe.db.sql("""select name from tabItem""", as_dict=1) - for d in item_list: - count_stock_entries = frappe.db.sql("""select count(name) from `tabStock Entry Detail` where item_code= %s""",d.get("name"))[0][0] + frappe.db.sql("update tabItem set has_batch_no = 'No' where ifnull(has_batch_no, '') = ''") + frappe.db.sql("update tabItem set has_serial_no = 'No' where ifnull(has_serial_no, '') = ''") + + item_list = frappe.db.sql("""select name, has_batch_no, has_serial_no from tabItem + where ifnull(is_stock_item, 'No') = 'Yes'""", as_dict=1) - count_batch_entries = frappe.db.sql("""select count(name) from `tabStock Entry Detail` where \ - item_code= %s and batch_no = '' """,d.get("name"))[0][0] + sle_count = get_sle_count() + sle_with_batch = get_sle_with_batch() + sle_with_serial = get_sle_with_serial() + + batch_items = get_items_with_batch() + serialized_items = get_items_with_serial() + + for d in item_list: + if d.has_batch_no == 'Yes': + if d.name not in batch_items and sle_count.get(d.name) and sle_count.get(d.name) != sle_with_batch.get(d.name): + frappe.db.set_value("Item", d.name, "has_batch_no", "No") + else: + if d.name in batch_items or (sle_count.get(d.name) and sle_count.get(d.name) == sle_with_batch.get(d.name)): + frappe.db.set_value("Item", d.name, "has_batch_no", "Yes") + + if d.has_serial_no == 'Yes': + if d.name not in serialized_items and sle_count.get(d.name) and sle_count.get(d.name) != sle_with_serial.get(d.name): + frappe.db.set_value("Item", d.name, "has_serial_no", "No") + else: + if d.name in serialized_items or (sle_count.get(d.name) and sle_count.get(d.name) == sle_with_serial.get(d.name)): + frappe.db.set_value("Item", d.name, "has_serial_no", "Yes") - if count_stock_entries > 0: - if count_stock_entries == count_batch_entries: - frappe.db.sql("""update `tabItem` set has_batch_no = 'Yes' where name = %s""",d.get("name")) - if count_batch_entries == 0: - frappe.db.sql("""update `tabItem` set has_batch_no = 'No' where name = %s""",d.get("name")) +def get_sle_count(): + sle_count = {} + for d in frappe.db.sql("""select item_code, count(name) as cnt from `tabStock Ledger Entry` group by item_code""", as_dict=1): + sle_count.setdefault(d.item_code, d.cnt) + + return sle_count + +def get_sle_with_batch(): + sle_with_batch = {} + for d in frappe.db.sql("""select item_code, count(name) as cnt from `tabStock Ledger Entry` + where batch_no != '' group by item_code""", as_dict=1): + sle_with_batch.setdefault(d.item_code, d.cnt) + + return sle_with_batch + + +def get_sle_with_serial(): + sle_with_serial = {} + for d in frappe.db.sql("""select item_code, count(name) as cnt from `tabStock Ledger Entry` + where serial_no != '' group by item_code""", as_dict=1): + sle_with_serial.setdefault(d.item_code, d.cnt) + + return sle_with_serial + +def get_items_with_batch(): + return frappe.db.sql_list("select item from tabBatch") + +def get_items_with_serial(): + return frappe.db.sql_list("select item_code from `tabSerial No`") \ No newline at end of file From e4c2ebfc5789291d19e32d2342f55a9f459ca126 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Fri, 23 Jan 2015 16:46:53 +0600 Subject: [PATCH 5/5] bumped to version 4.20.0 --- erpnext/__version__.py | 2 +- erpnext/hooks.py | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/__version__.py b/erpnext/__version__.py index 124e1ca293..75c77f13ac 100644 --- a/erpnext/__version__.py +++ b/erpnext/__version__.py @@ -1 +1 @@ -__version__ = '4.19.0' +__version__ = '4.20.0' diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 9ffa0ad41a..90ac2e7492 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -4,7 +4,7 @@ app_publisher = "Web Notes Technologies Pvt. Ltd. and Contributors" app_description = "Open Source Enterprise Resource Planning for Small and Midsized Organizations" app_icon = "icon-th" app_color = "#e74c3c" -app_version = "4.19.0" +app_version = "4.20.0" error_report_email = "support@erpnext.com" diff --git a/setup.py b/setup.py index 0d31ff0d01..f2c3988a9e 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ from setuptools import setup, find_packages import os -version = "4.19.0" +version = "4.20.0" with open("requirements.txt", "r") as f: install_requires = f.readlines()