blob: d1e00970c2d9d05fb401549ee89738963a8e1ab3 [file] [log] [blame]
Nabin Hait31665e52011-09-29 10:41:02 +05301import unittest
2
3import webnotes
4import webnotes.profile
5webnotes.user = webnotes.profile.Profile()
6
7
8from webnotes.model.doc import Document
9from webnotes.model.code import get_obj
10from webnotes.utils import cstr, flt
Nabin Hait88f9cb52011-09-30 17:20:06 +053011from webnotes.model.doclist import getlist
Nabin Hait31665e52011-09-29 10:41:02 +053012sql = webnotes.conn.sql
13
14from sandbox.testdata.masters import *
15from sandbox.testdata import stock_entry
16#----------------------------------------------------------
17
Nabin Hait88f9cb52011-09-30 17:20:06 +053018
Nabin Hait31665e52011-09-29 10:41:02 +053019class TestStockEntry(unittest.TestCase):
Nabin Hait88f9cb52011-09-30 17:20:06 +053020 #===========================================================================
21 def assertDoc(self, lst):
22 """assert all values"""
23 for d in lst:
24 cl, vl = [], []
25 for k in d.keys():
26 if k!='doctype':
27 cl.append('%s=%s' % (k, '%s'))
28 vl.append(d[k])
29
30 self.assertTrue(sql("select name from `tab%s` where %s limit 1" % (d['doctype'], ' and '.join(cl)), vl))
31
32 #===========================================================================
33 def assertCount(self, lst):
34 """assert all values"""
35 for d in lst:
36 cl, vl = [], []
37 for k in d[0].keys():
38 if k!='doctype':
39 cl.append('%s=%s' % (k, '%s'))
40 vl.append(d[0][k])
41
42 self.assertTrue(sql("select count(name) from `tab%s` where %s limit 1" % (d[0]['doctype'], ' and '.join(cl)), vl)[0][0] == d[1])
43
44 #===========================================================================
Nabin Hait31665e52011-09-29 10:41:02 +053045 def setUp(self):
46 print "====================================="
Nabin Hait88f9cb52011-09-30 17:20:06 +053047 webnotes.conn.begin()
Nabin Hait31665e52011-09-29 10:41:02 +053048 create_master_records()
49 print 'Master Data Created'
50
Nabin Hait88f9cb52011-09-30 17:20:06 +053051 #===========================================================================
52 # Purpose: Material Receipt
53 #===========================================================================
54 def test_mr_onsubmit(self):
Nabin Haita970b112011-09-30 18:05:08 +053055 print "Test Case: Material Receipt submission"
Nabin Hait88f9cb52011-09-30 17:20:06 +053056 self.save_stock_entry('Material Receipt')
57
58 mr = get_obj('Stock Entry', stock_entry.mr[0].name, with_children=1)
59 self.submit_stock_entry(mr)
60
61 # stock ledger entry
62 print "Checking stock ledger entry........."
63 self.assertDoc(self.get_expected_sle('mr_submit'))
64
65 # bin qty
66 print "Checking Bin qty........."
67 self.assertDoc([{'doctype':'Bin', 'actual_qty':10, 'item_code':'it', 'warehouse':'wh1'}])
68
69 # serial no
70 self.assertCount([[{'doctype': 'Serial No', 'item_code': 'it', 'warehouse': 'wh1', 'status': 'In Store', 'docstatus': 0}, 10]])
71
72
73 #===========================================================================
74 def test_mr_oncancel(self):
Nabin Haita970b112011-09-30 18:05:08 +053075 print "Test Case: Material Receipt Cancellation"
Nabin Hait88f9cb52011-09-30 17:20:06 +053076 self.save_stock_entry('Material Receipt')
77
78 mr = get_obj('Stock Entry', stock_entry.mr[0].name, with_children=1)
79 self.cancel_stock_entry(mr)
80
81 # stock ledger entry
82 print "Checking stock ledger entry........."
83 self.assertDoc(self.get_expected_sle('mr_cancel'))
84
85 # bin qty
86 print "Checking Bin qty........."
87 self.assertDoc([{'doctype':'Bin', 'actual_qty':0, 'item_code':'it', 'warehouse':'wh1'}])
88
89 # serial no
90 self.assertCount([[{'doctype': 'Serial No', 'item_code': 'it', 'warehouse': '', 'status': 'Not in Use', 'docstatus': 2}, 10]])
91
92 #===========================================================================
93 # Purpose: Material Transafer
94 #===========================================================================
95 def test_mtn_onsubmit(self):
Nabin Haita970b112011-09-30 18:05:08 +053096 print "Test Case: Material Transfer Note submission"
Nabin Hait88f9cb52011-09-30 17:20:06 +053097
98 self.save_stock_entry('Material Receipt')
99 mr = get_obj('Stock Entry', stock_entry.mr[0].name, with_children=1)
100 mr = self.submit_stock_entry(mr)
101
102 self.save_stock_entry('Material Transfer')
103 mtn = get_obj('Stock Entry', stock_entry.mtn[0].name, with_children=1)
Nabin Hait2cca0e72011-11-09 12:12:53 +0530104 mtn = self.submit_stock_entry(mtn)
Nabin Hait88f9cb52011-09-30 17:20:06 +0530105
106 # stock ledger entry
107 print "Checking stock ledger entry........."
108 self.assertDoc(self.get_expected_sle('mtn_submit'))
109
110 # bin qty
111 print "Checking Bin qty........."
112 self.assertDoc([
113 {'doctype':'Bin', 'actual_qty':5, 'item_code':'it', 'warehouse':'wh1'},
114 {'doctype':'Bin', 'actual_qty':5, 'item_code':'it', 'warehouse':'wh2'}
115 ])
116
117 # serial no
118 self.assertCount([
119 [{'doctype': 'Serial No', 'item_code': 'it', 'warehouse': 'wh1', 'status': 'In Store', 'docstatus': 0}, 5],
120 [{'doctype': 'Serial No', 'item_code': 'it', 'warehouse': 'wh2', 'status': 'In Store', 'docstatus': 0}, 5]
121 ])
122
123 #===========================================================================
124 def test_mtn_oncancel(self):
Nabin Haita970b112011-09-30 18:05:08 +0530125 print "Test Case: Material Transfer Note Cancellation"
Nabin Hait88f9cb52011-09-30 17:20:06 +0530126
127 self.save_stock_entry('Material Receipt')
128 mr = get_obj('Stock Entry', stock_entry.mr[0].name, with_children=1)
129 mr = self.submit_stock_entry(mr)
130
131 self.save_stock_entry('Material Transfer')
132 mtn = get_obj('Stock Entry', stock_entry.mtn[0].name, with_children=1)
133 self.cancel_stock_entry(mtn)
134
135 # stock ledger entry
136 print "Checking stock ledger entry........."
137 self.assertDoc(self.get_expected_sle('mtn_cancel'))
138
139 # bin qty
140 print "Checking Bin qty........."
141 self.assertDoc([
142 {'doctype':'Bin', 'actual_qty':10, 'item_code':'it', 'warehouse':'wh1'},
143 {'doctype':'Bin', 'actual_qty':0, 'item_code':'it', 'warehouse':'wh2'}
144 ])
145
146 # serial no
147 self.assertCount([[{'doctype': 'Serial No', 'item_code': 'it', 'warehouse': 'wh1', 'status': 'In Store', 'docstatus': 0}, 10]])
Nabin Haita970b112011-09-30 18:05:08 +0530148
149#===========================================================================
150 # Purpose: Material Issue
151 #===========================================================================
152 def test_mi_onsubmit(self):
153 print "Test Case: Material Issue submission"
154
155 self.save_stock_entry('Material Receipt')
156 mr = get_obj('Stock Entry', stock_entry.mr[0].name, with_children=1)
157 mr = self.submit_stock_entry(mr)
158
159 self.save_stock_entry('Material Issue')
160 mi = get_obj('Stock Entry', stock_entry.mi[0].name, with_children=1)
161 mi = self.submit_stock_entry(mi)
162
163 # stock ledger entry
164 print "Checking stock ledger entry........."
165 self.assertDoc(self.get_expected_sle('mi_submit'))
166
167 # bin qty
168 print "Checking Bin qty........."
169 self.assertDoc([
170 {'doctype':'Bin', 'actual_qty':6, 'item_code':'it', 'warehouse':'wh1'}
171 ])
172
173 # serial no
174 self.assertCount([
175 [{'doctype': 'Serial No', 'item_code': 'it', 'warehouse': 'wh1', 'status': 'In Store', 'docstatus': 0}, 6]
176 ])
177
178 #===========================================================================
179 def test_mi_oncancel(self):
180 print "Test Case: Material Issue Cancellation"
181
182 self.save_stock_entry('Material Receipt')
183 mr = get_obj('Stock Entry', stock_entry.mr[0].name, with_children=1)
184 mr = self.submit_stock_entry(mr)
185
186 self.save_stock_entry('Material Issue')
187 mi = get_obj('Stock Entry', stock_entry.mi[0].name, with_children=1)
188 self.cancel_stock_entry(mi)
189
190 # stock ledger entry
191 print "Checking stock ledger entry........."
192 self.assertDoc(self.get_expected_sle('mi_cancel'))
193
194 # bin qty
195 print "Checking Bin qty........."
196 self.assertDoc([
197 {'doctype':'Bin', 'actual_qty':10, 'item_code':'it', 'warehouse':'wh1'}
198 ])
199
200 # serial no
201 self.assertCount([
202 [{'doctype': 'Serial No', 'item_code': 'it', 'warehouse': 'wh1', 'status': 'In Store', 'docstatus': 0}, 10]
203 ])
204
Nabin Hait2cca0e72011-11-09 12:12:53 +0530205 #===========================================================================
206 def test_entries_on_same_datetime(self):
207 print "Test Case: Multiple entries on same datetime, cancel first one"
Nabin Haita970b112011-09-30 18:05:08 +0530208
Nabin Hait2cca0e72011-11-09 12:12:53 +0530209 # submitted 1st MR
210 self.save_stock_entry('Material Receipt')
211 mr = get_obj('Stock Entry', stock_entry.mr[0].name, with_children=1)
212 mr = self.submit_stock_entry(mr)
213
214 # submitted 2nd MR
215 for each in stock_entry.mr1:
216 each.save(1)
217 for t in stock_entry.mr1[1:]:
218 sql("update `tabStock Entry Detail` set parent = '%s' where name = '%s'" % (stock_entry.mr1[0].name, t.name))
219
220 mr1 = get_obj('Stock Entry', stock_entry.mr1[0].name, with_children=1)
221 mr1 = self.submit_stock_entry(mr1)
Nabin Hait88f9cb52011-09-30 17:20:06 +0530222
Nabin Hait2cca0e72011-11-09 12:12:53 +0530223
224 # submitted MTN
225 self.save_stock_entry('Material Transfer')
226 mtn = get_obj('Stock Entry', stock_entry.mtn[0].name, with_children=1)
227 mtn = self.submit_stock_entry(mtn)
228
229 # cancel prev MR
230 mr.on_cancel()
231 mr.doc.cancel_reason = "testing"
232 mr.doc.docstatus = 2
233 mr.doc.save()
234
235
236 # stock ledger entry
237 print "Checking stock ledger entry........."
238 self.assertDoc(self.get_expected_sle('entries_on_same_datetime'))
239
240 # bin qty
241 print "Checking Bin qty........."
242 self.assertDoc([
243 {'doctype':'Bin', 'actual_qty':0, 'item_code':'it', 'warehouse':'wh1'},
244 {'doctype':'Bin', 'actual_qty':5, 'item_code':'it', 'warehouse':'wh2'}
245 ])
246
247 # serial no
248 self.assertCount([
249 [{'doctype': 'Serial No', 'item_code': 'it', 'warehouse': 'wh1', 'status': 'In Store', 'docstatus': 0}, 0],
250 [{'doctype': 'Serial No', 'item_code': 'it', 'warehouse': 'wh2', 'status': 'In Store', 'docstatus': 0}, 5]
251 ])
252
Nabin Hait88f9cb52011-09-30 17:20:06 +0530253 #===========================================================================
254 def save_stock_entry(self, t):
255 if t == 'Material Receipt':
256 data = stock_entry.mr
257 elif t == 'Material Transfer':
258 data = stock_entry.mtn
Nabin Haita970b112011-09-30 18:05:08 +0530259 elif t == 'Material Issue':
260 data = stock_entry.mi
Nabin Hait88f9cb52011-09-30 17:20:06 +0530261
262 for each in data:
Nabin Hait31665e52011-09-29 10:41:02 +0530263 each.save(1)
264
Nabin Hait88f9cb52011-09-30 17:20:06 +0530265 for t in data[1:]:
266 sql("update `tabStock Entry Detail` set parent = '%s' where name = '%s'" % (data[0].name, t.name))
Nabin Hait31665e52011-09-29 10:41:02 +0530267 print "Stock Entry Created"
268
Nabin Hait31665e52011-09-29 10:41:02 +0530269
270 #===========================================================================
Nabin Hait88f9cb52011-09-30 17:20:06 +0530271 def submit_stock_entry(self, ste):
272 ste.validate()
273 ste.on_submit()
Nabin Hait31665e52011-09-29 10:41:02 +0530274
Nabin Hait88f9cb52011-09-30 17:20:06 +0530275 ste.doc.docstatus = 1
276 ste.doc.save()
277
Nabin Hait31665e52011-09-29 10:41:02 +0530278 print "Stock Entry Submitted"
Nabin Hait88f9cb52011-09-30 17:20:06 +0530279 return ste
Nabin Hait31665e52011-09-29 10:41:02 +0530280
281 #===========================================================================
Nabin Hait88f9cb52011-09-30 17:20:06 +0530282 def cancel_stock_entry(self, ste):
283 ste = self.submit_stock_entry(ste)
Nabin Hait31665e52011-09-29 10:41:02 +0530284
Nabin Hait88f9cb52011-09-30 17:20:06 +0530285 ste.on_cancel()
Nabin Hait31665e52011-09-29 10:41:02 +0530286
Nabin Hait88f9cb52011-09-30 17:20:06 +0530287 ste.doc.cancel_reason = "testing"
288 ste.doc.docstatus = 2
289 ste.doc.save()
Nabin Hait31665e52011-09-29 10:41:02 +0530290
291 print "Stock Entry Cancelled"
Nabin Hait88f9cb52011-09-30 17:20:06 +0530292 return ste
Nabin Hait31665e52011-09-29 10:41:02 +0530293
294 #===========================================================================
Nabin Hait31665e52011-09-29 10:41:02 +0530295 def tearDown(self):
296 webnotes.conn.rollback()
Nabin Hait88f9cb52011-09-30 17:20:06 +0530297
298
299 # Expected Result Set
300 #===================================================================================================
301 def get_expected_sle(self, action):
302 expected_sle = {
303 'mr_submit': [{
304 'doctype': 'Stock Ledger Entry',
305 'item_code':'it',
306 'warehouse':'wh1',
307 'voucher_type': 'Stock Entry',
308 'voucher_no': stock_entry.mr[0].name,
309 'actual_qty': 10,
310 'bin_aqat': 10,
311 'valuation_rate': 100,
312 'is_cancelled': 'No'
313 }],
314 'mr_cancel': [{
315 'doctype': 'Stock Ledger Entry',
316 'item_code':'it',
317 'warehouse':'wh1',
318 'voucher_type': 'Stock Entry',
319 'voucher_no': stock_entry.mr[0].name,
320 'actual_qty': 10,
321 'bin_aqat': 10,
322 'valuation_rate': 100,
323 'is_cancelled': 'Yes'
324 },{
325 'doctype': 'Stock Ledger Entry',
326 'item_code':'it',
327 'warehouse':'wh1',
328 'voucher_type': 'Stock Entry',
329 'voucher_no': stock_entry.mr[0].name,
330 'actual_qty': -10,
331 'ifnull(bin_aqat, 0)': 0,
332 'ifnull(valuation_rate, 0)': 0,
333 "ifnull(is_cancelled, 'No')": 'Yes'
334 }],
335 'mtn_submit': [{
336 'doctype': 'Stock Ledger Entry',
337 'item_code':'it',
338 'warehouse':'wh1',
339 'voucher_type': 'Stock Entry',
340 'voucher_no': stock_entry.mtn[0].name,
341 'actual_qty': -5,
342 'bin_aqat': 5,
343 'valuation_rate': 100,
344 'is_cancelled': 'No'
345 }, {
346 'doctype': 'Stock Ledger Entry',
347 'item_code':'it',
348 'warehouse':'wh2',
349 'voucher_type': 'Stock Entry',
350 'voucher_no': stock_entry.mtn[0].name,
351 'actual_qty': 5,
352 'bin_aqat': 5,
353 'valuation_rate': 100,
354 'is_cancelled': 'No'
355 }],
356 'mtn_cancel': [{
357 'doctype': 'Stock Ledger Entry',
358 'item_code':'it',
359 'warehouse':'wh1',
360 'voucher_type': 'Stock Entry',
361 'voucher_no': stock_entry.mtn[0].name,
362 'actual_qty': -5,
363 'bin_aqat': 5,
Nabin Hait88f9cb52011-09-30 17:20:06 +0530364 'is_cancelled': 'Yes'
365 }, {
366 'doctype': 'Stock Ledger Entry',
367 'item_code':'it',
368 'warehouse':'wh2',
369 'voucher_type': 'Stock Entry',
370 'voucher_no': stock_entry.mtn[0].name,
371 'actual_qty': 5,
372 'bin_aqat': 5,
373 'valuation_rate': 100,
374 'is_cancelled': 'Yes'
375 }, {
376 'doctype': 'Stock Ledger Entry',
377 'item_code':'it',
378 'warehouse':'wh1',
379 'voucher_type': 'Stock Entry',
380 'voucher_no': stock_entry.mtn[0].name,
381 'actual_qty': 5,
Nabin Hait88f9cb52011-09-30 17:20:06 +0530382 'is_cancelled': 'Yes'
383 }, {
384 'doctype': 'Stock Ledger Entry',
385 'item_code':'it',
386 'warehouse':'wh2',
387 'voucher_type': 'Stock Entry',
388 'voucher_no': stock_entry.mtn[0].name,
389 'actual_qty': -5,
Nabin Hait88f9cb52011-09-30 17:20:06 +0530390 'is_cancelled': 'Yes'
Nabin Haita970b112011-09-30 18:05:08 +0530391 }],
392 'mi_submit': [{'doctype': 'Stock Ledger Entry',
393 'item_code':'it',
394 'warehouse':'wh1',
395 'voucher_type': 'Stock Entry',
396 'voucher_no': stock_entry.mi[0].name,
397 'actual_qty': -4,
398 'bin_aqat': 6,
399 'valuation_rate': 100,
400 'is_cancelled': 'No'
401 }],
402 'mi_cancel': [{
403 'doctype': 'Stock Ledger Entry',
404 'item_code':'it',
405 'warehouse':'wh1',
406 'voucher_type': 'Stock Entry',
407 'voucher_no': stock_entry.mi[0].name,
408 'actual_qty': -4,
409 'bin_aqat': 6,
410 'valuation_rate': 100,
411 'is_cancelled': 'Yes'
412 },{
413 'doctype': 'Stock Ledger Entry',
414 'item_code':'it',
415 'warehouse':'wh1',
416 'voucher_type': 'Stock Entry',
417 'voucher_no': stock_entry.mi[0].name,
418 'actual_qty': 4,
419 'ifnull(bin_aqat, 0)': 0,
420 'ifnull(valuation_rate, 0)': 0,
421 "ifnull(is_cancelled, 'No')": 'Yes'
Nabin Hait2cca0e72011-11-09 12:12:53 +0530422 }],
423 'entries_on_same_datetime': [{
424 'doctype': 'Stock Ledger Entry',
425 'item_code':'it',
426 'warehouse':'wh1',
427 'voucher_type': 'Stock Entry',
428 'voucher_no': stock_entry.mr[0].name,
429 'actual_qty': 10,
430 'bin_aqat': 10,
431 'valuation_rate': 100,
432 'is_cancelled': 'Yes'
433 }, {
434 'doctype': 'Stock Ledger Entry',
435 'item_code':'it',
436 'warehouse':'wh1',
437 'voucher_type': 'Stock Entry',
438 'voucher_no': stock_entry.mr[0].name,
439 'actual_qty': -10,
440 'ifnull(bin_aqat, 0)': 0,
441 'ifnull(valuation_rate, 0)': 0,
442 "ifnull(is_cancelled, 'No')": 'Yes'
443 }, {
444 'doctype': 'Stock Ledger Entry',
445 'item_code':'it',
446 'warehouse':'wh1',
447 'voucher_type': 'Stock Entry',
448 'voucher_no': stock_entry.mr1[0].name,
449 'actual_qty': 5,
450 'bin_aqat': 5,
451 'valuation_rate': 400,
452 'is_cancelled': 'No'
453 }, {
454 'doctype': 'Stock Ledger Entry',
455 'item_code':'it',
456 'warehouse':'wh1',
457 'voucher_type': 'Stock Entry',
458 'voucher_no': stock_entry.mtn[0].name,
459 'actual_qty': -5,
460 'bin_aqat': 0,
461 'valuation_rate': 400,
462 'is_cancelled': 'No'
463 }, {
464 'doctype': 'Stock Ledger Entry',
465 'item_code':'it',
466 'warehouse':'wh2',
467 'voucher_type': 'Stock Entry',
468 'voucher_no': stock_entry.mtn[0].name,
469 'actual_qty': 5,
470 'bin_aqat': 5,
471 'valuation_rate': 100,
472 'is_cancelled': 'No'
Nabin Hait88f9cb52011-09-30 17:20:06 +0530473 }]
474 }
475
476 return expected_sle[action]