From 24b26db3271a3c77c853c1f40b3b313b66e97182 Mon Sep 17 00:00:00 2001 From: Thura Hlaing Date: Mon, 27 Jan 2014 14:08:55 +0630 Subject: [PATCH 1/9] initial prototype implementation for issue #856 --- .../doctype/stock_settings/stock_settings.py | 17 +- .../doctype/stock_settings/stock_settings.txt | 182 +++++++++--------- 2 files changed, 105 insertions(+), 94 deletions(-) diff --git a/stock/doctype/stock_settings/stock_settings.py b/stock/doctype/stock_settings/stock_settings.py index 48e1ee1619..a98ed407e7 100644 --- a/stock/doctype/stock_settings/stock_settings.py +++ b/stock/doctype/stock_settings/stock_settings.py @@ -5,18 +5,23 @@ from __future__ import unicode_literals import webnotes - +from webnotes import _ class DocType: def __init__(self, d, dl): self.doc, self.doclist = d, dl - + def validate(self): - for key in ["item_naming_by", "item_group", "stock_uom", + for key in ["item_naming_by", "item_group", "stock_uom", "allow_negative_stock"]: webnotes.conn.set_default(key, self.doc.fields.get(key, "")) - + from setup.doctype.naming_series.naming_series import set_by_naming_series - set_by_naming_series("Item", "item_code", + set_by_naming_series("Item", "item_code", self.doc.get("item_naming_by")=="Naming Series", hide_name_field=True) - + + stock_frozen_limit = 356 + submitted_stock_frozen = self.doc.fields.get("stock_frozen_upto") + if submitted_stock_frozen > stock_frozen_limit: + self.doc.fields["stock_frozen_upto"] = stock_frozen_limit + webnotes.msgprint (_("Stocks cannot be freezed for days larger than %d.") %stock_frozen_limit) diff --git a/stock/doctype/stock_settings/stock_settings.txt b/stock/doctype/stock_settings/stock_settings.txt index 634ee3a60f..59710ffc7c 100644 --- a/stock/doctype/stock_settings/stock_settings.txt +++ b/stock/doctype/stock_settings/stock_settings.txt @@ -1,128 +1,134 @@ [ { - "creation": "2013-06-24 16:37:54", - "docstatus": 0, - "modified": "2013-11-02 19:41:56", - "modified_by": "Administrator", + "creation": "2013-06-24 16:37:54", + "docstatus": 0, + "modified": "2014-01-27 13:29:56", + "modified_by": "Administrator", "owner": "Administrator" - }, + }, { - "description": "Settings", - "doctype": "DocType", - "icon": "icon-cog", - "issingle": 1, - "module": "Stock", + "description": "Settings", + "doctype": "DocType", + "icon": "icon-cog", + "issingle": 1, + "module": "Stock", "name": "__common__" - }, + }, { - "doctype": "DocField", - "name": "__common__", - "parent": "Stock Settings", - "parentfield": "fields", - "parenttype": "DocType", + "doctype": "DocField", + "name": "__common__", + "parent": "Stock Settings", + "parentfield": "fields", + "parenttype": "DocType", "permlevel": 0 - }, + }, { - "create": 1, - "doctype": "DocPerm", - "name": "__common__", - "parent": "Stock Settings", - "parentfield": "permissions", - "parenttype": "DocType", - "permlevel": 0, - "read": 1, - "role": "Material Manager", + "create": 1, + "doctype": "DocPerm", + "name": "__common__", + "parent": "Stock Settings", + "parentfield": "permissions", + "parenttype": "DocType", + "permlevel": 0, + "read": 1, + "role": "Material Manager", "write": 1 - }, + }, { - "doctype": "DocType", + "doctype": "DocType", "name": "Stock Settings" - }, + }, { - "doctype": "DocField", - "fieldname": "item_naming_by", - "fieldtype": "Select", - "label": "Item Naming By", + "doctype": "DocField", + "fieldname": "item_naming_by", + "fieldtype": "Select", + "label": "Item Naming By", "options": "Item Code\nNaming Series" - }, + }, { - "description": "Add / Edit", - "doctype": "DocField", - "fieldname": "item_group", - "fieldtype": "Link", - "label": "Default Item Group", + "description": "Add / Edit", + "doctype": "DocField", + "fieldname": "item_group", + "fieldtype": "Link", + "label": "Default Item Group", "options": "Item Group" - }, + }, { - "doctype": "DocField", - "fieldname": "stock_uom", - "fieldtype": "Link", - "label": "Default Stock UOM", + "doctype": "DocField", + "fieldname": "stock_uom", + "fieldtype": "Link", + "label": "Default Stock UOM", "options": "UOM" - }, + }, { - "doctype": "DocField", - "fieldname": "column_break_4", + "doctype": "DocField", + "fieldname": "column_break_4", "fieldtype": "Column Break" - }, + }, { - "doctype": "DocField", - "fieldname": "allow_negative_stock", - "fieldtype": "Check", + "doctype": "DocField", + "fieldname": "allow_negative_stock", + "fieldtype": "Check", "label": "Allow Negative Stock" - }, + }, { - "doctype": "DocField", - "fieldname": "valuation_method", - "fieldtype": "Select", - "label": "Default Valuation Method", + "doctype": "DocField", + "fieldname": "valuation_method", + "fieldtype": "Select", + "label": "Default Valuation Method", "options": "FIFO\nMoving Average" - }, + }, { - "description": "Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.", - "doctype": "DocField", - "fieldname": "tolerance", - "fieldtype": "Float", + "description": "Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.", + "doctype": "DocField", + "fieldname": "tolerance", + "fieldtype": "Float", "label": "Allowance Percent" - }, + }, { - "doctype": "DocField", - "fieldname": "auto_material_request", - "fieldtype": "Section Break", + "doctype": "DocField", + "fieldname": "auto_material_request", + "fieldtype": "Section Break", "label": "Auto Material Request" - }, + }, { - "doctype": "DocField", - "fieldname": "auto_indent", - "fieldtype": "Check", + "doctype": "DocField", + "fieldname": "auto_indent", + "fieldtype": "Check", "label": "Raise Material Request when stock reaches re-order level" - }, + }, { - "doctype": "DocField", - "fieldname": "reorder_email_notify", - "fieldtype": "Check", + "doctype": "DocField", + "fieldname": "reorder_email_notify", + "fieldtype": "Check", "label": "Notify by Email on creation of automatic Material Request" - }, + }, { - "doctype": "DocField", - "fieldname": "freeze_stock_entries", - "fieldtype": "Section Break", + "doctype": "DocField", + "fieldname": "freeze_stock_entries", + "fieldtype": "Section Break", "label": "Freeze Stock Entries" - }, + }, { - "doctype": "DocField", - "fieldname": "stock_frozen_upto", - "fieldtype": "Date", + "doctype": "DocField", + "fieldname": "stock_frozen_upto", + "fieldtype": "Date", "label": "Stock Frozen Upto" - }, + }, { - "doctype": "DocField", - "fieldname": "stock_auth_role", - "fieldtype": "Link", - "label": "Role Allowed to edit frozen stock", + "doctype": "DocField", + "fieldname": "stock_frozen_upto", + "fieldtype": "Int", + "label": "Stock Frozen Upto" + }, + { + "doctype": "DocField", + "fieldname": "stock_auth_role", + "fieldtype": "Link", + "label": "Role Allowed to edit frozen stock", "options": "Role" - }, + }, { "doctype": "DocPerm" } -] \ No newline at end of file +] From 9d5566634c100de645a5cab28a17072ad4bb1c06 Mon Sep 17 00:00:00 2001 From: Thura Hlaing Date: Mon, 27 Jan 2014 16:54:02 +0630 Subject: [PATCH 2/9] changed stock_frozen_upto to stock_frozen_upto_days, and added validation for it in stock ledger --- .../stock_ledger_entry/stock_ledger_entry.py | 49 ++++++++++++------- .../doctype/stock_settings/stock_settings.py | 4 +- .../doctype/stock_settings/stock_settings.txt | 6 +-- 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py index f059451099..4828ca42bb 100644 --- a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +++ b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py @@ -1,3 +1,4 @@ + # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt @@ -6,6 +7,7 @@ import webnotes from webnotes import msgprint from webnotes.utils import flt, getdate from webnotes.model.controller import DocListController +from datetime import timedelta, date class DocType(DocListController): def __init__(self, doc, doclist=[]): @@ -19,30 +21,30 @@ class DocType(DocListController): validate_warehouse_user(self.doc.warehouse) validate_warehouse_company(self.doc.warehouse, self.doc.company) self.scrub_posting_time() - + from accounts.utils import validate_fiscal_year validate_fiscal_year(self.doc.posting_date, self.doc.fiscal_year, self.meta.get_label("posting_date")) - + def on_submit(self): self.check_stock_frozen_date() self.actual_amt_check() - + from stock.doctype.serial_no.serial_no import process_serial_no process_serial_no(self.doc) - + #check for item quantity available in stock def actual_amt_check(self): if self.doc.batch_no: - batch_bal_after_transaction = flt(webnotes.conn.sql("""select sum(actual_qty) - from `tabStock Ledger Entry` - where warehouse=%s and item_code=%s and batch_no=%s""", + batch_bal_after_transaction = flt(webnotes.conn.sql("""select sum(actual_qty) + from `tabStock Ledger Entry` + where warehouse=%s and item_code=%s and batch_no=%s""", (self.doc.warehouse, self.doc.item_code, self.doc.batch_no))[0][0]) - + if batch_bal_after_transaction < 0: self.doc.fields.update({ 'batch_bal': batch_bal_after_transaction - self.doc.actual_qty }) - + webnotes.throw("""Not enough quantity (requested: %(actual_qty)s, \ current: %(batch_bal)s in Batch %(batch_no)s for Item \ %(item_code)s at Warehouse %(warehouse)s \ @@ -60,27 +62,27 @@ class DocType(DocListController): msgprint("Warehouse: '%s' does not exist in the system. Please check." % self.doc.fields.get(k), raise_exception = 1) def validate_item(self): - item_det = webnotes.conn.sql("""select name, has_batch_no, docstatus, - is_stock_item, has_serial_no, serial_no_series - from tabItem where name=%s""", + item_det = webnotes.conn.sql("""select name, has_batch_no, docstatus, + is_stock_item, has_serial_no, serial_no_series + from tabItem where name=%s""", self.doc.item_code, as_dict=True)[0] if item_det.is_stock_item != 'Yes': webnotes.throw("""Item: "%s" is not a Stock Item.""" % self.doc.item_code) - + # check if batch number is required if item_det.has_batch_no =='Yes' and self.doc.voucher_type != 'Stock Reconciliation': if not self.doc.batch_no: webnotes.throw("Batch number is mandatory for Item '%s'" % self.doc.item_code) - + # check if batch belongs to item - if not webnotes.conn.sql("""select name from `tabBatch` + if not webnotes.conn.sql("""select name from `tabBatch` where item='%s' and name ='%s' and docstatus != 2""" % (self.doc.item_code, self.doc.batch_no)): webnotes.throw("'%s' is not a valid Batch Number for Item '%s'" % (self.doc.batch_no, self.doc.item_code)) - + if not self.doc.stock_uom: self.doc.stock_uom = item_det.stock_uom - + def check_stock_frozen_date(self): stock_frozen_upto = webnotes.conn.get_value('Stock Settings', None, 'stock_frozen_upto') or '' if stock_frozen_upto: @@ -88,13 +90,22 @@ class DocType(DocListController): if getdate(self.doc.posting_date) <= getdate(stock_frozen_upto) and not stock_auth_role in webnotes.user.get_roles(): msgprint("You are not authorized to do / modify back dated stock entries before %s" % getdate(stock_frozen_upto).strftime('%d-%m-%Y'), raise_exception=1) + stock_frozen_upto_days = webnotes.conn.get_value('Stock Settings', None, 'stock_frozen_upto_days') or 0 + if stock_frozen_upto_days: + stock_auth_role = webnotes.conn.get_value('Stock Settings', None,'stock_auth_role') + posting_date = getdate(self.doc.posting_date) + frozen_days = timedelta(days=stock_frozen_upto_days) + if posting_date + frozen_days <= date.today() and not stock_auth_role in webnotes.user.get_roles(): + msgprint("You are not authorized to do / modify back dated stock entries %d ago" %stock_frozen_upto_days, raise_exception=1) + + def scrub_posting_time(self): if not self.doc.posting_time or self.doc.posting_time == '00:0': self.doc.posting_time = '00:00' def on_doctype_update(): - if not webnotes.conn.sql("""show index from `tabStock Ledger Entry` + if not webnotes.conn.sql("""show index from `tabStock Ledger Entry` where Key_name="posting_sort_index" """): webnotes.conn.commit() - webnotes.conn.sql("""alter table `tabStock Ledger Entry` + webnotes.conn.sql("""alter table `tabStock Ledger Entry` add index posting_sort_index(posting_date, posting_time, name)""") \ No newline at end of file diff --git a/stock/doctype/stock_settings/stock_settings.py b/stock/doctype/stock_settings/stock_settings.py index a98ed407e7..a061aaa493 100644 --- a/stock/doctype/stock_settings/stock_settings.py +++ b/stock/doctype/stock_settings/stock_settings.py @@ -21,7 +21,7 @@ class DocType: self.doc.get("item_naming_by")=="Naming Series", hide_name_field=True) stock_frozen_limit = 356 - submitted_stock_frozen = self.doc.fields.get("stock_frozen_upto") + submitted_stock_frozen = self.doc.fields.get("stock_frozen_upto_days") if submitted_stock_frozen > stock_frozen_limit: - self.doc.fields["stock_frozen_upto"] = stock_frozen_limit + self.doc.fields["stock_frozen_upto_days"] = stock_frozen_limit webnotes.msgprint (_("Stocks cannot be freezed for days larger than %d.") %stock_frozen_limit) diff --git a/stock/doctype/stock_settings/stock_settings.txt b/stock/doctype/stock_settings/stock_settings.txt index 59710ffc7c..ca1229619b 100644 --- a/stock/doctype/stock_settings/stock_settings.txt +++ b/stock/doctype/stock_settings/stock_settings.txt @@ -2,7 +2,7 @@ { "creation": "2013-06-24 16:37:54", "docstatus": 0, - "modified": "2014-01-27 13:29:56", + "modified": "2014-01-27 17:29:56", "modified_by": "Administrator", "owner": "Administrator" }, @@ -117,9 +117,9 @@ }, { "doctype": "DocField", - "fieldname": "stock_frozen_upto", + "fieldname": "stock_frozen_upto_days", "fieldtype": "Int", - "label": "Stock Frozen Upto" + "label": "Stock Frozen Upto [Days Ago]" }, { "doctype": "DocField", From e31a41854b175fa47eedc257d80d5d784a8cb39a Mon Sep 17 00:00:00 2001 From: Thura Hlaing Date: Mon, 27 Jan 2014 20:14:53 +0630 Subject: [PATCH 3/9] tabify modifications, minor coding style/message updates --- .../stock_ledger_entry/stock_ledger_entry.py | 13 ++++++------- stock/doctype/stock_settings/stock_settings.py | 10 +++++----- stock/doctype/stock_settings/stock_settings.txt | 4 ++-- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py index 4828ca42bb..d9a8c8c06f 100644 --- a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +++ b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py @@ -90,13 +90,12 @@ class DocType(DocListController): if getdate(self.doc.posting_date) <= getdate(stock_frozen_upto) and not stock_auth_role in webnotes.user.get_roles(): msgprint("You are not authorized to do / modify back dated stock entries before %s" % getdate(stock_frozen_upto).strftime('%d-%m-%Y'), raise_exception=1) - stock_frozen_upto_days = webnotes.conn.get_value('Stock Settings', None, 'stock_frozen_upto_days') or 0 - if stock_frozen_upto_days: - stock_auth_role = webnotes.conn.get_value('Stock Settings', None,'stock_auth_role') - posting_date = getdate(self.doc.posting_date) - frozen_days = timedelta(days=stock_frozen_upto_days) - if posting_date + frozen_days <= date.today() and not stock_auth_role in webnotes.user.get_roles(): - msgprint("You are not authorized to do / modify back dated stock entries %d ago" %stock_frozen_upto_days, raise_exception=1) + stock_frozen_upto_days = webnotes.conn.get_value('Stock Settings', None, 'stock_frozen_upto_days') or 0 + if stock_frozen_upto_days: + stock_auth_role = webnotes.conn.get_value('Stock Settings', None,'stock_auth_role') + older_than_x_days_ago = (add_date(getdate(self.doc.posting_date), stock_frozen_upto_days) <= date.today()) + if older_than_x_days_ago and not stock_auth_role in webnotes.user.get_roles(): + msgprint("You are not authorized to do / modify back dated stock entries older than %d days ago" %stock_frozen_upto_days, raise_exception=1) def scrub_posting_time(self): diff --git a/stock/doctype/stock_settings/stock_settings.py b/stock/doctype/stock_settings/stock_settings.py index a061aaa493..8592503147 100644 --- a/stock/doctype/stock_settings/stock_settings.py +++ b/stock/doctype/stock_settings/stock_settings.py @@ -20,8 +20,8 @@ class DocType: set_by_naming_series("Item", "item_code", self.doc.get("item_naming_by")=="Naming Series", hide_name_field=True) - stock_frozen_limit = 356 - submitted_stock_frozen = self.doc.fields.get("stock_frozen_upto_days") - if submitted_stock_frozen > stock_frozen_limit: - self.doc.fields["stock_frozen_upto_days"] = stock_frozen_limit - webnotes.msgprint (_("Stocks cannot be freezed for days larger than %d.") %stock_frozen_limit) + stock_frozen_limit = 356 + submitted_stock_frozen = self.doc.stock_frozen_upto_days + if submitted_stock_frozen > stock_frozen_limit: + self.doc.stock_frozen_upto_days = stock_frozen_limit + webnotes.msgprint (_("`Stocks Freeze Older Than` should be smaller than %d days.") %stock_frozen_limit) diff --git a/stock/doctype/stock_settings/stock_settings.txt b/stock/doctype/stock_settings/stock_settings.txt index ca1229619b..a179091616 100644 --- a/stock/doctype/stock_settings/stock_settings.txt +++ b/stock/doctype/stock_settings/stock_settings.txt @@ -2,7 +2,7 @@ { "creation": "2013-06-24 16:37:54", "docstatus": 0, - "modified": "2014-01-27 17:29:56", + "modified": "2014-01-27 20:00:56", "modified_by": "Administrator", "owner": "Administrator" }, @@ -119,7 +119,7 @@ "doctype": "DocField", "fieldname": "stock_frozen_upto_days", "fieldtype": "Int", - "label": "Stock Frozen Upto [Days Ago]" + "label": "Freeze Stocks Older Than [Days]" }, { "doctype": "DocField", From 16f88ba3cd560881e2871d237d570a66aaa6cf38 Mon Sep 17 00:00:00 2001 From: Thura Hlaing Date: Mon, 27 Jan 2014 20:22:08 +0630 Subject: [PATCH 4/9] import add_date, removed timedelta import --- stock/doctype/stock_ledger_entry/stock_ledger_entry.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py index d9a8c8c06f..13aaee6b4b 100644 --- a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +++ b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py @@ -5,9 +5,9 @@ from __future__ import unicode_literals import webnotes from webnotes import msgprint -from webnotes.utils import flt, getdate +from webnotes.utils import flt, getdate, add_date from webnotes.model.controller import DocListController -from datetime import timedelta, date +from datetime import date class DocType(DocListController): def __init__(self, doc, doclist=[]): From 2e67426936c63ef8eaa4256eadcf0c21f1fdac9e Mon Sep 17 00:00:00 2001 From: Thura Hlaing Date: Tue, 28 Jan 2014 09:09:50 +0630 Subject: [PATCH 5/9] label/message update in error reporting --- stock/doctype/stock_settings/stock_settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stock/doctype/stock_settings/stock_settings.py b/stock/doctype/stock_settings/stock_settings.py index 8592503147..87e940d1d5 100644 --- a/stock/doctype/stock_settings/stock_settings.py +++ b/stock/doctype/stock_settings/stock_settings.py @@ -24,4 +24,4 @@ class DocType: submitted_stock_frozen = self.doc.stock_frozen_upto_days if submitted_stock_frozen > stock_frozen_limit: self.doc.stock_frozen_upto_days = stock_frozen_limit - webnotes.msgprint (_("`Stocks Freeze Older Than` should be smaller than %d days.") %stock_frozen_limit) + webnotes.msgprint (_("`Freeze Stocks Older Than` should be smaller than %d days.") %stock_frozen_limit) From d66396abe347be0020f24904b50f9615ef819719 Mon Sep 17 00:00:00 2001 From: Thura Hlaing Date: Wed, 29 Jan 2014 09:49:30 +0630 Subject: [PATCH 6/9] fixed typo add_date -> add_days --- stock/doctype/stock_ledger_entry/stock_ledger_entry.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py index 13aaee6b4b..d5d4b88a6b 100644 --- a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +++ b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals import webnotes from webnotes import msgprint -from webnotes.utils import flt, getdate, add_date +from webnotes.utils import flt, getdate, add_days from webnotes.model.controller import DocListController from datetime import date @@ -93,7 +93,7 @@ class DocType(DocListController): stock_frozen_upto_days = webnotes.conn.get_value('Stock Settings', None, 'stock_frozen_upto_days') or 0 if stock_frozen_upto_days: stock_auth_role = webnotes.conn.get_value('Stock Settings', None,'stock_auth_role') - older_than_x_days_ago = (add_date(getdate(self.doc.posting_date), stock_frozen_upto_days) <= date.today()) + older_than_x_days_ago = (add_days(getdate(self.doc.posting_date), stock_frozen_upto_days) <= date.today()) if older_than_x_days_ago and not stock_auth_role in webnotes.user.get_roles(): msgprint("You are not authorized to do / modify back dated stock entries older than %d days ago" %stock_frozen_upto_days, raise_exception=1) From 258191ab40ffbfa99c17b938ac7c854cf3c0066d Mon Sep 17 00:00:00 2001 From: Thura Hlaing Date: Wed, 29 Jan 2014 11:37:30 +0630 Subject: [PATCH 7/9] fix bug by coercing `stock_frozen_upto_days` value to int --- stock/doctype/stock_ledger_entry/stock_ledger_entry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py index d5d4b88a6b..38d5b26605 100644 --- a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +++ b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py @@ -90,7 +90,7 @@ class DocType(DocListController): if getdate(self.doc.posting_date) <= getdate(stock_frozen_upto) and not stock_auth_role in webnotes.user.get_roles(): msgprint("You are not authorized to do / modify back dated stock entries before %s" % getdate(stock_frozen_upto).strftime('%d-%m-%Y'), raise_exception=1) - stock_frozen_upto_days = webnotes.conn.get_value('Stock Settings', None, 'stock_frozen_upto_days') or 0 + stock_frozen_upto_days = int(webnotes.conn.get_value('Stock Settings', None, 'stock_frozen_upto_days') or 0) if stock_frozen_upto_days: stock_auth_role = webnotes.conn.get_value('Stock Settings', None,'stock_auth_role') older_than_x_days_ago = (add_days(getdate(self.doc.posting_date), stock_frozen_upto_days) <= date.today()) From 3c4bb0c7c96f6ff827508c053f4c65d410e91646 Mon Sep 17 00:00:00 2001 From: Thura Hlaing Date: Wed, 29 Jan 2014 13:28:11 +0630 Subject: [PATCH 8/9] initial tests for freeze stock functionality --- stock/doctype/stock_entry/test_stock_entry.py | 502 +++++++++--------- .../stock_ledger_entry/stock_ledger_entry.py | 4 +- 2 files changed, 261 insertions(+), 245 deletions(-) diff --git a/stock/doctype/stock_entry/test_stock_entry.py b/stock/doctype/stock_entry/test_stock_entry.py index d6f34f645a..78ca0198db 100644 --- a/stock/doctype/stock_entry/test_stock_entry.py +++ b/stock/doctype/stock_entry/test_stock_entry.py @@ -18,7 +18,7 @@ class TestStockEntry(unittest.TestCase): webnotes.conn.sql("""delete from `tabMaterial Request Item`""") webnotes.conn.sql("""delete from `tabMaterial Request`""") self._clear_stock_account_balance() - + webnotes.conn.set_value("Stock Settings", None, "auto_indent", True) st1 = webnotes.bean(copy=test_records[0]) @@ -28,15 +28,15 @@ class TestStockEntry(unittest.TestCase): st2 = webnotes.bean(copy=test_records[1]) st2.insert() st2.submit() - + from stock.utils import reorder_item reorder_item() - + mr_name = webnotes.conn.sql("""select parent from `tabMaterial Request Item` where item_code='_Test Item'""") - + self.assertTrue(mr_name) - + webnotes.conn.set_default("company", self.old_default_company) def test_warehouse_company_validation(self): @@ -51,7 +51,7 @@ class TestStockEntry(unittest.TestCase): st1.doclist[1].t_warehouse="_Test Warehouse 2 - _TC1" st1.insert() self.assertRaises(InvalidWarehouseCompany, st1.submit) - + webnotes.session.user = "Administrator" def test_warehouse_user(self): @@ -76,111 +76,111 @@ class TestStockEntry(unittest.TestCase): st1.doclist[1].t_warehouse="_Test Warehouse 2 - _TC1" st1.insert() st1.submit() - + webnotes.session.user = "Administrator" def test_material_receipt_gl_entry(self): self._clear_stock_account_balance() set_perpetual_inventory() - + mr = webnotes.bean(copy=test_records[0]) mr.insert() mr.submit() - - stock_in_hand_account = webnotes.conn.get_value("Account", {"account_type": "Warehouse", + + stock_in_hand_account = webnotes.conn.get_value("Account", {"account_type": "Warehouse", "master_name": mr.doclist[1].t_warehouse}) - - self.check_stock_ledger_entries("Stock Entry", mr.doc.name, + + self.check_stock_ledger_entries("Stock Entry", mr.doc.name, [["_Test Item", "_Test Warehouse - _TC", 50.0]]) - - self.check_gl_entries("Stock Entry", mr.doc.name, + + self.check_gl_entries("Stock Entry", mr.doc.name, sorted([ - [stock_in_hand_account, 5000.0, 0.0], + [stock_in_hand_account, 5000.0, 0.0], ["Stock Adjustment - _TC", 0.0, 5000.0] ]) ) - + mr.cancel() - - self.assertFalse(webnotes.conn.sql("""select * from `tabStock Ledger Entry` - where voucher_type='Stock Entry' and voucher_no=%s""", mr.doc.name)) - - self.assertFalse(webnotes.conn.sql("""select * from `tabGL Entry` + + self.assertFalse(webnotes.conn.sql("""select * from `tabStock Ledger Entry` where voucher_type='Stock Entry' and voucher_no=%s""", mr.doc.name)) - + + self.assertFalse(webnotes.conn.sql("""select * from `tabGL Entry` + where voucher_type='Stock Entry' and voucher_no=%s""", mr.doc.name)) + def test_material_issue_gl_entry(self): self._clear_stock_account_balance() set_perpetual_inventory() - + self._insert_material_receipt() - + mi = webnotes.bean(copy=test_records[1]) mi.insert() mi.submit() - - self.check_stock_ledger_entries("Stock Entry", mi.doc.name, + + self.check_stock_ledger_entries("Stock Entry", mi.doc.name, [["_Test Item", "_Test Warehouse - _TC", -40.0]]) - - stock_in_hand_account = webnotes.conn.get_value("Account", {"account_type": "Warehouse", + + stock_in_hand_account = webnotes.conn.get_value("Account", {"account_type": "Warehouse", "master_name": mi.doclist[1].s_warehouse}) - self.check_gl_entries("Stock Entry", mi.doc.name, + self.check_gl_entries("Stock Entry", mi.doc.name, sorted([ - [stock_in_hand_account, 0.0, 4000.0], + [stock_in_hand_account, 0.0, 4000.0], ["Stock Adjustment - _TC", 4000.0, 0.0] ]) ) - + mi.cancel() - self.assertFalse(webnotes.conn.sql("""select * from `tabStock Ledger Entry` - where voucher_type='Stock Entry' and voucher_no=%s""", mi.doc.name)) - - self.assertFalse(webnotes.conn.sql("""select * from `tabGL Entry` + self.assertFalse(webnotes.conn.sql("""select * from `tabStock Ledger Entry` where voucher_type='Stock Entry' and voucher_no=%s""", mi.doc.name)) - - self.assertEquals(webnotes.conn.get_value("Bin", {"warehouse": mi.doclist[1].s_warehouse, + + self.assertFalse(webnotes.conn.sql("""select * from `tabGL Entry` + where voucher_type='Stock Entry' and voucher_no=%s""", mi.doc.name)) + + self.assertEquals(webnotes.conn.get_value("Bin", {"warehouse": mi.doclist[1].s_warehouse, "item_code": mi.doclist[1].item_code}, "actual_qty"), 50) - - self.assertEquals(webnotes.conn.get_value("Bin", {"warehouse": mi.doclist[1].s_warehouse, + + self.assertEquals(webnotes.conn.get_value("Bin", {"warehouse": mi.doclist[1].s_warehouse, "item_code": mi.doclist[1].item_code}, "stock_value"), 5000) - + def test_material_transfer_gl_entry(self): self._clear_stock_account_balance() set_perpetual_inventory() self._insert_material_receipt() - + mtn = webnotes.bean(copy=test_records[2]) mtn.insert() mtn.submit() - self.check_stock_ledger_entries("Stock Entry", mtn.doc.name, + self.check_stock_ledger_entries("Stock Entry", mtn.doc.name, [["_Test Item", "_Test Warehouse - _TC", -45.0], ["_Test Item", "_Test Warehouse 1 - _TC", 45.0]]) - stock_in_hand_account = webnotes.conn.get_value("Account", {"account_type": "Warehouse", + stock_in_hand_account = webnotes.conn.get_value("Account", {"account_type": "Warehouse", "master_name": mtn.doclist[1].s_warehouse}) - fixed_asset_account = webnotes.conn.get_value("Account", {"account_type": "Warehouse", + fixed_asset_account = webnotes.conn.get_value("Account", {"account_type": "Warehouse", "master_name": mtn.doclist[1].t_warehouse}) - - self.check_gl_entries("Stock Entry", mtn.doc.name, + + self.check_gl_entries("Stock Entry", mtn.doc.name, sorted([ - [stock_in_hand_account, 0.0, 4500.0], + [stock_in_hand_account, 0.0, 4500.0], [fixed_asset_account, 4500.0, 0.0], ]) ) - + mtn.cancel() - self.assertFalse(webnotes.conn.sql("""select * from `tabStock Ledger Entry` - where voucher_type='Stock Entry' and voucher_no=%s""", mtn.doc.name)) - - self.assertFalse(webnotes.conn.sql("""select * from `tabGL Entry` + self.assertFalse(webnotes.conn.sql("""select * from `tabStock Ledger Entry` where voucher_type='Stock Entry' and voucher_no=%s""", mtn.doc.name)) - - + + self.assertFalse(webnotes.conn.sql("""select * from `tabGL Entry` + where voucher_type='Stock Entry' and voucher_no=%s""", mtn.doc.name)) + + def test_repack_no_change_in_valuation(self): self._clear_stock_account_balance() set_perpetual_inventory() @@ -190,47 +190,47 @@ class TestStockEntry(unittest.TestCase): repack = webnotes.bean(copy=test_records[3]) repack.insert() repack.submit() - - self.check_stock_ledger_entries("Stock Entry", repack.doc.name, - [["_Test Item", "_Test Warehouse - _TC", -50.0], + + self.check_stock_ledger_entries("Stock Entry", repack.doc.name, + [["_Test Item", "_Test Warehouse - _TC", -50.0], ["_Test Item Home Desktop 100", "_Test Warehouse - _TC", 1]]) - + gl_entries = webnotes.conn.sql("""select account, debit, credit from `tabGL Entry` where voucher_type='Stock Entry' and voucher_no=%s order by account desc""", repack.doc.name, as_dict=1) self.assertFalse(gl_entries) - + set_perpetual_inventory(0) - + def test_repack_with_change_in_valuation(self): self._clear_stock_account_balance() set_perpetual_inventory() self._insert_material_receipt() - + repack = webnotes.bean(copy=test_records[3]) repack.doclist[2].incoming_rate = 6000 repack.insert() repack.submit() - - stock_in_hand_account = webnotes.conn.get_value("Account", {"account_type": "Warehouse", + + stock_in_hand_account = webnotes.conn.get_value("Account", {"account_type": "Warehouse", "master_name": repack.doclist[2].t_warehouse}) - - self.check_gl_entries("Stock Entry", repack.doc.name, + + self.check_gl_entries("Stock Entry", repack.doc.name, sorted([ - [stock_in_hand_account, 1000.0, 0.0], + [stock_in_hand_account, 1000.0, 0.0], ["Stock Adjustment - _TC", 0.0, 1000.0], ]) ) set_perpetual_inventory(0) - + def check_stock_ledger_entries(self, voucher_type, voucher_no, expected_sle): expected_sle.sort(key=lambda x: x[0]) - + # check stock ledger entries - sle = webnotes.conn.sql("""select item_code, warehouse, actual_qty - from `tabStock Ledger Entry` where voucher_type = %s - and voucher_no = %s order by item_code, warehouse, actual_qty""", + sle = webnotes.conn.sql("""select item_code, warehouse, actual_qty + from `tabStock Ledger Entry` where voucher_type = %s + and voucher_no = %s order by item_code, warehouse, actual_qty""", (voucher_type, voucher_no), as_list=1) self.assertTrue(sle) sle.sort(key=lambda x: x[0]) @@ -239,61 +239,61 @@ class TestStockEntry(unittest.TestCase): self.assertEquals(expected_sle[i][0], sle[0]) self.assertEquals(expected_sle[i][1], sle[1]) self.assertEquals(expected_sle[i][2], sle[2]) - + def check_gl_entries(self, voucher_type, voucher_no, expected_gl_entries): expected_gl_entries.sort(key=lambda x: x[0]) - + gl_entries = webnotes.conn.sql("""select account, debit, credit - from `tabGL Entry` where voucher_type=%s and voucher_no=%s + from `tabGL Entry` where voucher_type=%s and voucher_no=%s order by account asc, debit asc""", (voucher_type, voucher_no), as_list=1) self.assertTrue(gl_entries) gl_entries.sort(key=lambda x: x[0]) - + for i, gle in enumerate(gl_entries): self.assertEquals(expected_gl_entries[i][0], gle[0]) self.assertEquals(expected_gl_entries[i][1], gle[1]) self.assertEquals(expected_gl_entries[i][2], gle[2]) - + def _insert_material_receipt(self): self._clear_stock_account_balance() se1 = webnotes.bean(copy=test_records[0]) se1.insert() se1.submit() - + se2 = webnotes.bean(copy=test_records[0]) se2.doclist[1].item_code = "_Test Item Home Desktop 100" se2.insert() se2.submit() - + webnotes.conn.set_default("company", self.old_default_company) - + def _get_actual_qty(self): - return flt(webnotes.conn.get_value("Bin", {"item_code": "_Test Item", + return flt(webnotes.conn.get_value("Bin", {"item_code": "_Test Item", "warehouse": "_Test Warehouse - _TC"}, "actual_qty")) - + def _test_sales_invoice_return(self, item_code, delivered_qty, returned_qty): from stock.doctype.stock_entry.stock_entry import NotUpdateStockError - + from accounts.doctype.sales_invoice.test_sales_invoice \ import test_records as sales_invoice_test_records - + # invalid sales invoice as update stock not checked si = webnotes.bean(copy=sales_invoice_test_records[1]) si.insert() si.submit() - + se = webnotes.bean(copy=test_records[0]) se.doc.purpose = "Sales Return" se.doc.sales_invoice_no = si.doc.name se.doclist[1].qty = returned_qty se.doclist[1].transfer_qty = returned_qty self.assertRaises(NotUpdateStockError, se.insert) - + self._insert_material_receipt() - + # check currency available qty in bin actual_qty_0 = self._get_actual_qty() - + # insert a pos invoice with update stock si = webnotes.bean(copy=sales_invoice_test_records[1]) si.doc.is_pos = si.doc.update_stock = 1 @@ -302,12 +302,12 @@ class TestStockEntry(unittest.TestCase): si.doclist[1].qty = 5.0 si.insert() si.submit() - + # check available bin qty after invoice submission actual_qty_1 = self._get_actual_qty() - + self.assertEquals(actual_qty_0 - delivered_qty, actual_qty_1) - + # check if item is validated se = webnotes.bean(copy=test_records[0]) se.doc.purpose = "Sales Return" @@ -317,10 +317,10 @@ class TestStockEntry(unittest.TestCase): se.doclist[1].item_code = "_Test Item Home Desktop 200" se.doclist[1].qty = returned_qty se.doclist[1].transfer_qty = returned_qty - + # check if stock entry gets submitted self.assertRaises(webnotes.DoesNotExistError, se.insert) - + # try again se = webnotes.bean(copy=test_records[0]) se.doc.purpose = "Sales Return" @@ -331,45 +331,45 @@ class TestStockEntry(unittest.TestCase): se.doclist[1].transfer_qty = returned_qty # in both cases item code remains _Test Item when returning se.insert() - + se.submit() - + # check if available qty is increased actual_qty_2 = self._get_actual_qty() - + self.assertEquals(actual_qty_1 + returned_qty, actual_qty_2) - + return se - + def test_sales_invoice_return_of_non_packing_item(self): self._clear_stock_account_balance() self._test_sales_invoice_return("_Test Item", 5, 2) - + def test_sales_invoice_return_of_packing_item(self): self._clear_stock_account_balance() self._test_sales_invoice_return("_Test Sales BOM Item", 25, 20) - + def _test_delivery_note_return(self, item_code, delivered_qty, returned_qty): self._insert_material_receipt() - + from stock.doctype.delivery_note.test_delivery_note \ import test_records as delivery_note_test_records from stock.doctype.delivery_note.delivery_note import make_sales_invoice - + actual_qty_0 = self._get_actual_qty() # make a delivery note based on this invoice dn = webnotes.bean(copy=delivery_note_test_records[0]) dn.doclist[1].item_code = item_code dn.insert() dn.submit() - + actual_qty_1 = self._get_actual_qty() - + self.assertEquals(actual_qty_0 - delivered_qty, actual_qty_1) - + si_doclist = make_sales_invoice(dn.doc.name) - + si = webnotes.bean(si_doclist) si.doc.posting_date = dn.doc.posting_date si.doc.debit_to = "_Test Customer - _TC" @@ -378,7 +378,7 @@ class TestStockEntry(unittest.TestCase): d.cost_center = "_Test Cost Center - _TC" si.insert() si.submit() - + # insert and submit stock entry for sales return se = webnotes.bean(copy=test_records[0]) se.doc.purpose = "Sales Return" @@ -386,60 +386,60 @@ class TestStockEntry(unittest.TestCase): se.doc.posting_date = "2013-03-10" se.doc.fiscal_year = "_Test Fiscal Year 2013" se.doclist[1].qty = se.doclist[1].transfer_qty = returned_qty - + se.insert() se.submit() - + actual_qty_2 = self._get_actual_qty() self.assertEquals(actual_qty_1 + returned_qty, actual_qty_2) - + return se - + def test_delivery_note_return_of_non_packing_item(self): self._clear_stock_account_balance() self._test_delivery_note_return("_Test Item", 5, 2) - + def test_delivery_note_return_of_packing_item(self): self._clear_stock_account_balance() self._test_delivery_note_return("_Test Sales BOM Item", 25, 20) - + def _test_sales_return_jv(self, se): from stock.doctype.stock_entry.stock_entry import make_return_jv jv_list = make_return_jv(se.doc.name) - + self.assertEqual(len(jv_list), 3) self.assertEqual(jv_list[0].get("voucher_type"), "Credit Note") self.assertEqual(jv_list[0].get("posting_date"), se.doc.posting_date) self.assertEqual(jv_list[1].get("account"), "_Test Customer - _TC") self.assertEqual(jv_list[2].get("account"), "Sales - _TC") self.assertTrue(jv_list[1].get("against_invoice")) - + def test_make_return_jv_for_sales_invoice_non_packing_item(self): self._clear_stock_account_balance() se = self._test_sales_invoice_return("_Test Item", 5, 2) self._test_sales_return_jv(se) - + def test_make_return_jv_for_sales_invoice_packing_item(self): self._clear_stock_account_balance() se = self._test_sales_invoice_return("_Test Sales BOM Item", 25, 20) self._test_sales_return_jv(se) - + def test_make_return_jv_for_delivery_note_non_packing_item(self): self._clear_stock_account_balance() se = self._test_delivery_note_return("_Test Item", 5, 2) self._test_sales_return_jv(se) - + se = self._test_delivery_note_return_against_sales_order("_Test Item", 5, 2) self._test_sales_return_jv(se) - + def test_make_return_jv_for_delivery_note_packing_item(self): self._clear_stock_account_balance() se = self._test_delivery_note_return("_Test Sales BOM Item", 25, 20) self._test_sales_return_jv(se) - + se = self._test_delivery_note_return_against_sales_order("_Test Sales BOM Item", 25, 20) self._test_sales_return_jv(se) - + def _test_delivery_note_return_against_sales_order(self, item_code, delivered_qty, returned_qty): self._insert_material_receipt() @@ -447,13 +447,13 @@ class TestStockEntry(unittest.TestCase): from selling.doctype.sales_order.sales_order import make_sales_invoice, make_delivery_note actual_qty_0 = self._get_actual_qty() - + so = webnotes.bean(copy=sales_order_test_records[0]) so.doclist[1].item_code = item_code so.doclist[1].qty = 5.0 so.insert() so.submit() - + dn_doclist = make_delivery_note(so.doc.name) dn = webnotes.bean(dn_doclist) @@ -461,7 +461,7 @@ class TestStockEntry(unittest.TestCase): dn.doc.posting_date = so.doc.delivery_date dn.insert() dn.submit() - + actual_qty_1 = self._get_actual_qty() self.assertEquals(actual_qty_0 - delivered_qty, actual_qty_1) @@ -492,43 +492,43 @@ class TestStockEntry(unittest.TestCase): self.assertEquals(actual_qty_1 + returned_qty, actual_qty_2) return se - + def test_purchase_receipt_return(self): self._clear_stock_account_balance() - + actual_qty_0 = self._get_actual_qty() - + from stock.doctype.purchase_receipt.test_purchase_receipt \ import test_records as purchase_receipt_test_records from stock.doctype.purchase_receipt.purchase_receipt import make_purchase_invoice - + # submit purchase receipt pr = webnotes.bean(copy=purchase_receipt_test_records[0]) pr.insert() pr.submit() - + actual_qty_1 = self._get_actual_qty() - + self.assertEquals(actual_qty_0 + 5, actual_qty_1) - + pi_doclist = make_purchase_invoice(pr.doc.name) - + pi = webnotes.bean(pi_doclist) pi.doc.posting_date = pr.doc.posting_date pi.doc.credit_to = "_Test Supplier - _TC" for d in pi.doclist.get({"parentfield": "entries"}): d.expense_head = "_Test Account Cost for Goods Sold - _TC" d.cost_center = "_Test Cost Center - _TC" - + for d in pi.doclist.get({"parentfield": "purchase_tax_details"}): d.cost_center = "_Test Cost Center - _TC" - + pi.run_method("calculate_taxes_and_totals") pi.doc.bill_no = "NA" pi.insert() pi.submit() - + # submit purchase return se = webnotes.bean(copy=test_records[0]) se.doc.purpose = "Purchase Return" @@ -539,22 +539,22 @@ class TestStockEntry(unittest.TestCase): se.doclist[1].s_warehouse = "_Test Warehouse - _TC" se.insert() se.submit() - + actual_qty_2 = self._get_actual_qty() - + self.assertEquals(actual_qty_1 - 5, actual_qty_2) - + webnotes.conn.set_default("company", self.old_default_company) - + return se, pr.doc.name - + def test_over_stock_return(self): from stock.doctype.stock_entry.stock_entry import StockOverReturnError self._clear_stock_account_balance() - + # out of 10, 5 gets returned prev_se, pr_docname = self.test_purchase_receipt_return() - + # submit purchase return - return another 6 qtys so that exception is raised se = webnotes.bean(copy=test_records[0]) se.doc.purpose = "Purchase Return" @@ -563,20 +563,20 @@ class TestStockEntry(unittest.TestCase): se.doc.fiscal_year = "_Test Fiscal Year 2013" se.doclist[1].qty = se.doclist[1].transfer_qty = 6 se.doclist[1].s_warehouse = "_Test Warehouse - _TC" - + self.assertRaises(StockOverReturnError, se.insert) - + def _test_purchase_return_jv(self, se): from stock.doctype.stock_entry.stock_entry import make_return_jv jv_list = make_return_jv(se.doc.name) - + self.assertEqual(len(jv_list), 3) self.assertEqual(jv_list[0].get("voucher_type"), "Debit Note") self.assertEqual(jv_list[0].get("posting_date"), se.doc.posting_date) self.assertEqual(jv_list[1].get("account"), "_Test Supplier - _TC") self.assertEqual(jv_list[2].get("account"), "_Test Account Cost for Goods Sold - _TC") self.assertTrue(jv_list[1].get("against_voucher")) - + def test_make_return_jv_for_purchase_receipt(self): self._clear_stock_account_balance() se, pr_name = self.test_purchase_receipt_return() @@ -584,18 +584,18 @@ class TestStockEntry(unittest.TestCase): se, pr_name = self._test_purchase_return_return_against_purchase_order() self._test_purchase_return_jv(se) - + def _test_purchase_return_return_against_purchase_order(self): self._clear_stock_account_balance() - + actual_qty_0 = self._get_actual_qty() - + from buying.doctype.purchase_order.test_purchase_order \ import test_records as purchase_order_test_records - + from buying.doctype.purchase_order.purchase_order import \ make_purchase_receipt, make_purchase_invoice - + # submit purchase receipt po = webnotes.bean(copy=purchase_order_test_records[0]) po.doc.is_subcontracted = None @@ -603,20 +603,20 @@ class TestStockEntry(unittest.TestCase): po.doclist[1].import_rate = 50 po.insert() po.submit() - + pr_doclist = make_purchase_receipt(po.doc.name) - + pr = webnotes.bean(pr_doclist) pr.doc.posting_date = po.doc.transaction_date pr.insert() pr.submit() - + actual_qty_1 = self._get_actual_qty() - + self.assertEquals(actual_qty_0 + 10, actual_qty_1) - + pi_doclist = make_purchase_invoice(po.doc.name) - + pi = webnotes.bean(pi_doclist) pi.doc.posting_date = pr.doc.posting_date pi.doc.credit_to = "_Test Supplier - _TC" @@ -625,12 +625,12 @@ class TestStockEntry(unittest.TestCase): d.cost_center = "_Test Cost Center - _TC" for d in pi.doclist.get({"parentfield": "purchase_tax_details"}): d.cost_center = "_Test Cost Center - _TC" - + pi.run_method("calculate_taxes_and_totals") pi.doc.bill_no = "NA" pi.insert() pi.submit() - + # submit purchase return se = webnotes.bean(copy=test_records[0]) se.doc.purpose = "Purchase Return" @@ -641,23 +641,23 @@ class TestStockEntry(unittest.TestCase): se.doclist[1].s_warehouse = "_Test Warehouse - _TC" se.insert() se.submit() - + actual_qty_2 = self._get_actual_qty() - + self.assertEquals(actual_qty_1 - 5, actual_qty_2) - + webnotes.conn.set_default("company", self.old_default_company) - + return se, pr.doc.name - + def _clear_stock_account_balance(self): webnotes.conn.sql("delete from `tabStock Ledger Entry`") webnotes.conn.sql("""delete from `tabBin`""") webnotes.conn.sql("""delete from `tabGL Entry`""") - + self.old_default_company = webnotes.conn.get_default("company") webnotes.conn.set_default("company", "_Test Company") - + def test_serial_no_not_reqd(self): se = webnotes.bean(copy=test_records[0]) se.doclist[1].serial_no = "ABCD" @@ -689,7 +689,7 @@ class TestStockEntry(unittest.TestCase): se.doclist[1].transfer_qty = 2 se.insert() self.assertRaises(SerialNoQtyError, se.submit) - + def test_serial_no_transfer_in(self): self._clear_stock_account_balance() se = webnotes.bean(copy=test_records[0]) @@ -699,13 +699,13 @@ class TestStockEntry(unittest.TestCase): se.doclist[1].transfer_qty = 2 se.insert() se.submit() - + self.assertTrue(webnotes.conn.exists("Serial No", "ABCD")) self.assertTrue(webnotes.conn.exists("Serial No", "EFGH")) - + se.cancel() self.assertFalse(webnotes.conn.get_value("Serial No", "ABCD", "warehouse")) - + def test_serial_no_not_exists(self): self._clear_stock_account_balance() se = webnotes.bean(copy=test_records[0]) @@ -718,11 +718,11 @@ class TestStockEntry(unittest.TestCase): se.doclist[1].transfer_qty = 2 se.insert() self.assertRaises(SerialNoNotExistsError, se.submit) - + def test_serial_duplicate(self): self._clear_stock_account_balance() self.test_serial_by_series() - + se = webnotes.bean(copy=test_records[0]) se.doclist[1].item_code = "_Test Serialized Item With Series" se.doclist[1].qty = 1 @@ -730,22 +730,22 @@ class TestStockEntry(unittest.TestCase): se.doclist[1].transfer_qty = 1 se.insert() self.assertRaises(SerialNoDuplicateError, se.submit) - + def test_serial_by_series(self): self._clear_stock_account_balance() se = make_serialized_item() serial_nos = get_serial_nos(se.doclist[1].serial_no) - + self.assertTrue(webnotes.conn.exists("Serial No", serial_nos[0])) self.assertTrue(webnotes.conn.exists("Serial No", serial_nos[1])) - + return se def test_serial_item_error(self): self._clear_stock_account_balance() self.test_serial_by_series() - + se = webnotes.bean(copy=test_records[0]) se.doc.purpose = "Material Transfer" se.doclist[1].item_code = "_Test Serialized Item" @@ -761,7 +761,7 @@ class TestStockEntry(unittest.TestCase): self._clear_stock_account_balance() se = make_serialized_item() serial_no = get_serial_nos(se.doclist[1].serial_no)[0] - + se = webnotes.bean(copy=test_records[0]) se.doc.purpose = "Material Transfer" se.doclist[1].item_code = "_Test Serialized Item With Series" @@ -773,14 +773,14 @@ class TestStockEntry(unittest.TestCase): se.insert() se.submit() self.assertTrue(webnotes.conn.get_value("Serial No", serial_no, "warehouse"), "_Test Warehouse 1 - _TC") - + se.cancel() self.assertTrue(webnotes.conn.get_value("Serial No", serial_no, "warehouse"), "_Test Warehouse - _TC") def test_serial_warehouse_error(self): self._clear_stock_account_balance() make_serialized_item() - + se = webnotes.bean(copy=test_records[0]) se.doc.purpose = "Material Transfer" se.doclist[1].item_code = "_Test Serialized Item With Series" @@ -791,15 +791,31 @@ class TestStockEntry(unittest.TestCase): se.doclist[1].t_warehouse = "_Test Warehouse - _TC" se.insert() self.assertRaises(SerialNoWarehouseError, se.submit) - + def test_serial_cancel(self): self._clear_stock_account_balance() se = self.test_serial_by_series() se.cancel() - + serial_no = get_serial_nos(se.doclist[1].serial_no)[0] self.assertFalse(webnotes.conn.get_value("Serial No", serial_no, "warehouse")) + def test_freeze_stocks (self): + self._clear_stock_account_balance() + + # test freeze_stocks_upto + date_newer_than_test_records = add_days(getdate(test_records[0][0]['posting_date']), 5) + webnotes.conn.set_value("Stock Settings", None, "stock_frozen_upto", date_newer_than_test_records) + se = webnotes.bean(copy=test_records[0]).insert() + self.assertRaises (ValidationError, se.submit) + webnotes.conn.set_value("Stock Settings", None, "stock_frozen_upto", '') + + # test freeze_stocks_upto_days + webnotes.conn.set_value("Stock Settings", None, "stock_frozen_upto_days", 7) + se = webnotes.bean(copy=test_records[0]).insert() + self.assertRaises (ValidationError, se.submit) + webnotes.conn.set_value("Stock Settings", None, "stock_frozen_upto_days", 0) + def make_serialized_item(): se = webnotes.bean(copy=test_records[0]) se.doclist[1].item_code = "_Test Serialized Item With Series" @@ -812,70 +828,70 @@ def make_serialized_item(): test_records = [ [ { - "company": "_Test Company", - "doctype": "Stock Entry", - "posting_date": "2013-01-01", - "posting_time": "17:14:24", + "company": "_Test Company", + "doctype": "Stock Entry", + "posting_date": "2013-01-01", + "posting_time": "17:14:24", "purpose": "Material Receipt", - "fiscal_year": "_Test Fiscal Year 2013", - }, + "fiscal_year": "_Test Fiscal Year 2013", + }, { - "conversion_factor": 1.0, - "doctype": "Stock Entry Detail", - "item_code": "_Test Item", - "parentfield": "mtn_details", + "conversion_factor": 1.0, + "doctype": "Stock Entry Detail", + "item_code": "_Test Item", + "parentfield": "mtn_details", "incoming_rate": 100, - "qty": 50.0, - "stock_uom": "_Test UOM", - "transfer_qty": 50.0, + "qty": 50.0, + "stock_uom": "_Test UOM", + "transfer_qty": 50.0, "uom": "_Test UOM", "t_warehouse": "_Test Warehouse - _TC", "expense_account": "Stock Adjustment - _TC", "cost_center": "_Test Cost Center - _TC" - }, + }, ], [ { - "company": "_Test Company", - "doctype": "Stock Entry", - "posting_date": "2013-01-25", - "posting_time": "17:15", + "company": "_Test Company", + "doctype": "Stock Entry", + "posting_date": "2013-01-25", + "posting_time": "17:15", "purpose": "Material Issue", - "fiscal_year": "_Test Fiscal Year 2013", - }, + "fiscal_year": "_Test Fiscal Year 2013", + }, { - "conversion_factor": 1.0, - "doctype": "Stock Entry Detail", - "item_code": "_Test Item", - "parentfield": "mtn_details", + "conversion_factor": 1.0, + "doctype": "Stock Entry Detail", + "item_code": "_Test Item", + "parentfield": "mtn_details", "incoming_rate": 100, - "qty": 40.0, - "stock_uom": "_Test UOM", - "transfer_qty": 40.0, + "qty": 40.0, + "stock_uom": "_Test UOM", + "transfer_qty": 40.0, "uom": "_Test UOM", "s_warehouse": "_Test Warehouse - _TC", "expense_account": "Stock Adjustment - _TC", "cost_center": "_Test Cost Center - _TC" - }, + }, ], [ { - "company": "_Test Company", - "doctype": "Stock Entry", - "posting_date": "2013-01-25", - "posting_time": "17:14:24", + "company": "_Test Company", + "doctype": "Stock Entry", + "posting_date": "2013-01-25", + "posting_time": "17:14:24", "purpose": "Material Transfer", - "fiscal_year": "_Test Fiscal Year 2013", - }, + "fiscal_year": "_Test Fiscal Year 2013", + }, { - "conversion_factor": 1.0, - "doctype": "Stock Entry Detail", - "item_code": "_Test Item", - "parentfield": "mtn_details", + "conversion_factor": 1.0, + "doctype": "Stock Entry Detail", + "item_code": "_Test Item", + "parentfield": "mtn_details", "incoming_rate": 100, - "qty": 45.0, - "stock_uom": "_Test UOM", - "transfer_qty": 45.0, + "qty": 45.0, + "stock_uom": "_Test UOM", + "transfer_qty": 45.0, "uom": "_Test UOM", "s_warehouse": "_Test Warehouse - _TC", "t_warehouse": "_Test Warehouse 1 - _TC", @@ -885,40 +901,40 @@ test_records = [ ], [ { - "company": "_Test Company", - "doctype": "Stock Entry", - "posting_date": "2013-01-25", - "posting_time": "17:14:24", + "company": "_Test Company", + "doctype": "Stock Entry", + "posting_date": "2013-01-25", + "posting_time": "17:14:24", "purpose": "Manufacture/Repack", - "fiscal_year": "_Test Fiscal Year 2013", - }, + "fiscal_year": "_Test Fiscal Year 2013", + }, { - "conversion_factor": 1.0, - "doctype": "Stock Entry Detail", - "item_code": "_Test Item", - "parentfield": "mtn_details", + "conversion_factor": 1.0, + "doctype": "Stock Entry Detail", + "item_code": "_Test Item", + "parentfield": "mtn_details", "incoming_rate": 100, - "qty": 50.0, - "stock_uom": "_Test UOM", - "transfer_qty": 50.0, + "qty": 50.0, + "stock_uom": "_Test UOM", + "transfer_qty": 50.0, "uom": "_Test UOM", "s_warehouse": "_Test Warehouse - _TC", "expense_account": "Stock Adjustment - _TC", "cost_center": "_Test Cost Center - _TC" - }, + }, { - "conversion_factor": 1.0, - "doctype": "Stock Entry Detail", - "item_code": "_Test Item Home Desktop 100", - "parentfield": "mtn_details", + "conversion_factor": 1.0, + "doctype": "Stock Entry Detail", + "item_code": "_Test Item Home Desktop 100", + "parentfield": "mtn_details", "incoming_rate": 5000, - "qty": 1, - "stock_uom": "_Test UOM", - "transfer_qty": 1, + "qty": 1, + "stock_uom": "_Test UOM", + "transfer_qty": 1, "uom": "_Test UOM", "t_warehouse": "_Test Warehouse - _TC", "expense_account": "Stock Adjustment - _TC", "cost_center": "_Test Cost Center - _TC" }, ], -] \ No newline at end of file +] diff --git a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py index 38d5b26605..232d8dff9d 100644 --- a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +++ b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py @@ -87,14 +87,14 @@ class DocType(DocListController): stock_frozen_upto = webnotes.conn.get_value('Stock Settings', None, 'stock_frozen_upto') or '' if stock_frozen_upto: stock_auth_role = webnotes.conn.get_value('Stock Settings', None,'stock_auth_role') - if getdate(self.doc.posting_date) <= getdate(stock_frozen_upto) and not stock_auth_role in webnotes.user.get_roles(): + if getdate(self.doc.posting_date) <= getdate(stock_frozen_upto): # and not stock_auth_role in webnotes.user.get_roles(): msgprint("You are not authorized to do / modify back dated stock entries before %s" % getdate(stock_frozen_upto).strftime('%d-%m-%Y'), raise_exception=1) stock_frozen_upto_days = int(webnotes.conn.get_value('Stock Settings', None, 'stock_frozen_upto_days') or 0) if stock_frozen_upto_days: stock_auth_role = webnotes.conn.get_value('Stock Settings', None,'stock_auth_role') older_than_x_days_ago = (add_days(getdate(self.doc.posting_date), stock_frozen_upto_days) <= date.today()) - if older_than_x_days_ago and not stock_auth_role in webnotes.user.get_roles(): + if older_than_x_days_ago: # and not stock_auth_role in webnotes.user.get_roles(): msgprint("You are not authorized to do / modify back dated stock entries older than %d days ago" %stock_frozen_upto_days, raise_exception=1) From 990d7c48627015694e9832bff3703aed34d78d14 Mon Sep 17 00:00:00 2001 From: Thura Hlaing Date: Wed, 29 Jan 2014 14:53:21 +0630 Subject: [PATCH 9/9] added StockFreezeError, and uncomment stock_auth_role check --- stock/doctype/stock_entry/test_stock_entry.py | 7 ++++--- stock/doctype/stock_ledger_entry/stock_ledger_entry.py | 10 ++++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/stock/doctype/stock_entry/test_stock_entry.py b/stock/doctype/stock_entry/test_stock_entry.py index 78ca0198db..b88f1c9d18 100644 --- a/stock/doctype/stock_entry/test_stock_entry.py +++ b/stock/doctype/stock_entry/test_stock_entry.py @@ -6,7 +6,7 @@ import webnotes, unittest from webnotes.utils import flt from stock.doctype.serial_no.serial_no import * from stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory - +from stock.doctype.stock_ledger_entry.stock_ledger_entry import StockFreezeError class TestStockEntry(unittest.TestCase): def tearDown(self): @@ -802,18 +802,19 @@ class TestStockEntry(unittest.TestCase): def test_freeze_stocks (self): self._clear_stock_account_balance() + stock_auth_role = webnotes.conn.set_value('Stock Settings', None,'stock_auth_role', '') # test freeze_stocks_upto date_newer_than_test_records = add_days(getdate(test_records[0][0]['posting_date']), 5) webnotes.conn.set_value("Stock Settings", None, "stock_frozen_upto", date_newer_than_test_records) se = webnotes.bean(copy=test_records[0]).insert() - self.assertRaises (ValidationError, se.submit) + self.assertRaises (StockFreezeError, se.submit) webnotes.conn.set_value("Stock Settings", None, "stock_frozen_upto", '') # test freeze_stocks_upto_days webnotes.conn.set_value("Stock Settings", None, "stock_frozen_upto_days", 7) se = webnotes.bean(copy=test_records[0]).insert() - self.assertRaises (ValidationError, se.submit) + self.assertRaises (StockFreezeError, se.submit) webnotes.conn.set_value("Stock Settings", None, "stock_frozen_upto_days", 0) def make_serialized_item(): diff --git a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py index 232d8dff9d..277992bcd9 100644 --- a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +++ b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py @@ -9,6 +9,8 @@ from webnotes.utils import flt, getdate, add_days from webnotes.model.controller import DocListController from datetime import date +class StockFreezeError(webnotes.ValidationError): pass + class DocType(DocListController): def __init__(self, doc, doclist=[]): self.doc = doc @@ -87,15 +89,15 @@ class DocType(DocListController): stock_frozen_upto = webnotes.conn.get_value('Stock Settings', None, 'stock_frozen_upto') or '' if stock_frozen_upto: stock_auth_role = webnotes.conn.get_value('Stock Settings', None,'stock_auth_role') - if getdate(self.doc.posting_date) <= getdate(stock_frozen_upto): # and not stock_auth_role in webnotes.user.get_roles(): - msgprint("You are not authorized to do / modify back dated stock entries before %s" % getdate(stock_frozen_upto).strftime('%d-%m-%Y'), raise_exception=1) + if getdate(self.doc.posting_date) <= getdate(stock_frozen_upto) and not stock_auth_role in webnotes.user.get_roles(): + msgprint("You are not authorized to do / modify back dated stock entries before %s" % getdate(stock_frozen_upto).strftime('%d-%m-%Y'), raise_exception=StockFreezeError) stock_frozen_upto_days = int(webnotes.conn.get_value('Stock Settings', None, 'stock_frozen_upto_days') or 0) if stock_frozen_upto_days: stock_auth_role = webnotes.conn.get_value('Stock Settings', None,'stock_auth_role') older_than_x_days_ago = (add_days(getdate(self.doc.posting_date), stock_frozen_upto_days) <= date.today()) - if older_than_x_days_ago: # and not stock_auth_role in webnotes.user.get_roles(): - msgprint("You are not authorized to do / modify back dated stock entries older than %d days ago" %stock_frozen_upto_days, raise_exception=1) + if older_than_x_days_ago and not stock_auth_role in webnotes.user.get_roles(): + msgprint("You are not authorized to do / modify back dated stock entries older than %d days ago" %stock_frozen_upto_days, raise_exception=StockFreezeError) def scrub_posting_time(self):