completed sales purchase return as part of stock entry
This commit is contained in:
		
							parent
							
								
									6230aa9292
								
							
						
					
					
						commit
						ab7b7c2974
					
				| @ -133,7 +133,7 @@ class DocType(SellingController): | |||||||
| 		super(DocType, self).validate() | 		super(DocType, self).validate() | ||||||
| 		 | 		 | ||||||
| 		import utilities | 		import utilities | ||||||
| 		utilities.validate_status(self.doc.status, ["Draft", "submitted", "Cancelled"]) | 		utilities.validate_status(self.doc.status, ["Draft", "Submitted", "Cancelled"]) | ||||||
| 
 | 
 | ||||||
| 		self.so_required() | 		self.so_required() | ||||||
| 		self.validate_fiscal_year() | 		self.validate_fiscal_year() | ||||||
|  | |||||||
| @ -60,6 +60,7 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({ | |||||||
| 	}, | 	}, | ||||||
| 	 | 	 | ||||||
| 	refresh: function() { | 	refresh: function() { | ||||||
|  | 		var me = this; | ||||||
| 		erpnext.hide_naming_series(); | 		erpnext.hide_naming_series(); | ||||||
| 		this.toggle_related_fields(this.frm.doc); | 		this.toggle_related_fields(this.frm.doc); | ||||||
| 		this.toggle_enable_bom(); | 		this.toggle_enable_bom(); | ||||||
| @ -67,12 +68,13 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({ | |||||||
| 			this.show_stock_ledger(); | 			this.show_stock_ledger(); | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		if(this.frm.doc.docstatus === 1 && wn.boot.profile.can_create("Journal Voucher")) { | 		if(this.frm.doc.docstatus === 1 &&  | ||||||
|  | 				wn.boot.profile.can_create.indexOf("Journal Voucher")!==-1) { | ||||||
| 			if(this.frm.doc.purpose === "Sales Return") { | 			if(this.frm.doc.purpose === "Sales Return") { | ||||||
| 				this.frm.add_custom_button("Make Credit Note", this.make_return_jv); | 				this.frm.add_custom_button("Make Credit Note", function() { me.make_return_jv(); }); | ||||||
| 				this.add_excise_button(); | 				this.add_excise_button(); | ||||||
| 			} else if(this.frm.doc.purpose === "Purchase Return") { | 			} else if(this.frm.doc.purpose === "Purchase Return") { | ||||||
| 				this.frm.add_custom_button("Make Debit Note", this.make_return_jv); | 				this.frm.add_custom_button("Make Debit Note", function() { me.make_return_jv(); }); | ||||||
| 				this.add_excise_button(); | 				this.add_excise_button(); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @ -172,8 +174,17 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({ | |||||||
| 				stock_entry: this.frm.doc.name | 				stock_entry: this.frm.doc.name | ||||||
| 			}, | 			}, | ||||||
| 			callback: function(r) { | 			callback: function(r) { | ||||||
| 				console.log(r); | 				if(!r.exc) { | ||||||
| 				loaddoc("Journal Voucher", r.message); | 					var jv_name = wn.model.make_new_doc_and_get_name('Journal Voucher'); | ||||||
|  | 					var jv = locals["Journal Voucher"][jv_name]; | ||||||
|  | 					$.extend(jv, r.message[0]); | ||||||
|  | 					$.each(r.message.slice(1), function(i, jvd) { | ||||||
|  | 						var child = wn.model.add_child(jv, "Journal Voucher Detail", "entries"); | ||||||
|  | 						$.extend(child, jvd); | ||||||
|  | 					}); | ||||||
|  | 					loaddoc("Journal Voucher", jv_name); | ||||||
|  | 				} | ||||||
|  | 				 | ||||||
| 			} | 			} | ||||||
| 		}); | 		}); | ||||||
| 	}, | 	}, | ||||||
|  | |||||||
| @ -25,7 +25,6 @@ from webnotes import msgprint, _ | |||||||
| from stock.utils import get_incoming_rate | from stock.utils import get_incoming_rate | ||||||
| from stock.stock_ledger import get_previous_sle | from stock.stock_ledger import get_previous_sle | ||||||
| import json | import json | ||||||
| from accounts.utils import get_balance_on |  | ||||||
| 
 | 
 | ||||||
| sql = webnotes.conn.sql | sql = webnotes.conn.sql | ||||||
| 
 | 
 | ||||||
| @ -297,7 +296,7 @@ class DocType(AccountsController): | |||||||
| 			 | 			 | ||||||
| 			# posting date check | 			# posting date check | ||||||
| 			ref_posting_datetime = "%s %s" % (cstr(ref.doclist[0].posting_date),  | 			ref_posting_datetime = "%s %s" % (cstr(ref.doclist[0].posting_date),  | ||||||
| 				cstr(ref.doclist[0].posting_time)) | 				cstr(ref.doclist[0].posting_time) or "00:00:00") | ||||||
| 			this_posting_datetime = "%s %s" % (cstr(self.doc.posting_date),  | 			this_posting_datetime = "%s %s" % (cstr(self.doc.posting_date),  | ||||||
| 				cstr(self.doc.posting_time)) | 				cstr(self.doc.posting_time)) | ||||||
| 			if this_posting_datetime < ref_posting_datetime: | 			if this_posting_datetime < ref_posting_datetime: | ||||||
| @ -779,13 +778,30 @@ def make_return_jv(stock_entry): | |||||||
| 		result = make_return_jv_from_purchase_receipt(se, ref) | 		result = make_return_jv_from_purchase_receipt(se, ref) | ||||||
| 	 | 	 | ||||||
| 	# create jv doclist and fetch balance for each unique row item | 	# create jv doclist and fetch balance for each unique row item | ||||||
|  | 	jv_list = [{ | ||||||
|  | 		"__islocal": 1, | ||||||
|  | 		"doctype": "Journal Voucher", | ||||||
|  | 		"posting_date": se.doc.posting_date, | ||||||
|  | 		"voucher_type": se.doc.purpose == "Sales Return" and "Credit Note" or "Debit Note", | ||||||
|  | 		"fiscal_year": se.doc.fiscal_year, | ||||||
|  | 		"company": se.doc.company | ||||||
|  | 	}] | ||||||
| 	 | 	 | ||||||
| 	if not webnotes.response.get("docs"): | 	from accounts.utils import get_balance_on | ||||||
| 		webnotes.response["docs"] = [] | 	for r in result: | ||||||
|  | 		jv_list.append({ | ||||||
|  | 			"__islocal": 1, | ||||||
|  | 			"doctype": "Journal Voucher Detail", | ||||||
|  | 			"parentfield": "entries", | ||||||
|  | 			"account": r.get("account"), | ||||||
|  | 			"debit": r.get("debit"), | ||||||
|  | 			"credit": r.get("credit"), | ||||||
|  | 			"against_invoice": r.get("against_invoice"), | ||||||
|  | 			"against_voucher": r.get("against_voucher"), | ||||||
|  | 			"balance": get_balance_on(r.get("account"), se.doc.posting_date) | ||||||
|  | 		}) | ||||||
| 		 | 		 | ||||||
| 	webnotes.response["docs"] = jv.doclist | 	return jv_list | ||||||
| 	 |  | ||||||
| 	return jv.doc.name |  | ||||||
| 	 | 	 | ||||||
| def make_return_jv_from_sales_invoice(se, ref): | def make_return_jv_from_sales_invoice(se, ref): | ||||||
| 	# customer account entry | 	# customer account entry | ||||||
| @ -833,12 +849,10 @@ def make_return_jv_from_delivery_note(se, ref): | |||||||
| 		ref.doclist[0].name) | 		ref.doclist[0].name) | ||||||
| 	 | 	 | ||||||
| 	if not invoices_against_delivery: | 	if not invoices_against_delivery: | ||||||
| 		item_codes = [item.item_code for item in se.doclist.get({"parentfield": "mtn_details"})] | 		sales_orders_against_delivery = [d.prevdoc_docname for d in  | ||||||
| 		sales_orders_against_delivery = [d.prev_docname for d in  | 			ref.doclist.get({"prevdoc_doctype": "Sales Order"}) if d.prevdoc_docname] | ||||||
| 			ref.doclist.get({"prev_doctype": "Sales Order"})  |  | ||||||
| 			if d.prev_docname and d.item_code in item_codes] |  | ||||||
| 		 | 		 | ||||||
| 		invoices_against_delivery = get_invoice_list("Sales Order Item", "sales_order", | 		invoices_against_delivery = get_invoice_list("Sales Invoice Item", "sales_order", | ||||||
| 			sales_orders_against_delivery) | 			sales_orders_against_delivery) | ||||||
| 	 | 	 | ||||||
| 	against_invoice = {} | 	against_invoice = {} | ||||||
| @ -846,8 +860,10 @@ def make_return_jv_from_delivery_note(se, ref): | |||||||
| 	for se_item in se.doclist.get({"parentfield": "mtn_details"}): | 	for se_item in se.doclist.get({"parentfield": "mtn_details"}): | ||||||
| 		pending = se_item.transfer_qty | 		pending = se_item.transfer_qty | ||||||
| 		for sales_invoice in invoices_against_delivery: | 		for sales_invoice in invoices_against_delivery: | ||||||
| 			si_doclist = webnotes.get_doclist("Sales Invoice", sales_invoice) | 			si = webnotes.bean("Sales Invoice", sales_invoice) | ||||||
| 			ref_item = si_doclist.get({"item_code": se_item.item_code}) | 			si.run_method("make_packing_list") | ||||||
|  | 			ref_item = si.doclist.get({"item_code": se_item.item_code}) | ||||||
|  | 			 | ||||||
| 			if not ref_item: | 			if not ref_item: | ||||||
| 				continue | 				continue | ||||||
| 			 | 			 | ||||||
| @ -860,12 +876,12 @@ def make_return_jv_from_delivery_note(se, ref): | |||||||
| 				transfer_qty = pending | 				transfer_qty = pending | ||||||
| 				pending = 0 | 				pending = 0 | ||||||
| 			 | 			 | ||||||
| 			account, debit = get_sales_account_and_amount_from_item(si_doclist, ref_item, | 			account, debit = get_sales_account_and_amount_from_item(si.doclist, ref_item, | ||||||
| 				transfer_qty) | 				transfer_qty) | ||||||
| 				 | 				 | ||||||
| 			if si_doclist[0].name not in against_invoice: | 			if si.doclist[0].name not in against_invoice: | ||||||
| 				against_invoice[sales_invoice] = { | 				against_invoice[sales_invoice] = { | ||||||
| 					"parent": {"account": si_doclist[0].debit_to, "credit": 0}, | 					"parent": {"account": si.doclist[0].debit_to, "credit": 0}, | ||||||
| 					"children": {} | 					"children": {} | ||||||
| 				} | 				} | ||||||
| 				 | 				 | ||||||
| @ -883,8 +899,11 @@ def make_return_jv_from_delivery_note(se, ref): | |||||||
| 	 | 	 | ||||||
| 	result = [] | 	result = [] | ||||||
| 	for sales_invoice, opts in against_invoice.items(): | 	for sales_invoice, opts in against_invoice.items(): | ||||||
| 		result += [opts["parent"]] + [{"account": account, "debit": debit}  | 		parent = opts["parent"] | ||||||
|  | 		parent.update({"against_invoice": sales_invoice}) | ||||||
|  | 		children = [{"account": account, "debit": debit}  | ||||||
| 			for account, debit in opts["children"].items()] | 			for account, debit in opts["children"].items()] | ||||||
|  | 		result += [parent] + children | ||||||
| 	return result | 	return result | ||||||
| 	 | 	 | ||||||
| def get_invoice_list(doctype, link_field, value): | def get_invoice_list(doctype, link_field, value): | ||||||
| @ -896,4 +915,63 @@ def get_invoice_list(doctype, link_field, value): | |||||||
| 			", ".join(["%s"]*len(value))), tuple(value)) | 			", ".join(["%s"]*len(value))), tuple(value)) | ||||||
| 			 | 			 | ||||||
| def make_return_jv_from_purchase_receipt(se, ref): | def make_return_jv_from_purchase_receipt(se, ref): | ||||||
| 	pass | 	invoice_against_receipt = get_invoice_list("Purchase Invoice Item", "purchase_receipt", | ||||||
|  | 		ref.doclist[0].name) | ||||||
|  | 	 | ||||||
|  | 	if not invoice_against_receipt: | ||||||
|  | 		purchase_orders_against_receipt = [d.prevdoc_docname for d in  | ||||||
|  | 			ref.doclist.get({"prevdoc_doctype": "Purchase Order"}) if d.prevdoc_docname] | ||||||
|  | 		 | ||||||
|  | 		invoice_against_receipt = get_invoice_list("Purchase Invoice Item", "purchase_order", | ||||||
|  | 			purchase_orders_against_receipt) | ||||||
|  | 			 | ||||||
|  | 	against_voucher = {} | ||||||
|  | 	 | ||||||
|  | 	for se_item in se.doclist.get({"parentfield": "mtn_details"}): | ||||||
|  | 		pending = se_item.transfer_qty | ||||||
|  | 		for purchase_invoice in invoice_against_receipt: | ||||||
|  | 			pi = webnotes.bean("Purchase Invoice", purchase_invoice) | ||||||
|  | 			ref_item = pi.doclist.get({"item_code": se_item.item_code}) | ||||||
|  | 			 | ||||||
|  | 			if not ref_item: | ||||||
|  | 				continue | ||||||
|  | 			 | ||||||
|  | 			ref_item = ref_item[0] | ||||||
|  | 			 | ||||||
|  | 			if ref_item.qty < pending: | ||||||
|  | 				transfer_qty = ref_item.qty | ||||||
|  | 				pending -= ref_item.qty | ||||||
|  | 			else: | ||||||
|  | 				transfer_qty = pending | ||||||
|  | 				pending = 0 | ||||||
|  | 			 | ||||||
|  | 			credit = ref_item.rate * transfer_qty | ||||||
|  | 			account = ref_item.expense_head | ||||||
|  | 			 | ||||||
|  | 			if pi.doclist[0].name not in against_voucher: | ||||||
|  | 				against_voucher[purchase_invoice] = { | ||||||
|  | 					"parent": {"account": pi.doclist[0].credit_to, "debit": 0}, | ||||||
|  | 					"children": {} | ||||||
|  | 				} | ||||||
|  | 			 | ||||||
|  | 			against_voucher[purchase_invoice]["parent"]["debit"] += credit | ||||||
|  | 
 | ||||||
