rewritten stock reconciliation

This commit is contained in:
Nabin Hait 2011-11-21 17:13:53 +05:30
parent 8fa6ad90ed
commit fc26f64011
6 changed files with 399 additions and 434 deletions

View File

@ -0,0 +1,94 @@
import unittest
import webnotes
import webnotes.profile
webnotes.user = webnotes.profile.Profile()
from webnotes.model.doc import Document
from webnotes.model.code import get_obj
from webnotes.utils import cstr, flt
from webnotes.model.doclist import getlist
sql = webnotes.conn.sql
from sandbox.testdata.masters import *
from sandbox.testdata.sle_data import sle, bin
from sandbox.testdata.stock_reco import *
#----------------------------------------------------------
class TestStockEntry(unittest.TestCase):
def assertDoc(self, lst):
"""assert all values"""
for d in lst:
cl, vl = [], []
for k in d.keys():
if k!='doctype':
cl.append('%s=%s' % (k, '%s'))
vl.append(d[k])
self.assertTrue(sql("select name from `tab%s` where %s limit 1" % (d['doctype'], ' and '.join(cl)), vl))
#===========================================================================
def setUp(self):
print "====================================="
webnotes.conn.begin()
create_master_records()
print 'Master Data Created'
for d in sle:
d.save(1)
print "Existing SLE created"
bin.save(1)
sreco.save(1)
print "Stock Reco saved"
#===========================================================================
def test_diff_in_both(self):
reco = get_obj('Stock Reconciliation', sreco.name)
reco.doc.docstatus = 1
reco.doc.save()
reco.validate()
reco.on_submit()
print "Stock Reco submitted"
print "Checking stock ledger entry........."
self.assertDoc(self.get_expected_sle('diff_in_both'))
#===========================================================================
def tearDown(self):
webnotes.conn.rollback()
# Expected Result Set
#===================================================================================================
def get_expected_sle(self, action):
expected_sle = {
'diff_in_both': [{
'doctype': 'Stock Ledger Entry',
'item_code':'it',
'warehouse':'wh1',
'voucher_type': 'Stock Reconciliation',
'voucher_no': sreco.name,
'actual_qty': 15,
'bin_aqat': 20,
'valuation_rate': 150,
#'stock_value': 3000,
'is_cancelled': 'No'
},{
'doctype': 'Stock Ledger Entry',
'posting_date': '2011-09-10',
'posting_time': '15:00',
'item_code': 'it',
'warehouse': 'wh1',
'actual_qty': 20,
'incoming_rate': 200,
'bin_aqat': 40,
'valuation_rate': 175,
#'stock_value': 4500,
'is_cancelled': 'No'
}
]
}
return expected_sle[action]

85
erpnext/sandbox/testdata/sle_data.py vendored Normal file
View File

@ -0,0 +1,85 @@
from webnotes.model.doc import Document
# Existing SLE data
#---------------------------
sle = [
Document(
fielddata = {
'doctype': 'Stock Ledger Entry',
'name': 'sle1',
'posting_date': '2011-09-01',
'posting_time': '12:00',
'item_code': 'it',
'warehouse': 'wh1',
'actual_qty': 10,
'incoming_rate': 100,
'bin_aqat': 10,
'valuation_rate': 100,
'fcfs_stack': '',
'stock_value': 1000,
'is_cancelled': 'No'
}
),
Document(
fielddata = {
'doctype': 'Stock Ledger Entry',
'name': 'sle2',
'posting_date': '2011-09-01',
'posting_time': '12:00',
'item_code': 'it',
'warehouse': 'wh1',
'actual_qty': -5,
'incoming_rate': 100,
'bin_aqat': 5,
'valuation_rate': 100,
'fcfs_stack': '',
'stock_value': 500,
'is_cancelled': 'No'
}
),
Document(
fielddata = {
'doctype': 'Stock Ledger Entry',
'name': 'sle3',
'posting_date': '2011-09-10',
'posting_time': '15:00',
'item_code': 'it',
'warehouse': 'wh1',
'actual_qty': 20,
'incoming_rate': 200,
'bin_aqat': 25,
'valuation_rate': 180,
'fcfs_stack': '',
'stock_value': 4500,
'is_cancelled': 'No'
}
),
Document(
fielddata = {
'doctype': 'Stock Ledger Entry',
'name': 'sle4',
'posting_date': '2011-09-15',
'posting_time': '09:30',
'item_code': 'it',
'warehouse': 'wh1',
'actual_qty': -5,
'incoming_rate': 180,
'bin_aqat': 20,
'valuation_rate': 180,
'fcfs_stack': '',
'stock_value': 3600,
'is_cancelled': 'No'
}
)
]
bin = Document(
fielddata = {
'doctype': 'Bin',
'name': 'bin01',
'item_code': 'it',
'warehouse': 'wh1',
'actual_qty': 20,
}
)

