From 08f4cb7f6a53ceaf5cae67e0243fd899f1a2011d Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 10 May 2012 12:13:47 +0530 Subject: [PATCH] stock reco fix in valuation and cancellation --- erpnext/patches/patch_list.py | 5 + .../selling/doctype/sms_center/sms_center.py | 1 - erpnext/stock/doctype/bin/bin.py | 3 +- .../stock_reconciliation.py | 93 ++++++++++++------- .../stock_reconciliation.txt | 17 +++- 5 files changed, 79 insertions(+), 40 deletions(-) diff --git a/erpnext/patches/patch_list.py b/erpnext/patches/patch_list.py index 01f4a0efdd..ea8e5d6588 100644 --- a/erpnext/patches/patch_list.py +++ b/erpnext/patches/patch_list.py @@ -332,5 +332,10 @@ patch_list = [ 'patch_file': 'renamedt_in_custom_search_criteria', 'description': 'raname dt in custom search criteria' }, + { + 'patch_module': 'patches.may_2012', + 'patch_file': 'stock_reco_patch', + 'description': 'stock reco patch: store diff info in field' + }, ] diff --git a/erpnext/selling/doctype/sms_center/sms_center.py b/erpnext/selling/doctype/sms_center/sms_center.py index 0e54dd6dd1..0d54f72bd7 100644 --- a/erpnext/selling/doctype/sms_center/sms_center.py +++ b/erpnext/selling/doctype/sms_center/sms_center.py @@ -46,7 +46,6 @@ class DocType: where_clause = self.doc.supplier and " and ifnull(is_supplier, 0) = 1 and supplier = '%s'" % self.doc.supplier or " and ifnull(is_supplier, 0) = 1" if self.doc.send_to == 'All Sales Partner Contact': where_clause = self.doc.sales_partner and " and ifnull(is_sales_partner, 0) = 1 and sales_aprtner = '%s'" % self.doc.sales_partner or " and ifnull(is_sales_partner, 0) = 1" - msgprint(1) if self.doc.send_to in ['All Contact', 'All Customer Contact', 'All Supplier Contact', 'All Sales Partner Contact']: msgprint("select CONCAT(ifnull(first_name,''),'',ifnull(last_name,'')), mobile_no from `tabContact` where ifnull(mobile_no,'')!='' and docstatus != 2 %s" % where_clause) rec = sql("select CONCAT(ifnull(first_name,''),'',ifnull(last_name,'')), mobile_no from `tabContact` where ifnull(mobile_no,'')!='' and docstatus != 2 %s" % where_clause) diff --git a/erpnext/stock/doctype/bin/bin.py b/erpnext/stock/doctype/bin/bin.py index ce2cae68f3..fe96c9f022 100644 --- a/erpnext/stock/doctype/bin/bin.py +++ b/erpnext/stock/doctype/bin/bin.py @@ -181,8 +181,7 @@ class DocType: # get moving average inventory values # ------------------------------------ def get_moving_average_inventory_values(self, val_rate, in_rate, opening_qty, actual_qty, is_cancelled): - #msgprint(actual_qty) - if flt(in_rate) <= 0: # In case of delivery/stock issue in_rate = 0 or wrong incoming rate + if flt(in_rate) == 0: # In case of delivery/stock issue in_rate = 0 or wrong incoming rate in_rate = val_rate # val_rate is same as previous entry if : diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py index f3742b3b2d..1f3df46678 100644 --- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py @@ -16,7 +16,7 @@ import webnotes from webnotes.utils import cstr, flt, get_defaults, nowdate -from webnotes import msgprint +from webnotes import msgprint, errprint from webnotes.model.code import get_obj sql = webnotes.conn.sql @@ -28,22 +28,30 @@ class DocType: self.doclist = doclist self.validated = 1 self.data = [] + self.val_method = get_defaults()['valuation_method'] def get_template(self): - return [['Item Code', 'Warehouse', 'Quantity', 'Valuation Rate']] + if self.val_method == 'Moving Average': + return [['Item Code', 'Warehouse', 'Quantity', 'Valuation Rate']] + else: + return [['Item Code', 'Warehouse', 'Quantity', 'Incoming Rate']] - def get_csv_file_data(self): + + def get_csv_file_data(self, submit = 1): """Get csv data""" - filename = self.doc.file_list.split(',') - if not filename: - msgprint("Please Attach File. ", raise_exception=1) + if submit: + filename = self.doc.file_list.split(',') + if not filename: + msgprint("Please Attach File. ", raise_exception=1) - from webnotes.utils import file_manager - fn, content = file_manager.get_file(filename[1]) + from webnotes.utils import file_manager + fn, content = file_manager.get_file(filename[1]) - # NOTE: Don't know why this condition exists - if not isinstance(content, basestring) and hasattr(content, 'tostring'): - content = content.tostring() + # NOTE: Don't know why this condition exists + if not isinstance(content, basestring) and hasattr(content, 'tostring'): + content = content.tostring() + else: + content = self.doc.diff_info return content @@ -69,7 +77,7 @@ class DocType: def get_reconciliation_data(self,submit = 1): """Read and validate csv data""" import csv - data = csv.reader(self.get_csv_file_data().splitlines()) + data = csv.reader(self.get_csv_file_data(submit).splitlines()) self.convert_into_list(data, submit) @@ -96,7 +104,6 @@ class DocType: def validate(self): """Validate attachment data""" - #self.data = [['it', 'wh1', 20, 150]] if self.doc.file_list: self.get_reconciliation_data() @@ -105,17 +112,32 @@ class DocType: def get_system_stock(self, it, wh): """get actual qty on reconciliation date and time as per system""" bin = sql("select name from tabBin where item_code=%s and warehouse=%s", (it, wh)) - prev_sle = bin and get_obj('Bin', bin[0][0]).get_sle_prev_timebucket(self.doc.reconciliation_date, self.doc.reconciliation_time) or {} + prev_sle = bin and get_obj('Bin', bin[0][0]).get_prev_sle(self.doc.reconciliation_date, self.doc.reconciliation_time) or {} return { 'actual_qty': prev_sle.get('bin_aqat', 0), 'stock_uom' : sql("select stock_uom from tabItem where name = %s", it)[0][0], 'val_rate' : prev_sle.get('valuation_rate', 0) } + + def get_incoming_rate(self, row, qty_diff, sys_stock, is_submit): + """Calculate incoming rate to maintain valuation rate""" + if qty_diff and is_submit: + if self.val_method == 'Moving Average': + in_rate = flt(row[3]) + (flt(sys_stock['actual_qty'])*(flt(row[3]) - flt(sys_stock['val_rate'])))/ flt(qty_diff) + elif not sys_stock and not row[3]: + msgprint("Incoming Rate is mandatory for item: %s and warehouse: %s" % (rpw[0], row[1]), raise_exception=1) + else: + in_rate = qty_diff > 0 and row[3] or 0 + else: + in_rate = 0 + + return in_rate + def make_sl_entry(self, is_submit, row, qty_diff, sys_stock): """Make stock ledger entry""" - in_rate = self.get_incoming_rate(row, qty_diff, sys_stock) + in_rate = self.get_incoming_rate(row, qty_diff, sys_stock, is_submit) values = [{ 'item_code' : row[0], 'warehouse' : row[1], @@ -133,14 +155,16 @@ class DocType: 'is_cancelled' : (is_submit==1) and 'No' or 'Yes', 'batch_no' : '', 'serial_no' : '' - }] + }] get_obj('Stock Ledger', 'Stock Ledger').update_stock(values) - - def get_incoming_rate(self, row, qty_diff, sys_stock): - """Calculate incoming rate to maintain valuation rate""" - in_rate = flt(row[3]) + (flt(sys_stock['actual_qty'])*(flt(row[3]) - flt(sys_stock['val_rate'])))/ flt(qty_diff) - return in_rate + + + def make_entry_for_valuation(self, row, sys_stock, is_submit): + self.make_sl_entry(is_submit, row, 1, sys_stock) + sys_stock['val_rate'] = row[3] + sys_stock['actual_qty'] += 1 + self.make_sl_entry(is_submit, row, -1, sys_stock) def do_stock_reco(self, is_submit = 1): @@ -159,33 +183,34 @@ class DocType: # Make sl entry if qty_diff: self.make_sl_entry(is_submit, row, qty_diff, sys_stock) - elif rate_diff: - self.make_sl_entry(is_submit, row, 1, sys_stock) - sys_stock['val_rate'] = row[3] - sys_stock['actual_qty'] += 1 - self.make_sl_entry(is_submit, row, -1, sys_stock) + sys_stock['actual_qty'] += qty_diff + + + if (not qty_diff and rate_diff) or qty_diff < 0 and self.val_method == 'Moving Average': + self.make_entry_for_valuation(row, sys_stock, is_submit) if is_submit == 1: - self.add_data_in_CSV(qty_diff, rate_diff) + self.store_diff_info(qty_diff, rate_diff) msgprint("Stock Reconciliation Completed Successfully...") - def add_data_in_CSV(self, qty_diff, rate_diff): + def store_diff_info(self, qty_diff, rate_diff): """Add diffs column in attached file""" # add header - out = "Item Code, Warehouse, Qty, Valuation Rate, Qty Diff, Val Rate Diff" + if self.val_method == 'Moving Average': + out = "Item Code, Warehouse, Qty, Valuation Rate, Qty Diff, Rate Diff" + else: + out = "Item Code, Warehouse, Qty, Incoming Rate, Qty Diff, Rate Diff" + # add data for d in self.data: s = [cstr(i) for i in d] + [cstr(qty_diff), cstr(rate_diff)] out += "\n" + ','.join(s) - - # write to file - fname = self.doc.file_list.split(',') - from webnotes.utils import file_manager - file_manager.write_file(fname[1], out) + + webnotes.conn.set(self.doc, 'diff_info', out) diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.txt b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.txt index c2fe30a87e..ac23d59c8d 100644 --- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.txt +++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.txt @@ -3,9 +3,9 @@ # These values are common in all dictionaries { - 'creation': '2012-03-27 14:36:40', + 'creation': '2012-04-13 11:56:39', 'docstatus': 0, - 'modified': '2012-03-27 14:45:52', + 'modified': '2012-05-10 11:54:52', 'modified_by': u'Administrator', 'owner': u'Administrator' }, @@ -27,7 +27,7 @@ 'server_code_error': u' ', 'show_in_menu': 0, 'subject': u'Date: %(reconciliation_date)s, Time: %(reconciliation_time)s', - 'version': 107 + 'version': 1 }, # These values are common for all DocField @@ -160,6 +160,17 @@ 'print_hide': 1 }, + # DocField + { + 'doctype': u'DocField', + 'fieldname': u'diff_info', + 'fieldtype': u'Text', + 'hidden': 1, + 'label': u'Diff Info', + 'permlevel': 0, + 'print_hide': 1 + }, + # DocField { 'depends_on': u'eval:doc.amended_from',