|  | 			if account not in against_voucher[purchase_invoice]["children"]: | ||||||
|  | 				against_voucher[purchase_invoice]["children"][account] = 0 | ||||||
|  | 				 | ||||||
|  | 			against_voucher[purchase_invoice]["children"][account] += credit | ||||||
|  | 			 | ||||||
|  | 			# find tax account and value and add corresponding rows | ||||||
|  | 			 | ||||||
|  | 			if pending <= 0: | ||||||
|  | 				break | ||||||
|  | 	 | ||||||
|  | 	result = [] | ||||||
|  | 	for purchase_invoice, opts in against_voucher.items(): | ||||||
|  | 		parent = opts["parent"] | ||||||
|  | 		parent.update({"against_voucher": purchase_invoice}) | ||||||
|  | 		children = [{"account": account, "credit": credit}  | ||||||
|  | 			for account, credit in opts["children"].items()] | ||||||
|  | 		result += [parent] + children | ||||||
|  | 	return result | ||||||
|  | 		 | ||||||
| @ -9,6 +9,9 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 	def test_auto_material_request(self): | 	def test_auto_material_request(self): | ||||||
| 		webnotes.conn.sql("""delete from `tabMaterial Request Item`""") | 		webnotes.conn.sql("""delete from `tabMaterial Request Item`""") | ||||||
| 		webnotes.conn.sql("""delete from `tabMaterial Request`""") | 		webnotes.conn.sql("""delete from `tabMaterial Request`""") | ||||||
|  | 		self._clear_stock() | ||||||
|  | 		 | ||||||
|  | 		webnotes.conn.set_value("Global Defaults", None, "auto_indent", True) | ||||||
| 
 | 
 | ||||||