43
erpnext/sandbox/testdata/stock_reco.py vendored Normal file
View File

@ -0,0 +1,43 @@
from webnotes.model.doc import Document
# Stock Reconciliation
#---------------------------
sreco = Document(
fielddata = {
'doctype': 'Stock Reconciliation',
'name': 'sreco',
'reconciliation_date': '2011-09-08',
'reconciliation_time': '20:00',
}
)
# diff in both
csv_data1 = [
['Item', 'Warehouse', 'Quantity', 'Rate'],
['it', 'wh1', 20, 150]
]
# diff in qty, no rate
csv_data2 = [
['Item', 'Warehouse', 'Quantity'],
['it', 'wh1', 20]
]
# diff in rate, no qty
csv_data3 = [
['Item', 'Warehouse', 'Rate'],
['it', 'wh1', 200]
]
# diff in rate, same qty
csv_data4 = [
['Item', 'Warehouse', 'Quantity', 'Rate'],
['it', 'wh1', 5, 200]
]
# no diff
csv_data1 = [
['Item', 'Warehouse', 'Quantity', 'Rate'],
['it', 'wh1', 5, 100]
]

View File

@ -1,37 +1,7 @@
cur_frm.cscript.onload = function(doc, cdt, cdn) {
cfn_set_fields(doc, cdt, cdn);
cur_frm.cscript.refresh = function(doc) {
if (doc.docstatus) hide_field('Steps');
}
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
cfn_set_fields(doc, cdt, cdn);
cur_frm.cscript['Download Template'] = function(doc, cdt, cdn) {
$c_obj_csv(make_doclist(cdt, cdn), 'get_template', '');
}
var cfn_set_fields = function(doc, cdt, cdn) {
refresh_field('remark');
refresh_field('next_step');
if (doc.docstatus == 0 && doc.next_step == 'Upload File and Save Document')
doc.next_step = 'Validate Data';
if (! doc.file_list)
doc.next_step = 'Upload File and Save Document'
if (doc.next_step == 'Upload File and Save Document') {
//alert("Upload File and Save Document");
cur_frm.clear_tip();
cur_frm.set_tip("Please Enter Reconciliation Date and Attach CSV File with Columns in Following Sequence:-");
cur_frm.append_tip("Item Code , Warehouse , Qty , MAR");
hide_field("Validate Data");
}
if (doc.next_step == 'Validate Data') {
//alert("Validate Data");
cur_frm.clear_tip();
cur_frm.set_tip("Please Check Remarks");
unhide_field("Validate Data");
}
if (doc.next_step == 'Submit Document') {
//alert('Submit Document');
cur_frm.clear_tip();
cur_frm.set_tip("Please Submit the document.");
hide_field("Validate Data");
}
}

View File

@ -1,270 +1,23 @@
# Please edit this list and import only required elements
import webnotes
from webnotes.utils import add_days, add_months, add_years, cint, cstr, date_diff, default_fields, flt, fmt_money, formatdate, generate_hash, getTraceback, get_defaults, get_first_day, get_last_day, getdate, has_common, month_name, now, nowdate, replace_newlines, sendmail, set_default, str_esc_quote, user_format, validate_email_add
from webnotes.model import db_exists
from webnotes.model.doc import Document, addchild, removechild, getchildren, make_autoname, SuperDocType
from webnotes.model.doclist import getlist, copy_doclist
from webnotes.model.code import get_obj, get_server_obj, run_server_obj, updatedb, check_syntax
from webnotes import session, form, is_testing, msgprint, errprint
set = webnotes.conn.set
from webnotes.utils import cstr, flt, get_defaults, nowdate
from webnotes import msgprint
from webnotes.model.code import get_obj
sql = webnotes.conn.sql
get_value = webnotes.conn.get_value
in_transaction = webnotes.conn.in_transaction
convert_to_lists = webnotes.conn.convert_to_lists
# -----------------------------------------------------------------------------------------
class DocType:
def __init__(self, doc, doclist=[]):
self.doc = doc
self.doclist = doclist
self.label = { 'item_code': 0 , 'warehouse': 1 , 'qty': 2, 'mar': 3,'stock_uom':4, 'actual_qty':5, 'diff': 6} # with mar
self.validated = 1
self.data = []
# autoname
#-----------------
def autoname(self):
self.doc.name = make_autoname('SR/' + self.doc.fiscal_year + '/.######')
def get_template(self):
return [['Item Code', 'Warehouse', 'Quantity', 'Valuation Rate']]
# -----------------
# update next step
# -----------------
def update_next_step(self,next_step):
sql("update `tabStock Reconciliation` set next_step = '%s' where name = '%s'" % (next_step,self.doc.name))
# -----------
# add remark
# -----------
def add_remark(self, text, next_step, first_time = 0):
if first_time:
sql("update `tabStock Reconciliation` set remark = '' where name = '%s'" % self.doc.name)
else:
sql("update `tabStock Reconciliation` set remark = concat(remark, '%s'), modified = '%s' where name = '%s'" % (text + "<br>", nowdate(), self.doc.name))
self.update_next_step(next_step)
# --------------
# validate item
# --------------
def validate_item(self, item, count, check_item = 1):
det = sql("select item_code, has_serial_no from `tabItem` where name = '%s'"% cstr(item), as_dict = 1)
if not det:
text = "Item: " + cstr(item) + " mentioned at Row No. " + cstr(count) + "does not exist in the system"
msgprint(text)
self.add_remark(text, 'Validate Data', 0)
check_item = 0
elif det and det[0]['has_serial_no'] == 'Yes':
text = "You cannot make Stock Reconciliation of items having serial no. You can directly upload serial no to update their inventory. Please remove Item Code : %s at Row No. %s" %(cstr(item), cstr(count))
msgprint(text)
self.add_remark(text, 'Validate Data', 0)
check_item = 0
return check_item
# -------------------
# validate warehouse
# -------------------
def validate_warehouse(self,wh,count, check_warehouse = 1):
if not sql("select name from `tabWarehouse` where name = '%s'" % cstr(wh)):
text = "Warehouse: " + cstr(wh) + " mentioned at Row No. " + cstr(count) + "does not exist in the system"
self.add_remark(text,'Validate Data',0)
check_warehouse = 0
return check_warehouse
# ---------------------------
# validate data of .csv file
# ---------------------------
def validate_data(self,stock):
self.add_remark('','Validate Data',1)
# check whether file uploaded
if not self.doc.file_list:
set(self.doc,'next_step','Upload File and Save Document')
msgprint("Please Attach File", raise_exception=1)
# validate item and warehouse
check_item,check_warehouse,count = 1, 1, 1
for s in stock:
count +=1
check_item = self.validate_item(s[self.label['item_code']],count) or 0
check_warehouse = self.validate_warehouse(s[self.label['warehouse']],count) or 0
if check_item and check_warehouse:
text = "Validation Completed Successfully..."
self.add_remark(text,'Submit Document',0)
return check_item and check_warehouse
# ------------------------------
# convert lines in .csv to list
# ------------------------------
def convert_into_list(self, stock, submit):
count, st_list = 1, []
for s in stock:
if submit and len(s) != 4:
msgprint("Data entered at Row No " + cstr(count) + " in Attachment File is not in correct format.", raise_exception=1)
l = [s[0].encode("ascii"), s[1].encode("ascii"), s[2].encode("ascii"), s[3].encode("ascii")]
st_list.append(l)
count += 1
return st_list
# ------------------
# get current stock
# ------------------
def get_current_stock(self, item_code, warehouse):
bin = sql("select name from `tabBin` where item_code = '%s' and warehouse = '%s'" % (item_code, warehouse))
prev_sle = bin and get_obj('Bin', bin[0][0]).get_prev_sle(self.doc.reconciliation_date,self.doc.reconciliation_time) or {}
stock_uom = sql("select stock_uom from `tabItem` where name = %s",item_code)
return {'actual_qty': prev_sle.get('bin_aqat', 0), 'stock_uom': stock_uom[0][0]}
# -----------
# update mar
# -----------
def update_mar(self, d, qty_diff):
"""
update item valuation in previous date and also on post date if no qty diff
"""
self.update_entries_pre_date(d)
if not flt(d[self.label['qty']]) and not flt(d[self.label['actual_qty']]):
# seems like a special condition when there is no actual quanitity but there is a rate, may be only for setting a rate!
self.make_sl_entry(1,d,1)
self.make_sl_entry(1,d,-1)
elif not qty_diff:
self.update_entries_post_date(d)
# update valuation rate as csv file in all sle before reconciliation date
# ------------------------------------------------------------------------
def update_entries_pre_date(self, d):
mar = flt(d[self.label['mar']])
# previous sle
prev_sle = sql("""
select name, fcfs_stack
from `tabStock Ledger Entry`
where item_code = %s
and warehouse = %s
and ifnull(is_cancelled, 'No') = 'No'
and timestamp(posting_date, posting_time) <= timestamp(%s, %s)
""", (d[self.label['item_code']], d[self.label['warehouse']], self.doc.reconciliation_date, self.doc.reconciliation_time))
for each in prev_sle:
# updated fifo stack
fstack = each[1] and [[i[0], mar] for i in eval(each[1])] or ''
# update incoming rate, valuation rate, stock value and fifo stack
sql("""update `tabStock Ledger Entry`
set incoming_rate = %s, valuation_rate = %s, stock_value = bin_aqat*%s, fcfs_stack = %s
where name = %s
""", (mar, mar, mar, cstr(fstack), each[0]))
# Update item valuation in all sle after the reconcliation date
# ---------------------------------------------------------
def update_entries_post_date(self, d):
bin = sql("select name from `tabBin` where item_code = '%s' and warehouse = '%s'" % (d[self.label['item_code']], d[self.label['warehouse']]))
bin_obj = get_obj('Bin', bin[0][0])
# update valuation in sle posted after reconciliation datetime
bin_obj.update_entries_after(posting_date = self.doc.reconciliation_date, posting_time = self.doc.reconciliation_time)
# --------------
# make sl entry
# --------------
def make_sl_entry(self, update_stock, stock, diff):
values = []
values.append({
'item_code' : stock[self.label['item_code']],
'warehouse' : stock[self.label['warehouse']],
'transaction_date' : now(),
'posting_date' : self.doc.reconciliation_date,
'posting_time' : self.doc.reconciliation_time,
'voucher_type' : self.doc.doctype,
'voucher_no' : self.doc.name,
'voucher_detail_no' : self.doc.name,
'actual_qty' : flt(update_stock) * flt(diff),
'stock_uom' : stock[self.label['stock_uom']],
'incoming_rate' : stock[self.label['mar']] or 0,
'company' : self.doc.company,
'fiscal_year' : self.doc.fiscal_year,
'is_cancelled' : (update_stock==1) and 'No' or 'Yes',
'batch_no' : '',
'serial_no' : ''
})
get_obj('Stock Ledger', 'Stock Ledger').update_stock(values)
# -----------------------
# get stock reco details
# -----------------------
def get_reconciliation_stock_details(self,submit = 0):
import csv
stock = csv.reader(self.get_csv_file_data().splitlines())
stock = self.convert_into_list(stock, submit)
if stock[0][0] and stock[0][0].strip()=='Item Code':
stock.pop(0) # remove the labels
check = self.validate_data(stock)
if not check:
return 0
return stock
# validate date and time
# ------------------------
def validate_datetime(self):
if not self.doc.reconciliation_date:
msgprint("Please Enter Reconciliation Date.", raise_exception=1)
if not self.doc.reconciliation_time:
msgprint("Please Enter Reconciliation Time.", raise_exception=1)
# ----------------------
# stock reconciliations
# ----------------------
def stock_reconciliations(self, submit = 0):
self.validate_datetime()
# get reco data
rec_stock_detail = self.get_reconciliation_stock_details(submit) or []
if not rec_stock_detail:
msgprint("Please Check Remarks", raise_exception=1)
count = 1
for stock in rec_stock_detail:
count += 1
# Get qty as per system
cur_stock_detail = self.get_current_stock(stock[self.label['item_code']],stock[self.label['warehouse']])
stock.append(cur_stock_detail['stock_uom'])
stock.append(cur_stock_detail['actual_qty'])
# Qty Diff between file and system
diff = flt(stock[self.label['qty']]) - flt(cur_stock_detail['actual_qty'])
# Update MAR
if not stock[self.label['mar']] == '~':
self.update_mar(stock, diff)
# Make sl entry if qty differ
if diff:
self.make_sl_entry(submit, stock, diff)
if rec_stock_detail:
text = "Stock Reconciliation Completed Successfully..."
self.add_data_in_CSV(rec_stock_detail)
self.add_remark(text,'Completed', 0)
# Get csv data
#--------------------------
def get_csv_file_data(self):
"""Get csv data"""
filename = self.doc.file_list.split(',')
if not filename:
msgprint("Please Attach File. ", raise_exception=1)
@ -274,37 +27,160 @@ class DocType:
if not type(content) == str:
content = content.tostring()
return content
def convert_into_list(self, data):
"""Convert csv data into list"""
count = 1
for s in data:
if s[0].strip() != 'Item Code': # remove the labels
# validate
if len(s) != 4:
msgprint("Data entered at Row No " + cstr(count) + " in Attachment File is not in correct format.", raise_exception=1)
self.validated = 0
self.validate_item(s[0], count)
self.validate_warehouse(s[1], count)
# encode as ascii
self.data.append([d.encode("ascii") for d in s])
count += 1
if not self.validated:
raise Exception
def getCSVelement(self,v):
v = cstr(v)
if not v: return ''
if (',' in v) or ('' in v) or ('"' in v):
if '"' in v: v = v.replace('"', '""')
return '"'+v+'"'
else: return v or ''
# Add qty diff column in attached file
#----------------------------------------
def add_data_in_CSV(self,data):
filename = self.doc.file_list.split(',')
head = []
for h in ['Item Code','Warehouse','Qty','Actual','Difference','MAR']:
head.append(self.getCSVelement(h))
dset = (','.join(head) + "\n")
for d in data:
l = [d[self.label['item_code']],d[self.label['warehouse']],d[self.label['qty']],d[self.label['actual_qty']],flt(d[self.label['qty']])-flt(d[self.label['actual_qty']]),d[self.label['mar']]]
s =[]
for i in l:
s.append(self.getCSVelement(i))
dset +=(','.join(s)+"\n")
def get_reconciliation_data(self,submit = 0):
"""Read and validate csv data"""
import csv
data = csv.reader(self.get_csv_file_data().splitlines())
self.convert_into_list(data)
from webnotes.utils import file_manager
file_manager.write_file(filename[1], dset)
# ----------
# on submit
# ----------
def validate_item(self, item, count):
""" Validate item exists and non-serialized"""
det = sql("select item_code, has_serial_no from `tabItem` where name = '%s'"% cstr(item), as_dict = 1)
if not det:
msgprint("Item: " + cstr(item) + " mentioned at Row No. " + cstr(count) + "does not exist in the system")
self.validated = 0
elif det and det[0]['has_serial_no'] == 'Yes':
msgprint("""You cannot make Stock Reconciliation of items having serial no. \n
You can directly upload serial no to update their inventory. \n
Please remove Item Code : %s at Row No. %s""" %(cstr(item), cstr(count)))
self.validated = 0
def validate_warehouse(self, wh, count,):
"""Validate warehouse exists"""
if not sql("select name from `tabWarehouse` where name = '%s'" % cstr(wh)):
msgprint("Warehouse: " + cstr(wh) + " mentioned at Row No. " + cstr(count) + " does not exist in the system")
self.validated = 0
def validate(self):
"""Validate attachment data"""
#self.data = [['it', 'wh1', 20, 150]]
if self.doc.file_list:
self.get_reconciliation_data()
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 {}
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 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)
values = [{
'item_code' : row[0],
'warehouse' : row[1],
'transaction_date' : nowdate(),
'posting_date' : self.doc.reconciliation_date,
'posting_time' : self.doc.reconciliation_time,
'voucher_type' : self.doc.doctype,
'voucher_no' : self.doc.name,
'voucher_detail_no' : self.doc.name,
'actual_qty' : flt(is_submit) * flt(qty_diff),
'stock_uom' : sys_stock['stock_uom'],
'incoming_rate' : in_rate,
'company' : get_defaults()['company'],
'fiscal_year' : get_defaults()['fiscal_year'],
'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 do_stock_reco(self, is_submit = 1):
"""
Make stock entry of qty diff, calculate incoming rate to maintain valuation rate.
If no qty diff, but diff in valuation rate, make (+1,-1) entry to update valuation
"""
for row in self.data:
# Get qty as per system
sys_stock = self.get_system_stock(row[0],row[1])
# Diff between file and system
qty_diff = row[2] != '~' and flt(row[2]) - flt(sys_stock['actual_qty']) or 0
rate_diff = row[3] != '~' and flt(row[3]) - flt(sys_stock['val_rate']) or 0
# 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)
if is_submit == 1:
self.add_data_in_CSV(qty_diff, rate_diff)
msgprint("Stock Reconciliation Completed Successfully...")
def add_data_in_CSV(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'"
# 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)
def on_submit(self):
self.stock_reconciliations(submit = 1)
if not self.doc.file_list:
msgprint("Please attach file before submitting.", raise_exception=1)
else:
self.do_stock_reco(is_submit = 1)
def on_cancel(self):
self.validate()
self.do_stock_reco(is_submit = -1)

View File

@ -5,16 +5,18 @@
{
'creation': '2010-08-08 17:09:26',
'docstatus': 0,
'modified': '2011-04-25 11:46:21',
'modified': '2011-11-18 17:32:21',
'modified_by': 'Administrator',
'owner': 'Administrator'
},
# These values are common for all DocType
{
'_last_update': '1309508840',
'_last_update': '1321617633',
'allow_attach': 1,
'autoname': 'SR/.######',
'colour': 'White:FFF',
'default_print_format': 'Standard',
'doctype': 'DocType',
'max_attachments': 1,
'module': 'Stock',
@ -23,7 +25,8 @@
'section_style': 'Tray',
'server_code_error': ' ',
'show_in_menu': 0,
'version': 85
'subject': 'Date: %(reconciliation_date)s, Time: %(reconciliation_time)s',
'version': 105
},
# These values are common for all DocField
@ -37,6 +40,7 @@
# These values are common for all DocPerm
{
'amend': 0,
'doctype': 'DocPerm',
'name': '__common__',
'parent': 'Stock Reconciliation',
@ -53,11 +57,9 @@
# DocPerm
{
'amend': 1,
'cancel': 1,
'create': 1,
'doctype': 'DocPerm',
'idx': 1,
'permlevel': 0,
'role': 'Material Manager',
'submit': 1,
@ -66,11 +68,9 @@
# DocPerm
{
'amend': 0,
'cancel': 0,
'create': 0,
'doctype': 'DocPerm',
'idx': 2,
'permlevel': 1,
'role': 'Material Manager',
'submit': 0,
@ -79,44 +79,21 @@
# DocPerm
{
'amend': 1,
'cancel': 1,
'create': 1,
'doctype': 'DocPerm',
'idx': 3,
'permlevel': 0,
'role': 'System Manager',
'submit': 1,
'write': 1
},
# DocPerm
{
'doctype': 'DocPerm',
'idx': 4,
'permlevel': 1,
'role': 'System Manager'
},
# DocField
{
'doctype': 'DocField',
'fieldtype': 'Button',
'hidden': 1,
'idx': 1,
'label': 'Validate Data',
'oldfieldtype': 'Button',
'options': 'get_reconciliation_stock_details',
'permlevel': 0
},
# DocField
{
'doctype': 'DocField',
'fieldtype': 'Section Break',
'idx': 2,
'label': 'Summary',
'oldfieldtype': 'Section Break',
'fieldtype': 'HTML',
'label': 'Steps',
'options': '<div class="field_description"><b>Steps:</b><br>1. Enter Reconciliation Date and Time<br>2. Save the document<br>3. Attach csv file as per template.<br>4. Submit the document</div>',
'permlevel': 0
},
@ -125,14 +102,12 @@
'doctype': 'DocField',
'fieldname': 'reconciliation_date',
'fieldtype': 'Date',
'idx': 3,
'in_filter': 0,
'label': 'Reconciliation Date',
'oldfieldname': 'reconciliation_date',
'oldfieldtype': 'Date',
'permlevel': 0,
'reqd': 1,
'search_index': 1
'reqd': 1
},
# DocField
@ -140,7 +115,6 @@
'doctype': 'DocField',
'fieldname': 'reconciliation_time',
'fieldtype': 'Time',
'idx': 4,
'in_filter': 0,
'label': 'Reconciliation Time',
'oldfieldname': 'reconciliation_time',
@ -149,100 +123,23 @@
'reqd': 1
},
# DocField
{
'doctype': 'DocField',
'fieldname': 'next_step',
'fieldtype': 'Select',
'idx': 5,
'label': 'Next Steps',
'oldfieldname': 'next_step',
'oldfieldtype': 'Select',
'options': 'Upload File and Save Document\nValidate Data\nSubmit Document\nCompleted',
'permlevel': 1
},
# DocField
{
'doctype': 'DocField',
'fieldname': 'remark',
'fieldtype': 'Text',
'idx': 6,
'label': 'Remark',
'oldfieldname': 'remark',
'oldfieldtype': 'Text',
'permlevel': 1
},
# DocField
{
'doctype': 'DocField',
'fieldname': 'company',
'fieldtype': 'Link',
'idx': 7,
'in_filter': 1,
'label': 'Company',
'oldfieldname': 'company',
'oldfieldtype': 'Link',
'options': 'Company',
'permlevel': 0,
'search_index': 0
},
# DocField
{
'doctype': 'DocField',
'fieldname': 'fiscal_year',
'fieldtype': 'Select',
'idx': 8,
'in_filter': 1,
'label': 'Fiscal Year',
'oldfieldname': 'fiscal_year',
'oldfieldtype': 'Select',
'options': 'link:Fiscal Year',
'permlevel': 0,
'search_index': 0
},
# DocField
{
'doctype': 'DocField',
'fieldname': 'amended_from',
'fieldtype': 'Data',
'idx': 9,
'label': 'Amended From',
'permlevel': 1
},
# DocField
{
'doctype': 'DocField',
'fieldname': 'amendment_date',
'fieldtype': 'Date',
'idx': 10,
'label': 'Amendment Date',
'permlevel': 1
},
# DocField
{
'doctype': 'DocField',
'fieldtype': 'Section Break',
'idx': 11,
'label': 'Attachment',
'oldfieldtype': 'Section Break',
'permlevel': 0
},
# DocField
{
'doctype': 'DocField',
'fieldtype': 'HTML',
'idx': 12,
'label': 'Attachment HTML',
'oldfieldtype': 'HTML',
'options': 'The attachment must be a CSV(Comma Seperated Value) file',
'permlevel': 1
'fieldtype': 'Button',
'label': 'Download Template',
'permlevel': 0
},
# DocField
@ -251,8 +148,8 @@
'fieldname': 'file_list',
'fieldtype': 'Text',
'hidden': 1,
'idx': 13,
'label': 'File List',
'no_copy': 1,
'oldfieldname': 'file_list',
'oldfieldtype': 'Text',
'permlevel': 1,