| 		st1 = webnotes.bean(copy=test_records[0]) | 		st1 = webnotes.bean(copy=test_records[0]) | ||||||
| 		st1.insert() | 		st1.insert() | ||||||
| @ -166,9 +169,14 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 	 | 	 | ||||||
| 	def _insert_material_receipt(self): | 	def _insert_material_receipt(self): | ||||||
| 		self._clear_stock() | 		self._clear_stock() | ||||||
| 		material_receipt = webnotes.bean(copy=test_records[0]) | 		se1 = webnotes.bean(copy=test_records[0]) | ||||||
| 		material_receipt.insert() | 		se1.insert() | ||||||
| 		material_receipt.submit() | 		se1.submit() | ||||||
|  | 		 | ||||||
|  | 		se2 = webnotes.bean(copy=test_records[0]) | ||||||
|  | 		se2.doclist[1].item_code = "_Test Item Home Desktop 100" | ||||||
|  | 		se2.insert() | ||||||
|  | 		se2.submit() | ||||||
| 		 | 		 | ||||||
| 	def _get_actual_qty(self): | 	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",  | ||||||
| @ -239,6 +247,8 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 		 | 		 | ||||||
| 		self.assertEquals(actual_qty_1 + returned_qty, actual_qty_2) | 		self.assertEquals(actual_qty_1 + returned_qty, actual_qty_2) | ||||||
| 		 | 		 | ||||||
|  | 		return se | ||||||
|  | 	 | ||||||
| 	def test_sales_invoice_return_of_non_packing_item(self): | 	def test_sales_invoice_return_of_non_packing_item(self): | ||||||
| 		self._test_sales_invoice_return("_Test Item", 5, 2) | 		self._test_sales_invoice_return("_Test Item", 5, 2) | ||||||
| 			 | 			 | ||||||
| @ -248,11 +258,12 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 	def _test_delivery_note_return(self, item_code, delivered_qty, returned_qty): | 	def _test_delivery_note_return(self, item_code, delivered_qty, returned_qty): | ||||||
| 		self._insert_material_receipt() | 		self._insert_material_receipt() | ||||||
| 		 | 		 | ||||||
| 		actual_qty_0 = self._get_actual_qty() |  | ||||||
| 		 |  | ||||||
| 		# insert and submit delivery note |  | ||||||
| 		from stock.doctype.delivery_note.test_delivery_note \ | 		from stock.doctype.delivery_note.test_delivery_note \ | ||||||
| 			import test_records as delivery_note_test_records | 			import test_records as delivery_note_test_records | ||||||
|  | 		 | ||||||
|  | 		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 = webnotes.bean(copy=delivery_note_test_records[0]) | ||||||
| 		dn.doclist[1].item_code = item_code | 		dn.doclist[1].item_code = item_code | ||||||
| 		dn.insert() | 		dn.insert() | ||||||
| @ -262,11 +273,26 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 		 | 		 | ||||||
| 		self.assertEquals(actual_qty_0 - delivered_qty, actual_qty_1) | 		self.assertEquals(actual_qty_0 - delivered_qty, actual_qty_1) | ||||||
| 		 | 		 | ||||||
|  | 		si_doclist = webnotes.map_doclist([ | ||||||
|  | 			["Delivery Note", "Sales Invoice"], | ||||||
|  | 			["Delivery Note Item", "Sales Invoice Item"], | ||||||
|  | 			["Sales Taxes and Charges", "Sales Taxes and Charges"], | ||||||
|  | 			["Sales Team", "Sales Team"]], dn.doc.name) | ||||||
|  | 			 | ||||||
|  | 		si = webnotes.bean(si_doclist) | ||||||
|  | 		si.doc.posting_date = dn.doc.posting_date | ||||||
|  | 		si.doc.debit_to = "_Test Customer - _TC" | ||||||
|  | 		for d in si.doclist.get({"parentfield": "entries"}): | ||||||
|  | 			d.income_account = "Sales - _TC" | ||||||
|  | 			d.cost_center = "_Test Cost Center - _TC" | ||||||
|  | 		si.insert() | ||||||
|  | 		si.submit() | ||||||
|  | 		 | ||||||
| 		# insert and submit stock entry for sales return | 		# insert and submit stock entry for sales return | ||||||
| 		se = webnotes.bean(copy=test_records[0]) | 		se = webnotes.bean(copy=test_records[0]) | ||||||
| 		se.doc.purpose = "Sales Return" | 		se.doc.purpose = "Sales Return" | ||||||
| 		se.doc.delivery_note_no = dn.doc.name | 		se.doc.delivery_note_no = dn.doc.name | ||||||
| 		se.doc.posting_date = "2013-03-01" | 		se.doc.posting_date = "2013-03-10" | ||||||
| 		se.doclist[1].qty = se.doclist[1].transfer_qty = returned_qty | 		se.doclist[1].qty = se.doclist[1].transfer_qty = returned_qty | ||||||
| 		 | 		 | ||||||
| 		se.insert() | 		se.insert() | ||||||
| @ -275,12 +301,115 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 		actual_qty_2 = self._get_actual_qty() | 		actual_qty_2 = self._get_actual_qty() | ||||||
| 		self.assertEquals(actual_qty_1 + returned_qty, actual_qty_2) | 		self.assertEquals(actual_qty_1 + returned_qty, actual_qty_2) | ||||||
| 		 | 		 | ||||||
|  | 		return se | ||||||
|  | 		 | ||||||
| 	def test_delivery_note_return_of_non_packing_item(self): | 	def test_delivery_note_return_of_non_packing_item(self): | ||||||
| 		self._test_delivery_note_return("_Test Item", 5, 2) | 		self._test_delivery_note_return("_Test Item", 5, 2) | ||||||
| 		 | 		 | ||||||
| 	def test_delivery_note_return_of_packing_item(self): | 	def test_delivery_note_return_of_packing_item(self): | ||||||
| 		self._test_delivery_note_return("_Test Sales BOM Item", 25, 20) | 		self._test_delivery_note_return("_Test Sales BOM Item", 25, 20) | ||||||
| 		 | 		 | ||||||
|  | 	def _test_sales_return_jv(self, se, returned_value): | ||||||
|  | 		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")) | ||||||
|  | 		 | ||||||
|  | 		# debit == credit | ||||||
|  | 		debit = sum([flt(d.get("debit")) for d in jv_list]) | ||||||
|  | 		credit = sum([flt(d.get("credit")) for d in jv_list]) | ||||||
|  | 		self.assertEqual(debit, credit) | ||||||
|  | 		 | ||||||
|  | 		# validate value of debit | ||||||
|  | 		self.assertEqual(debit, returned_value) | ||||||
|  | 		 | ||||||
|  | 	def test_make_return_jv_for_sales_invoice_non_packing_item(self): | ||||||
|  | 		se = self._test_sales_invoice_return("_Test Item", 5, 2) | ||||||
|  | 		self._test_sales_return_jv(se, 1000) | ||||||
|  | 		 | ||||||
|  | 	def test_make_return_jv_for_sales_invoice_packing_item(self): | ||||||
|  | 		se = self._test_sales_invoice_return("_Test Sales BOM Item", 25, 20) | ||||||
|  | 		self._test_sales_return_jv(se, 2000) | ||||||
|  | 		 | ||||||
|  | 	def test_make_return_jv_for_delivery_note_non_packing_item(self): | ||||||
|  | 		se = self._test_delivery_note_return("_Test Item", 5, 2) | ||||||
|  | 		self._test_sales_return_jv(se, 200) | ||||||
|  | 		 | ||||||
|  | 		se = self._test_delivery_note_return_against_sales_order("_Test Item", 5, 2) | ||||||
|  | 		self._test_sales_return_jv(se, 200) | ||||||
|  | 		 | ||||||
|  | 	def test_make_return_jv_for_delivery_note_packing_item(self): | ||||||
|  | 		se = self._test_delivery_note_return("_Test Sales BOM Item", 25, 20) | ||||||
|  | 		self._test_sales_return_jv(se, 400) | ||||||
|  | 		 | ||||||
|  | 		se = self._test_delivery_note_return_against_sales_order("_Test Sales BOM Item", 25, 20) | ||||||
|  | 		self._test_sales_return_jv(se, 400) | ||||||
|  | 		 | ||||||
|  | 	def _test_delivery_note_return_against_sales_order(self, item_code, delivered_qty, returned_qty): | ||||||
|  | 		self._insert_material_receipt() | ||||||
|  | 
 | ||||||
|  | 		from selling.doctype.sales_order.test_sales_order \ | ||||||
|  | 			import test_records as sales_order_test_records | ||||||
|  | 
 | ||||||
|  | 		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 = webnotes.map_doclist([ | ||||||
|  | 			["Sales Order", "Delivery Note"], | ||||||
|  | 			["Sales Order Item", "Delivery Note Item"], | ||||||
|  | 			["Sales Taxes and Charges", "Sales Taxes and Charges"], | ||||||
|  | 			["Sales Team", "Sales Team"]], so.doc.name) | ||||||
|  | 
 | ||||||
|  | 		dn = webnotes.bean(dn_doclist) | ||||||
|  | 		dn.doc.status = "Draft" | ||||||
|  | 		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) | ||||||
|  | 
 | ||||||
|  | 		si_doclist = webnotes.map_doclist([ | ||||||
|  | 			["Sales Order", "Sales Invoice"], | ||||||
|  | 			["Sales Order Item", "Sales Invoice Item"], | ||||||
|  | 			["Sales Taxes and Charges", "Sales Taxes and Charges"], | ||||||
|  | 			["Sales Team", "Sales Team"]], so.doc.name) | ||||||
|  | 
 | ||||||
|  | 		si = webnotes.bean(si_doclist) | ||||||
|  | 		si.doc.posting_date = dn.doc.posting_date | ||||||
|  | 		si.doc.debit_to = "_Test Customer - _TC" | ||||||
|  | 		for d in si.doclist.get({"parentfield": "entries"}): | ||||||
|  | 			d.income_account = "Sales - _TC" | ||||||
|  | 			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" | ||||||
|  | 		se.doc.delivery_note_no = dn.doc.name | ||||||
|  | 		se.doc.posting_date = "2013-03-10" | ||||||
|  | 		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_purchase_receipt_return(self): | 	def test_purchase_receipt_return(self): | ||||||
| 		self._clear_stock() | 		self._clear_stock() | ||||||
| 		 | 		 | ||||||
| @ -298,6 +427,24 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 		 | 		 | ||||||
| 		self.assertEquals(actual_qty_0 + 10, actual_qty_1) | 		self.assertEquals(actual_qty_0 + 10, actual_qty_1) | ||||||
| 		 | 		 | ||||||
|  | 		pi_doclist = webnotes.map_doclist([ | ||||||
|  | 			["Purchase Receipt", "Purchase Invoice"], | ||||||
|  | 			["Purchase Receipt Item", "Purchase Invoice Item"], | ||||||
|  | 			["Purchase Taxes and Charges", "Purchase Taxes and Charges"]], 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.insert() | ||||||
|  | 		pi.submit() | ||||||
|  | 		 | ||||||
| 		# submit purchase return | 		# submit purchase return | ||||||
| 		se = webnotes.bean(copy=test_records[0]) | 		se = webnotes.bean(copy=test_records[0]) | ||||||
| 		se.doc.purpose = "Purchase Return" | 		se.doc.purpose = "Purchase Return" | ||||||
| @ -312,13 +459,13 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 		 | 		 | ||||||
| 		self.assertEquals(actual_qty_1 - 5, actual_qty_2) | 		self.assertEquals(actual_qty_1 - 5, actual_qty_2) | ||||||
| 		 | 		 | ||||||
| 		return pr.doc.name | 		return se, pr.doc.name | ||||||
| 		 | 		 | ||||||
| 	def test_over_stock_return(self): | 	def test_over_stock_return(self): | ||||||
| 		from stock.doctype.stock_entry.stock_entry import StockOverReturnError | 		from stock.doctype.stock_entry.stock_entry import StockOverReturnError | ||||||
| 		 | 		 | ||||||
| 		# out of 10, 5 gets returned | 		# out of 10, 5 gets returned | ||||||
| 		pr_docname = self.test_purchase_receipt_return() | 		prev_se, pr_docname = self.test_purchase_receipt_return() | ||||||
| 		 | 		 | ||||||
| 		# submit purchase return - return another 6 qtys so that exception is raised | 		# submit purchase return - return another 6 qtys so that exception is raised | ||||||
| 		se = webnotes.bean(copy=test_records[0]) | 		se = webnotes.bean(copy=test_records[0]) | ||||||
| @ -330,6 +477,96 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 		 | 		 | ||||||
| 		self.assertRaises(StockOverReturnError, se.insert) | 		self.assertRaises(StockOverReturnError, se.insert) | ||||||
| 		 | 		 | ||||||
|  | 	def _test_purchase_return_jv(self, se, returned_value): | ||||||
|  | 		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")) | ||||||
|  | 		 | ||||||
|  | 		# debit == credit | ||||||
|  | 		debit = sum([flt(d.get("debit")) for d in jv_list]) | ||||||
|  | 		credit = sum([flt(d.get("credit")) for d in jv_list]) | ||||||
|  | 		self.assertEqual(debit, credit) | ||||||
|  | 		 | ||||||
|  | 		# validate value of credit | ||||||
|  | 		self.assertEqual(credit, returned_value) | ||||||
|  | 		 | ||||||
|  | 	def test_make_return_jv_for_purchase_receipt(self): | ||||||
|  | 		se, pr_name = self.test_purchase_receipt_return() | ||||||
|  | 		self._test_purchase_return_jv(se, 250) | ||||||
|  | 		 | ||||||
|  | 		se, pr_name = self._test_purchase_return_return_against_purchase_order() | ||||||
|  | 		self._test_purchase_return_jv(se, 250) | ||||||
|  | 		 | ||||||
|  | 	def _test_purchase_return_return_against_purchase_order(self): | ||||||
|  | 		self._clear_stock() | ||||||
|  | 		 | ||||||
|  | 		actual_qty_0 = self._get_actual_qty() | ||||||
|  | 		 | ||||||
|  | 		from buying.doctype.purchase_order.test_purchase_order \ | ||||||
|  | 			import test_records as purchase_order_test_records | ||||||
|  | 		 | ||||||
|  | 		# submit purchase receipt | ||||||
|  | 		po = webnotes.bean(copy=purchase_order_test_records[0]) | ||||||
|  | 		po.doc.is_subcontracted = None | ||||||
|  | 		po.doclist[1].item_code = "_Test Item" | ||||||
|  | 		po.doclist[1].import_rate = 50 | ||||||
|  | 		po.insert() | ||||||
|  | 		po.submit() | ||||||
|  | 		 | ||||||
|  | 		pr_doclist = webnotes.map_doclist([ | ||||||
|  | 			["Purchase Order", "Purchase Receipt"], | ||||||
|  | 			["Purchase Order Item", "Purchase Receipt Item"], | ||||||
|  | 			["Purchase Taxes and Charges", "Purchase Taxes and Charges"]], 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 = webnotes.map_doclist([ | ||||||
|  | 			["Purchase Order", "Purchase Invoice"], | ||||||
|  | 			["Purchase Order Item", "Purchase Invoice Item"], | ||||||
|  | 			["Purchase Taxes and Charges", "Purchase Taxes and Charges"]], po.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.insert() | ||||||
|  | 		pi.submit() | ||||||
|  | 		 | ||||||
|  | 		# submit purchase return | ||||||
|  | 		se = webnotes.bean(copy=test_records[0]) | ||||||
|  | 		se.doc.purpose = "Purchase Return" | ||||||
|  | 		se.doc.purchase_receipt_no = pr.doc.name | ||||||
|  | 		se.doc.posting_date = "2013-03-01" | ||||||
|  | 		se.doclist[1].qty = se.doclist[1].transfer_qty = 5 | ||||||
|  | 		se.doclist[1].s_warehouse = "_Test Warehouse" | ||||||
|  | 		se.insert() | ||||||
|  | 		se.submit() | ||||||
|  | 		 | ||||||
|  | 		actual_qty_2 = self._get_actual_qty() | ||||||
|  | 		 | ||||||
|  | 		self.assertEquals(actual_qty_1 - 5, actual_qty_2) | ||||||
|  | 		 | ||||||
|  | 		return se, pr.doc.name | ||||||
|  | 		 | ||||||
| test_records = [ | test_records = [ | ||||||
| 	[ | 	[ | ||||||
| 		{ | 		{ | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user