Test case cleanup and fixes
This commit is contained in:
		
							parent
							
								
									c8c1d1c693
								
							
						
					
					
						commit
						7c9d003917
					
				| @ -4,27 +4,26 @@ | |||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
| import unittest, frappe | import unittest, frappe | ||||||
| from frappe.utils import flt | from frappe.utils import flt | ||||||
|  | from erpnext.accounts.utils import get_actual_expense, BudgetError, get_fiscal_year | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| class TestJournalEntry(unittest.TestCase): | class TestJournalEntry(unittest.TestCase): | ||||||
| 	def test_journal_entry_with_against_jv(self): | 	def test_journal_entry_with_against_jv(self): | ||||||
| 
 |  | ||||||
| 		jv_invoice = frappe.copy_doc(test_records[2]) | 		jv_invoice = frappe.copy_doc(test_records[2]) | ||||||
| 		base_jv = frappe.copy_doc(test_records[0]) | 		base_jv = frappe.copy_doc(test_records[0]) | ||||||
| 		self.jv_against_voucher_testcase(base_jv, jv_invoice) | 		self.jv_against_voucher_testcase(base_jv, jv_invoice) | ||||||
| 
 | 
 | ||||||
| 	def test_jv_against_sales_order(self): | 	def test_jv_against_sales_order(self): | ||||||
| 		from erpnext.selling.doctype.sales_order.test_sales_order \ | 		from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order | ||||||
| 			import test_records as so_test_records |  | ||||||
| 
 | 
 | ||||||
| 		sales_order = frappe.copy_doc(so_test_records[0]) | 		sales_order = make_sales_order(do_not_save=True) | ||||||
| 		base_jv = frappe.copy_doc(test_records[0]) | 		base_jv = frappe.copy_doc(test_records[0]) | ||||||
| 		self.jv_against_voucher_testcase(base_jv, sales_order) | 		self.jv_against_voucher_testcase(base_jv, sales_order) | ||||||
| 
 | 
 | ||||||
| 	def test_jv_against_purchase_order(self): | 	def test_jv_against_purchase_order(self): | ||||||
| 		from erpnext.buying.doctype.purchase_order.test_purchase_order \ | 		from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order | ||||||
| 			import test_records as po_test_records |  | ||||||
| 
 | 
 | ||||||
| 		purchase_order = frappe.copy_doc(po_test_records[0]) | 		purchase_order = create_purchase_order(do_not_save=True) | ||||||
| 		base_jv = frappe.copy_doc(test_records[1]) | 		base_jv = frappe.copy_doc(test_records[1]) | ||||||
| 		self.jv_against_voucher_testcase(base_jv, purchase_order) | 		self.jv_against_voucher_testcase(base_jv, purchase_order) | ||||||
| 
 | 
 | ||||||
| @ -35,7 +34,6 @@ class TestJournalEntry(unittest.TestCase): | |||||||
| 			'Purchase Order': "against_purchase_order" | 			'Purchase Order': "against_purchase_order" | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 		self.clear_account_balance() |  | ||||||
| 		test_voucher.insert() | 		test_voucher.insert() | ||||||
| 		test_voucher.submit() | 		test_voucher.submit() | ||||||
| 
 | 
 | ||||||
| @ -104,78 +102,58 @@ class TestJournalEntry(unittest.TestCase): | |||||||
| 
 | 
 | ||||||
| 	def test_monthly_budget_crossed_ignore(self): | 	def test_monthly_budget_crossed_ignore(self): | ||||||
| 		frappe.db.set_value("Company", "_Test Company", "monthly_bgt_flag", "Ignore") | 		frappe.db.set_value("Company", "_Test Company", "monthly_bgt_flag", "Ignore") | ||||||
| 		self.clear_account_balance() |  | ||||||
| 		 | 		 | ||||||
| 		jv = frappe.copy_doc(test_records[0]) | 		existing_expense = self.get_actual_expense("2013-02-28") | ||||||
| 		jv.get("accounts")[1].account = "_Test Account Cost for Goods Sold - _TC" | 		current_expense = - existing_expense + 20000 if existing_expense < 0 else 20000 | ||||||
| 		jv.get("accounts")[1].cost_center = "_Test Cost Center - _TC" | 		 | ||||||
| 		jv.get("accounts")[1].debit = 20000.0 | 		jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",  | ||||||
| 		jv.get("accounts")[0].credit = 20000.0 | 			"_Test Account Bank Account - _TC", current_expense, "_Test Cost Center - _TC", submit=True) | ||||||
| 		jv.insert() | 			 | ||||||
| 		jv.submit() |  | ||||||
| 		self.assertTrue(frappe.db.get_value("GL Entry", | 		self.assertTrue(frappe.db.get_value("GL Entry", | ||||||
| 			{"voucher_type": "Journal Entry", "voucher_no": jv.name})) | 			{"voucher_type": "Journal Entry", "voucher_no": jv.name})) | ||||||
| 
 | 
 | ||||||
| 	def test_monthly_budget_crossed_stop(self): | 	def test_monthly_budget_crossed_stop(self): | ||||||
| 		from erpnext.accounts.utils import BudgetError |  | ||||||
| 		frappe.db.set_value("Company", "_Test Company", "monthly_bgt_flag", "Stop") | 		frappe.db.set_value("Company", "_Test Company", "monthly_bgt_flag", "Stop") | ||||||
| 		self.clear_account_balance() |  | ||||||
| 		 | 		 | ||||||
| 		jv = frappe.copy_doc(test_records[0]) | 		existing_expense = self.get_actual_expense("2013-02-28") | ||||||
| 		jv.get("accounts")[1].account = "_Test Account Cost for Goods Sold - _TC" | 		current_expense = - existing_expense + 20000 if existing_expense < 0 else 20000 | ||||||
| 		jv.get("accounts")[1].cost_center = "_Test Cost Center - _TC" | 		 | ||||||
| 		jv.get("accounts")[1].debit = 20000.0 | 		jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",  | ||||||
| 		jv.get("accounts")[0].credit = 20000.0 | 			"_Test Account Bank Account - _TC", current_expense, "_Test Cost Center - _TC") | ||||||
| 		jv.insert() |  | ||||||
| 			 | 			 | ||||||
| 		self.assertRaises(BudgetError, jv.submit) | 		self.assertRaises(BudgetError, jv.submit) | ||||||
| 
 | 
 | ||||||
| 		frappe.db.set_value("Company", "_Test Company", "monthly_bgt_flag", "Ignore") | 		frappe.db.set_value("Company", "_Test Company", "monthly_bgt_flag", "Ignore") | ||||||
| 
 | 
 | ||||||
| 	def test_yearly_budget_crossed_stop(self): | 	def test_yearly_budget_crossed_stop(self): | ||||||
| 		from erpnext.accounts.utils import BudgetError |  | ||||||
| 		self.clear_account_balance() |  | ||||||
| 		self.test_monthly_budget_crossed_ignore() | 		self.test_monthly_budget_crossed_ignore() | ||||||
| 
 | 
 | ||||||
| 		frappe.db.set_value("Company", "_Test Company", "yearly_bgt_flag", "Stop") | 		frappe.db.set_value("Company", "_Test Company", "yearly_bgt_flag", "Stop") | ||||||
| 		 | 		 | ||||||
| 		jv = frappe.copy_doc(test_records[0]) | 		existing_expense = self.get_actual_expense("2013-02-28") | ||||||
| 		jv.posting_date = "2013-08-12" | 		current_expense = - existing_expense + 150000 if existing_expense < 0 else 150000 | ||||||
| 		jv.get("accounts")[1].account = "_Test Account Cost for Goods Sold - _TC" | 
 | ||||||
| 		jv.get("accounts")[1].cost_center = "_Test Cost Center - _TC" | 		jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",  | ||||||
| 		jv.get("accounts")[1].debit = 150000.0 | 			"_Test Account Bank Account - _TC", current_expense, "_Test Cost Center - _TC") | ||||||
| 		jv.get("accounts")[0].credit = 150000.0 |  | ||||||
| 		jv.insert() |  | ||||||
| 		 | 		 | ||||||
| 		self.assertRaises(BudgetError, jv.submit) | 		self.assertRaises(BudgetError, jv.submit) | ||||||
| 
 | 
 | ||||||
| 		frappe.db.set_value("Company", "_Test Company", "yearly_bgt_flag", "Ignore") | 		frappe.db.set_value("Company", "_Test Company", "yearly_bgt_flag", "Ignore") | ||||||
| 
 | 
 | ||||||
| 	def test_monthly_budget_on_cancellation(self): | 	def test_monthly_budget_on_cancellation(self): | ||||||
| 		from erpnext.accounts.utils import BudgetError |  | ||||||
| 		frappe.db.set_value("Company", "_Test Company", "monthly_bgt_flag", "Stop") | 		frappe.db.set_value("Company", "_Test Company", "monthly_bgt_flag", "Stop") | ||||||
| 		self.clear_account_balance() |  | ||||||
| 
 | 
 | ||||||
| 		jv = frappe.copy_doc(test_records[0]) | 		existing_expense = self.get_actual_expense("2013-02-28") | ||||||
| 		jv.get("accounts")[0].update({ | 		current_expense = - existing_expense - 30000 if existing_expense < 0 else 30000 | ||||||
| 			"account": "_Test Account Cost for Goods Sold - _TC", | 		 | ||||||
| 			"cost_center": "_Test Cost Center - _TC", | 		jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",  | ||||||
| 			"party_type": None, | 			"_Test Account Bank Account - _TC", current_expense, "_Test Cost Center - _TC", submit=True) | ||||||
| 			"party": None, |  | ||||||
| 			"credit": 30000.0 |  | ||||||
| 		}) |  | ||||||
| 		jv.get("accounts")[1].debit = 30000.0 |  | ||||||
| 		jv.submit() |  | ||||||
| 		 | 		 | ||||||
| 		self.assertTrue(frappe.db.get_value("GL Entry", | 		self.assertTrue(frappe.db.get_value("GL Entry", | ||||||
| 			{"voucher_type": "Journal Entry", "voucher_no": jv.name})) | 			{"voucher_type": "Journal Entry", "voucher_no": jv.name})) | ||||||
| 
 | 
 | ||||||
| 		jv1 = frappe.copy_doc(test_records[0]) | 		jv1 = make_journal_entry("_Test Account Cost for Goods Sold - _TC",  | ||||||
| 		jv1.get("accounts")[1].account = "_Test Account Cost for Goods Sold - _TC" | 			"_Test Account Bank Account - _TC", 40000, "_Test Cost Center - _TC", submit=True) | ||||||
| 		jv1.get("accounts")[1].cost_center = "_Test Cost Center - _TC" |  | ||||||
| 		jv1.get("accounts")[1].debit = 40000.0 |  | ||||||
| 		jv1.get("accounts")[0].credit = 40000.0 |  | ||||||
| 		jv1.submit() |  | ||||||
| 					 | 					 | ||||||
| 		self.assertTrue(frappe.db.get_value("GL Entry", | 		self.assertTrue(frappe.db.get_value("GL Entry", | ||||||
| 			{"voucher_type": "Journal Entry", "voucher_no": jv1.name})) | 			{"voucher_type": "Journal Entry", "voucher_no": jv1.name})) | ||||||
| @ -184,8 +162,41 @@ class TestJournalEntry(unittest.TestCase): | |||||||
| 
 | 
 | ||||||
| 		frappe.db.set_value("Company", "_Test Company", "monthly_bgt_flag", "Ignore") | 		frappe.db.set_value("Company", "_Test Company", "monthly_bgt_flag", "Ignore") | ||||||
| 		 | 		 | ||||||
| 	def clear_account_balance(self): | 	def get_actual_expense(self, monthly_end_date): | ||||||
| 		frappe.db.sql("""delete from `tabGL Entry`""") | 		return get_actual_expense({ | ||||||
|  | 			"account": "_Test Account Cost for Goods Sold - _TC", | ||||||
|  | 			"cost_center": "_Test Cost Center - _TC", | ||||||
|  | 			"monthly_end_date": monthly_end_date, | ||||||
|  | 			"company": "_Test Company", | ||||||
|  | 			"fiscal_year": get_fiscal_year(monthly_end_date)[0] | ||||||
|  | 		}) | ||||||
|  | 		 | ||||||
|  | def make_journal_entry(account1, account2, amount, cost_center=None, submit=False): | ||||||
|  | 	jv = frappe.new_doc("Journal Entry") | ||||||
|  | 	jv.posting_date = "2013-02-14" | ||||||
|  | 	jv.company = "_Test Company" | ||||||
|  | 	jv.fiscal_year = "_Test Fiscal Year 2013" | ||||||
|  | 	jv.user_remark = "test" | ||||||
|  | 	 | ||||||
|  | 	jv.set("accounts", [ | ||||||
|  | 		{ | ||||||
|  | 			"account": account1, | ||||||
|  | 			"cost_center": cost_center, | ||||||
|  | 			"debit": amount if amount > 0 else 0, | ||||||
|  | 			"credit": abs(amount) if amount < 0 else 0, | ||||||
|  | 		}, { | ||||||
|  | 			"account": account2, | ||||||
|  | 			"cost_center": cost_center, | ||||||
|  | 			"credit": amount if amount > 0 else 0, | ||||||
|  | 			"debit": abs(amount) if amount < 0 else 0, | ||||||
|  | 		} | ||||||
|  | 	]) | ||||||
|  | 	jv.insert() | ||||||
|  | 	 | ||||||
|  | 	if submit: | ||||||
|  | 		jv.submit() | ||||||
|  | 	 | ||||||
|  | 	return jv | ||||||
| 		 | 		 | ||||||
| 
 | 
 | ||||||
| test_records = frappe.get_test_records('Journal Entry') | test_records = frappe.get_test_records('Journal Entry') | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| [ | [ | ||||||
|  { |  { | ||||||
|   "cheque_date": "2013-02-14", |   "cheque_date": "2013-03-14", | ||||||
|   "cheque_no": "33", |   "cheque_no": "33", | ||||||
|   "company": "_Test Company", |   "company": "_Test Company", | ||||||
|   "doctype": "Journal Entry", |   "doctype": "Journal Entry", | ||||||
| @ -28,6 +28,8 @@ | |||||||
|   "user_remark": "test", |   "user_remark": "test", | ||||||
|   "voucher_type": "Bank Entry" |   "voucher_type": "Bank Entry" | ||||||
|  }, |  }, | ||||||
|  |   | ||||||
|  |   | ||||||
|  { |  { | ||||||
|   "cheque_date": "2013-02-14", |   "cheque_date": "2013-02-14", | ||||||
|   "cheque_no": "33", |   "cheque_no": "33", | ||||||
| @ -57,6 +59,8 @@ | |||||||
|   "user_remark": "test", |   "user_remark": "test", | ||||||
|   "voucher_type": "Bank Entry" |   "voucher_type": "Bank Entry" | ||||||
|  }, |  }, | ||||||
|  |   | ||||||
|  |   | ||||||
|  { |  { | ||||||
|   "cheque_date": "2013-02-14", |   "cheque_date": "2013-02-14", | ||||||
|   "cheque_no": "33", |   "cheque_no": "33", | ||||||
|  | |||||||
| @ -4,32 +4,25 @@ | |||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
| import unittest, frappe, json | import unittest, frappe, json | ||||||
| from frappe.utils import flt | from frappe.utils import flt | ||||||
|  | from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order | ||||||
|  | from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order | ||||||
|  | from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import test_records as si_test_records | ||||||
|  | from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import test_records as pi_test_records | ||||||
|  | from erpnext.accounts.doctype.journal_entry.test_journal_entry import test_records as jv_test_records | ||||||
| 
 | 
 | ||||||
| test_dependencies = ["Item"] | test_dependencies = ["Item"] | ||||||
| 
 | 
 | ||||||
| class TestPaymentTool(unittest.TestCase): | class TestPaymentTool(unittest.TestCase): | ||||||
| 	def test_make_journal_entry(self): | 	def test_make_journal_entry(self): | ||||||
| 		from erpnext.accounts.doctype.journal_entry.test_journal_entry \ |  | ||||||
| 			import test_records as jv_test_records |  | ||||||
| 		from erpnext.selling.doctype.sales_order.test_sales_order \ |  | ||||||
| 			import test_records as so_test_records |  | ||||||
| 		from erpnext.buying.doctype.purchase_order.test_purchase_order \ |  | ||||||
| 			import test_records as po_test_records |  | ||||||
| 		from erpnext.accounts.doctype.sales_invoice.test_sales_invoice \ |  | ||||||
| 			import test_records as si_test_records |  | ||||||
| 		from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice \ |  | ||||||
| 			import test_records as pi_test_records |  | ||||||
| 
 |  | ||||||
| 		self.clear_table_entries() | 		self.clear_table_entries() | ||||||
|  | 		frappe.db.set_default("currency", "INR") | ||||||
| 
 | 
 | ||||||
| 		base_customer_jv = self.create_against_jv(jv_test_records[2], { "party": "_Test Customer 3"}) | 		base_customer_jv = self.create_against_jv(jv_test_records[2], { "party": "_Test Customer 3"}) | ||||||
| 		base_supplier_jv = self.create_against_jv(jv_test_records[1], { "party": "_Test Supplier 1"}) | 		base_supplier_jv = self.create_against_jv(jv_test_records[1], { "party": "_Test Supplier 1"}) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 		# Create SO with partial outstanding | 		# Create SO with partial outstanding | ||||||
| 		so1 = self.create_voucher(so_test_records[0], { | 		so1 = make_sales_order(customer="_Test Customer 3", qty=10, rate=100) | ||||||
| 			"customer": "_Test Customer 3" |  | ||||||
| 		}) |  | ||||||
| 		 | 		 | ||||||
| 		self.create_against_jv(jv_test_records[0], { | 		self.create_against_jv(jv_test_records[0], { | ||||||
| 			"party": "_Test Customer 3", | 			"party": "_Test Customer 3", | ||||||
| @ -39,9 +32,7 @@ class TestPaymentTool(unittest.TestCase): | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 		#Create SO with no outstanding | 		#Create SO with no outstanding | ||||||
| 		so2 = self.create_voucher(so_test_records[0], { | 		so2 = make_sales_order(customer="_Test Customer 3") | ||||||
| 			"customer": "_Test Customer 3" |  | ||||||
| 		}) |  | ||||||
| 
 | 
 | ||||||
| 		self.create_against_jv(jv_test_records[0], { | 		self.create_against_jv(jv_test_records[0], { | ||||||
| 			"party": "_Test Customer 3", | 			"party": "_Test Customer 3", | ||||||
| @ -51,9 +42,7 @@ class TestPaymentTool(unittest.TestCase): | |||||||
| 		}) | 		}) | ||||||
| 
 | 
 | ||||||
| 		# Purchase order | 		# Purchase order | ||||||
| 		po = self.create_voucher(po_test_records[1], { | 		po = create_purchase_order(supplier="_Test Supplier 1") | ||||||
| 			"supplier": "_Test Supplier 1" |  | ||||||
| 		}) |  | ||||||
| 
 | 
 | ||||||
| 		#Create SI with partial outstanding | 		#Create SI with partial outstanding | ||||||
| 		si1 = self.create_voucher(si_test_records[0], { | 		si1 = self.create_voucher(si_test_records[0], { | ||||||
|  | |||||||
| @ -5,43 +5,48 @@ | |||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
| import unittest | import unittest | ||||||
| import frappe | import frappe | ||||||
| from erpnext.accounts.doctype.journal_entry.test_journal_entry import test_records as jv_records | from frappe.utils import flt | ||||||
|  | from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry | ||||||
| 
 | 
 | ||||||
| class TestPeriodClosingVoucher(unittest.TestCase): | class TestPeriodClosingVoucher(unittest.TestCase): | ||||||
| 	def test_closing_entry(self): | 	def test_closing_entry(self): | ||||||
| 		# clear GL Entries | 		make_journal_entry("_Test Account Bank Account - _TC", "Sales - _TC", 400,  | ||||||
| 		frappe.db.sql("""delete from `tabGL Entry`""") | 			"_Test Cost Center - _TC", submit=True) | ||||||
| 		jv = frappe.copy_doc(jv_records[2]) |  | ||||||
| 		jv.insert() |  | ||||||
| 		jv.submit() |  | ||||||
| 		 | 		 | ||||||
| 		jv1 = frappe.copy_doc(jv_records[0]) | 		make_journal_entry("_Test Account Cost for Goods Sold - _TC",  | ||||||
| 		jv1.get("accounts")[1].account = "_Test Account Cost for Goods Sold - _TC" | 			"_Test Account Bank Account - _TC", 600, "_Test Cost Center - _TC", submit=True) | ||||||
| 		jv1.get("accounts")[1].cost_center = "_Test Cost Center - _TC" |  | ||||||
| 		jv1.get("accounts")[1].debit = 600.0 |  | ||||||
| 		jv1.get("accounts")[0].credit = 600.0 |  | ||||||
| 		jv1.insert() |  | ||||||
| 		jv1.submit() |  | ||||||
| 			 | 			 | ||||||
| 		pcv = frappe.copy_doc(test_records[0]) | 		profit_or_loss = frappe.db.sql("""select sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) as balance | ||||||
|  | 			from `tabGL Entry` t1, `tabAccount` t2 | ||||||
|  | 			where t1.account = t2.name and ifnull(t2.report_type, '') = 'Profit and Loss' | ||||||
|  | 			and t2.docstatus < 2 and t2.company = '_Test Company' | ||||||
|  | 			and t1.posting_date between '2013-01-01' and '2013-12-31'""") | ||||||
|  | 			 | ||||||
|  | 		profit_or_loss = flt(profit_or_loss[0][0]) if profit_or_loss else 0 | ||||||
|  | 		 | ||||||
|  | 		pcv = self.make_period_closing_voucher() | ||||||
|  | 		 | ||||||
|  | 		gle_value = frappe.db.sql("""select ifnull(debit, 0) - ifnull(credit, 0) | ||||||
|  | 			from `tabGL Entry` where voucher_type='Period Closing Voucher' and voucher_no=%s | ||||||
|  | 			and account = '_Test Account Reserves and Surplus - _TC'""", pcv.name) | ||||||
|  | 			 | ||||||
|  | 		gle_value = flt(gle_value[0][0]) if gle_value else 0 | ||||||
|  | 
 | ||||||
|  | 		self.assertEqual(gle_value, profit_or_loss) | ||||||
|  | 		 | ||||||
|  | 	def make_period_closing_voucher(self): | ||||||
|  | 		pcv = frappe.get_doc({ | ||||||
|  | 			"doctype": "Period Closing Voucher", | ||||||
|  | 			"closing_account_head": "_Test Account Reserves and Surplus - _TC", | ||||||
|  | 			"company": "_Test Company", | ||||||
|  | 			"fiscal_year": "_Test Fiscal Year 2013", | ||||||
|  | 			"posting_date": "2013-12-31", | ||||||
|  | 			"remarks": "test" | ||||||
|  | 		}) | ||||||
| 		pcv.insert() | 		pcv.insert() | ||||||
| 		pcv.submit() | 		pcv.submit() | ||||||
| 		 | 		 | ||||||
| 		gl_entries = frappe.db.sql("""select account, debit, credit | 		return pcv | ||||||
| 			from `tabGL Entry` where voucher_type='Period Closing Voucher' and voucher_no=%s |  | ||||||
| 			order by account asc, debit asc""", pcv.name, as_dict=1) |  | ||||||
| 
 |  | ||||||
| 		self.assertTrue(gl_entries) |  | ||||||
| 
 |  | ||||||
| 		expected_gl_entries = sorted([ |  | ||||||
| 			["_Test Account Reserves and Surplus - _TC", 200.0, 0.0], |  | ||||||
| 			["_Test Account Cost for Goods Sold - _TC", 0.0, 600.0], |  | ||||||
| 			["Sales - _TC", 400.0, 0.0] |  | ||||||
| 		]) |  | ||||||
| 		for i, gle in enumerate(gl_entries): |  | ||||||
| 			self.assertEquals(expected_gl_entries[i][0], gle.account) |  | ||||||
| 			self.assertEquals(expected_gl_entries[i][1], gle.debit) |  | ||||||
| 			self.assertEquals(expected_gl_entries[i][2], gle.credit) |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| test_dependencies = ["Customer", "Cost Center"] | test_dependencies = ["Customer", "Cost Center"] | ||||||
|  | |||||||
| @ -1,8 +0,0 @@ | |||||||
| [{ |  | ||||||
| 	"doctype": "Period Closing Voucher", |  | ||||||
| 	"closing_account_head": "_Test Account Reserves and Surplus - _TC", |  | ||||||
| 	"company": "_Test Company", |  | ||||||
| 	"fiscal_year": "_Test Fiscal Year 2013", |  | ||||||
| 	"posting_date": "2013-03-31", |  | ||||||
| 	"remarks": "test" |  | ||||||
| }] |  | ||||||
| @ -7,7 +7,6 @@ | |||||||
|   "customer_name": "_Test Customer", |   "customer_name": "_Test Customer", | ||||||
|   "debit_to": "_Test Receivable - _TC", |   "debit_to": "_Test Receivable - _TC", | ||||||
|   "doctype": "Sales Invoice", |   "doctype": "Sales Invoice", | ||||||
|   "due_date": "2013-01-23", |  | ||||||
|   "items": [ |   "items": [ | ||||||
|    { |    { | ||||||
|     "amount": 500.0, |     "amount": 500.0, | ||||||
| @ -49,7 +48,6 @@ | |||||||
|    } |    } | ||||||
|   ], |   ], | ||||||
|   "plc_conversion_rate": 1.0, |   "plc_conversion_rate": 1.0, | ||||||
|   "posting_date": "2013-01-23", |  | ||||||
|   "price_list_currency": "INR", |   "price_list_currency": "INR", | ||||||
|   "sales_team": [ |   "sales_team": [ | ||||||
|    { |    { | ||||||
| @ -68,6 +66,8 @@ | |||||||
|   "selling_price_list": "_Test Price List", |   "selling_price_list": "_Test Price List", | ||||||
|   "territory": "_Test Territory" |   "territory": "_Test Territory" | ||||||
|  }, |  }, | ||||||
|  |   | ||||||
|  |   | ||||||
|  { |  { | ||||||
|   "company": "_Test Company", |   "company": "_Test Company", | ||||||
|   "conversion_rate": 1.0, |   "conversion_rate": 1.0, | ||||||
| @ -76,7 +76,6 @@ | |||||||
|   "customer_name": "_Test Customer", |   "customer_name": "_Test Customer", | ||||||
|   "debit_to": "_Test Receivable - _TC", |   "debit_to": "_Test Receivable - _TC", | ||||||
|   "doctype": "Sales Invoice", |   "doctype": "Sales Invoice", | ||||||
|   "due_date": "2013-03-07", |  | ||||||
|   "items": [ |   "items": [ | ||||||
|    { |    { | ||||||
|     "amount": 500.0, |     "amount": 500.0, | ||||||
| @ -94,7 +93,6 @@ | |||||||
|     "qty": 1.0 |     "qty": 1.0 | ||||||
|    } |    } | ||||||
|   ], |   ], | ||||||
|   "fiscal_year": "_Test Fiscal Year 2013", |  | ||||||
|   "base_grand_total": 630.0, |   "base_grand_total": 630.0, | ||||||
|   "grand_total": 630.0, |   "grand_total": 630.0, | ||||||
|   "is_pos": 0, |   "is_pos": 0, | ||||||
| @ -119,7 +117,6 @@ | |||||||
|    } |    } | ||||||
|   ], |   ], | ||||||
|   "plc_conversion_rate": 1.0, |   "plc_conversion_rate": 1.0, | ||||||
|   "posting_date": "2013-03-07", |  | ||||||
|   "price_list_currency": "INR", |   "price_list_currency": "INR", | ||||||
|   "selling_price_list": "_Test Price List", |   "selling_price_list": "_Test Price List", | ||||||
|   "territory": "_Test Territory" |   "territory": "_Test Territory" | ||||||
| @ -132,7 +129,6 @@ | |||||||
|   "customer_name": "_Test Customer", |   "customer_name": "_Test Customer", | ||||||
|   "debit_to": "_Test Receivable - _TC", |   "debit_to": "_Test Receivable - _TC", | ||||||
|   "doctype": "Sales Invoice", |   "doctype": "Sales Invoice", | ||||||
|   "due_date": "2013-01-23", |  | ||||||
|   "items": [ |   "items": [ | ||||||
|    { |    { | ||||||
|     "cost_center": "_Test Cost Center - _TC", |     "cost_center": "_Test Cost Center - _TC", | ||||||
| @ -245,7 +241,6 @@ | |||||||
|    } |    } | ||||||
|   ], |   ], | ||||||
|   "plc_conversion_rate": 1.0, |   "plc_conversion_rate": 1.0, | ||||||
|   "posting_date": "2013-01-23", |  | ||||||
|   "price_list_currency": "INR", |   "price_list_currency": "INR", | ||||||
|   "selling_price_list": "_Test Price List", |   "selling_price_list": "_Test Price List", | ||||||
|   "territory": "_Test Territory" |   "territory": "_Test Territory" | ||||||
| @ -258,7 +253,6 @@ | |||||||
|   "customer_name": "_Test Customer", |   "customer_name": "_Test Customer", | ||||||
|   "debit_to": "_Test Receivable - _TC", |   "debit_to": "_Test Receivable - _TC", | ||||||
|   "doctype": "Sales Invoice", |   "doctype": "Sales Invoice", | ||||||
|   "due_date": "2013-01-23", |  | ||||||
|   "items": [ |   "items": [ | ||||||
|    { |    { | ||||||
|     "cost_center": "_Test Cost Center - _TC", |     "cost_center": "_Test Cost Center - _TC", | ||||||
| @ -382,7 +376,6 @@ | |||||||
|    } |    } | ||||||
|   ], |   ], | ||||||
|   "plc_conversion_rate": 1.0, |   "plc_conversion_rate": 1.0, | ||||||
|   "posting_date": "2013-01-23", |  | ||||||
|   "price_list_currency": "INR", |   "price_list_currency": "INR", | ||||||
|   "selling_price_list": "_Test Price List", |   "selling_price_list": "_Test Price List", | ||||||
|   "territory": "_Test Territory" |   "territory": "_Test Territory" | ||||||
|  | |||||||
| @ -3,8 +3,7 @@ | |||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
| 
 | 
 | ||||||
| import frappe | import frappe | ||||||
| import unittest, json, copy | import unittest, copy | ||||||
| from frappe.utils import flt |  | ||||||
| from erpnext.accounts.utils import get_stock_and_account_difference | from erpnext.accounts.utils import get_stock_and_account_difference | ||||||
| from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory | from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory | ||||||
| from erpnext.projects.doctype.time_log_batch.test_time_log_batch import * | from erpnext.projects.doctype.time_log_batch.test_time_log_batch import * | ||||||
| @ -93,8 +92,8 @@ class TestSalesInvoice(unittest.TestCase): | |||||||
| 		expected_values = { | 		expected_values = { | ||||||
| 			"keys": ["price_list_rate", "discount_percentage", "rate", "amount", | 			"keys": ["price_list_rate", "discount_percentage", "rate", "amount", | ||||||
| 				"base_price_list_rate", "base_rate", "base_amount"], | 				"base_price_list_rate", "base_rate", "base_amount"], | ||||||
| 			"_Test Item Home Desktop 100": [50, 0, 50, 500, 2500, 2500, 25000], | 			"_Test Item Home Desktop 100": [1, 0, 1, 10, 50, 50, 500], | ||||||
| 			"_Test Item Home Desktop 200": [150, 0, 150, 750, 7500, 7500, 37500], | 			"_Test Item Home Desktop 200": [3, 0, 3, 15, 150, 150, 750], | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		# check if children are saved | 		# check if children are saved | ||||||
| @ -106,8 +105,10 @@ class TestSalesInvoice(unittest.TestCase): | |||||||
| 				self.assertEquals(d.get(k), expected_values[d.item_code][i]) | 				self.assertEquals(d.get(k), expected_values[d.item_code][i]) | ||||||
| 
 | 
 | ||||||
| 		# check net total | 		# check net total | ||||||
| 		self.assertEquals(si.net_total, 1250) | 		self.assertEquals(si.total, 25) | ||||||
| 		self.assertEquals(si.base_net_total, 62500) | 		self.assertEquals(si.base_total, 1250) | ||||||
|  | 		self.assertEquals(si.net_total, 25) | ||||||
|  | 		self.assertEquals(si.base_net_total, 1250) | ||||||
| 
 | 
 | ||||||
| 		# check tax calculation | 		# check tax calculation | ||||||
| 		expected_values = { | 		expected_values = { | ||||||
| @ -385,7 +386,6 @@ class TestSalesInvoice(unittest.TestCase): | |||||||
| 		self.assertEquals(w.outstanding_amount, w.base_grand_total) | 		self.assertEquals(w.outstanding_amount, w.base_grand_total) | ||||||
| 
 | 
 | ||||||
| 	def test_payment(self): | 	def test_payment(self): | ||||||
| 		frappe.db.sql("""delete from `tabGL Entry`""") |  | ||||||
| 		w = self.make() | 		w = self.make() | ||||||
| 
 | 
 | ||||||
| 		from erpnext.accounts.doctype.journal_entry.test_journal_entry \ | 		from erpnext.accounts.doctype.journal_entry.test_journal_entry \ | ||||||
| @ -396,12 +396,10 @@ class TestSalesInvoice(unittest.TestCase): | |||||||
| 		jv.insert() | 		jv.insert() | ||||||
| 		jv.submit() | 		jv.submit() | ||||||
| 
 | 
 | ||||||
| 		self.assertEquals(frappe.db.get_value("Sales Invoice", w.name, "outstanding_amount"), | 		self.assertEquals(frappe.db.get_value("Sales Invoice", w.name, "outstanding_amount"), 161.8) | ||||||
| 			161.8) |  | ||||||
| 
 | 
 | ||||||
| 		jv.cancel() | 		jv.cancel() | ||||||
| 		self.assertEquals(frappe.db.get_value("Sales Invoice", w.name, "outstanding_amount"), | 		self.assertEquals(frappe.db.get_value("Sales Invoice", w.name, "outstanding_amount"), 561.8) | ||||||
| 			561.8) |  | ||||||
| 
 | 
 | ||||||
| 	def test_time_log_batch(self): | 	def test_time_log_batch(self): | ||||||
| 		delete_time_log_and_batch() | 		delete_time_log_and_batch() | ||||||
| @ -430,7 +428,6 @@ class TestSalesInvoice(unittest.TestCase): | |||||||
| 		delete_time_log_and_batch() | 		delete_time_log_and_batch() | ||||||
| 
 | 
 | ||||||
| 	def test_sales_invoice_gl_entry_without_aii(self): | 	def test_sales_invoice_gl_entry_without_aii(self): | ||||||
| 		self.clear_stock_account_balance() |  | ||||||
| 		set_perpetual_inventory(0) | 		set_perpetual_inventory(0) | ||||||
| 		si = frappe.copy_doc(test_records[1]) | 		si = frappe.copy_doc(test_records[1]) | ||||||
| 		si.insert() | 		si.insert() | ||||||
| @ -463,7 +460,6 @@ class TestSalesInvoice(unittest.TestCase): | |||||||
| 		self.assertFalse(gle) | 		self.assertFalse(gle) | ||||||
| 
 | 
 | ||||||
| 	def test_pos_gl_entry_with_aii(self): | 	def test_pos_gl_entry_with_aii(self): | ||||||
| 		self.clear_stock_account_balance() |  | ||||||
| 		set_perpetual_inventory() | 		set_perpetual_inventory() | ||||||
| 		self.make_pos_setting() | 		self.make_pos_setting() | ||||||
| 
 | 
 | ||||||
| @ -501,8 +497,8 @@ class TestSalesInvoice(unittest.TestCase): | |||||||
| 			[pos["items"][0]["income_account"], 0.0, 500.0], | 			[pos["items"][0]["income_account"], 0.0, 500.0], | ||||||
| 			[pos["taxes"][0]["account_head"], 0.0, 80.0], | 			[pos["taxes"][0]["account_head"], 0.0, 80.0], | ||||||
| 			[pos["taxes"][1]["account_head"], 0.0, 50.0], | 			[pos["taxes"][1]["account_head"], 0.0, 50.0], | ||||||
| 			[stock_in_hand, 0.0, 75.0], | 			[stock_in_hand, 0.0, abs(sle.stock_value_difference)], | ||||||
| 			[pos["items"][0]["expense_account"], 75.0, 0.0], | 			[pos["items"][0]["expense_account"], abs(sle.stock_value_difference), 0.0], | ||||||
| 			[si.debit_to, 0.0, 600.0], | 			[si.debit_to, 0.0, 600.0], | ||||||
| 			["_Test Account Bank Account - _TC", 600.0, 0.0] | 			["_Test Account Bank Account - _TC", 600.0, 0.0] | ||||||
| 		]) | 		]) | ||||||
| @ -545,7 +541,6 @@ class TestSalesInvoice(unittest.TestCase): | |||||||
| 			pos_setting.insert() | 			pos_setting.insert() | ||||||
| 
 | 
 | ||||||
| 	def test_si_gl_entry_with_aii_and_update_stock_with_warehouse_but_no_account(self): | 	def test_si_gl_entry_with_aii_and_update_stock_with_warehouse_but_no_account(self): | ||||||
| 		self.clear_stock_account_balance() |  | ||||||
| 		set_perpetual_inventory() | 		set_perpetual_inventory() | ||||||
| 		frappe.delete_doc("Account", "_Test Warehouse No Account - _TC") | 		frappe.delete_doc("Account", "_Test Warehouse No Account - _TC") | ||||||
| 
 | 
 | ||||||
| @ -600,7 +595,6 @@ class TestSalesInvoice(unittest.TestCase): | |||||||
| 		set_perpetual_inventory(0) | 		set_perpetual_inventory(0) | ||||||
| 
 | 
 | ||||||
| 	def test_sales_invoice_gl_entry_with_aii_no_item_code(self): | 	def test_sales_invoice_gl_entry_with_aii_no_item_code(self): | ||||||
| 		self.clear_stock_account_balance() |  | ||||||
| 		set_perpetual_inventory() | 		set_perpetual_inventory() | ||||||
| 
 | 
 | ||||||
| 		si = frappe.get_doc(test_records[1]) | 		si = frappe.get_doc(test_records[1]) | ||||||
| @ -627,7 +621,6 @@ class TestSalesInvoice(unittest.TestCase): | |||||||
| 		set_perpetual_inventory(0) | 		set_perpetual_inventory(0) | ||||||
| 
 | 
 | ||||||
| 	def test_sales_invoice_gl_entry_with_aii_non_stock_item(self): | 	def test_sales_invoice_gl_entry_with_aii_non_stock_item(self): | ||||||
| 		self.clear_stock_account_balance() |  | ||||||
| 		set_perpetual_inventory() | 		set_perpetual_inventory() | ||||||
| 		si = frappe.get_doc(test_records[1]) | 		si = frappe.get_doc(test_records[1]) | ||||||
| 		si.get("items")[0].item_code = "_Test Non Stock Item" | 		si.get("items")[0].item_code = "_Test Non Stock Item" | ||||||
| @ -705,14 +698,8 @@ class TestSalesInvoice(unittest.TestCase): | |||||||
| 
 | 
 | ||||||
| 	def test_recurring_invoice(self): | 	def test_recurring_invoice(self): | ||||||
| 		from erpnext.controllers.tests.test_recurring_document import test_recurring_document | 		from erpnext.controllers.tests.test_recurring_document import test_recurring_document | ||||||
| 
 |  | ||||||
| 		test_recurring_document(self, test_records) | 		test_recurring_document(self, test_records) | ||||||
| 
 | 
 | ||||||
| 	def clear_stock_account_balance(self): |  | ||||||
| 		frappe.db.sql("delete from `tabStock Ledger Entry`") |  | ||||||
| 		frappe.db.sql("delete from tabBin") |  | ||||||
| 		frappe.db.sql("delete from `tabGL Entry`") |  | ||||||
| 
 |  | ||||||
| 	def test_serialized(self): | 	def test_serialized(self): | ||||||
| 		from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item | 		from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item | ||||||
| 		from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos | 		from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos | ||||||
| @ -767,5 +754,35 @@ class TestSalesInvoice(unittest.TestCase): | |||||||
| 
 | 
 | ||||||
| 		self.assertRaises(SerialNoStatusError, si.submit) | 		self.assertRaises(SerialNoStatusError, si.submit) | ||||||
| 		 | 		 | ||||||
|  | def create_sales_invoice(**args): | ||||||
|  | 	si = frappe.new_doc("Sales Invoice") | ||||||
|  | 	args = frappe._dict(args) | ||||||
|  | 	if args.posting_date: | ||||||
|  | 		si.posting_date = args.posting_date | ||||||
|  | 	if args.posting_time: | ||||||
|  | 		si.posting_time = args.posting_time | ||||||
|  | 	 | ||||||
|  | 	si.company = args.company or "_Test Company" | ||||||
|  | 	si.customer = args.customer or "_Test Customer" | ||||||
|  | 	si.debit_to = args.debit_to or "Debtors - _TC" | ||||||
|  | 	si.update_stock = args.update_stock | ||||||
|  | 	si.is_pos = args.is_pos | ||||||
|  | 	 | ||||||
|  | 	si.append("items", { | ||||||
|  | 		"item_code": args.item or args.item_code or "_Test Item", | ||||||
|  | 		"warehouse": args.warehouse or "_Test Warehouse - _TC", | ||||||
|  | 		"qty": args.qty or 1, | ||||||
|  | 		"rate": args.rate or 100, | ||||||
|  | 		"expense_account": "Cost of Goods Sold - _TC", | ||||||
|  | 		"cost_center": "_Test Cost Center - _TC", | ||||||
|  | 		"serial_no": args.serial_no | ||||||
|  | 	}) | ||||||
|  | 	 | ||||||
|  | 	if not args.do_not_save: | ||||||
|  | 		si.insert() | ||||||
|  | 		if not args.do_not_submit: | ||||||
|  | 			si.submit() | ||||||
|  | 	return si | ||||||
|  | 
 | ||||||
| test_dependencies = ["Journal Entry", "Contact", "Address"] | test_dependencies = ["Journal Entry", "Contact", "Address"] | ||||||
| test_records = frappe.get_test_records('Sales Invoice') | test_records = frappe.get_test_records('Sales Invoice') | ||||||
|  | |||||||
| @ -5,119 +5,106 @@ from __future__ import unicode_literals | |||||||
| import unittest | import unittest | ||||||
| import frappe | import frappe | ||||||
| import frappe.defaults | import frappe.defaults | ||||||
| from frappe.utils import flt | from frappe.utils import flt, add_days, nowdate | ||||||
|  | from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_receipt, make_purchase_invoice | ||||||
| 
 | 
 | ||||||
| class TestPurchaseOrder(unittest.TestCase): | class TestPurchaseOrder(unittest.TestCase): | ||||||
| 	def test_make_purchase_receipt(self): | 	def test_make_purchase_receipt(self): | ||||||
| 		from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_receipt | 		po = create_purchase_order(do_not_submit=True) | ||||||
| 
 | 		self.assertRaises(frappe.ValidationError, make_purchase_receipt, po.name) | ||||||
| 		po = frappe.copy_doc(test_records[0]).insert() |  | ||||||
| 
 |  | ||||||
| 		self.assertRaises(frappe.ValidationError, make_purchase_receipt, |  | ||||||
| 			po.name) |  | ||||||
| 
 |  | ||||||
| 		po = frappe.get_doc("Purchase Order", po.name) |  | ||||||
| 		po.submit() | 		po.submit() | ||||||
| 
 | 
 | ||||||
| 		pr = make_purchase_receipt(po.name) | 		pr = create_pr_against_po(po.name) | ||||||
| 		pr.supplier_warehouse = "_Test Warehouse 1 - _TC" | 		self.assertEquals(len(pr.get("items")), 1) | ||||||
| 		pr.posting_date = "2013-05-12" |  | ||||||
| 		self.assertEquals(pr.doctype, "Purchase Receipt") |  | ||||||
| 		self.assertEquals(len(pr.get("items")), len(test_records[0]["items"])) |  | ||||||
| 
 |  | ||||||
| 		pr.naming_series = "_T-Purchase Receipt-" |  | ||||||
| 		frappe.get_doc(pr).insert() |  | ||||||
| 
 | 
 | ||||||
| 	def test_ordered_qty(self): | 	def test_ordered_qty(self): | ||||||
| 		existing_ordered_qty = self._get_ordered_qty("_Test Item", "_Test Warehouse - _TC") | 		existing_ordered_qty = get_ordered_qty() | ||||||
| 		from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_receipt |  | ||||||
| 
 |  | ||||||
| 		po = frappe.copy_doc(test_records[0]).insert() |  | ||||||
| 		 | 		 | ||||||
|  | 		po = create_purchase_order(do_not_submit=True) | ||||||
| 		self.assertRaises(frappe.ValidationError, make_purchase_receipt, po.name) | 		self.assertRaises(frappe.ValidationError, make_purchase_receipt, po.name) | ||||||
| 		 | 		 | ||||||
| 		po = frappe.get_doc("Purchase Order", po.name) |  | ||||||
| 		po.is_subcontracted = "No" |  | ||||||
| 		po.get("items")[0].item_code = "_Test Item" |  | ||||||
| 		po.submit() | 		po.submit() | ||||||
|  | 		self.assertEqual(get_ordered_qty(), existing_ordered_qty + 10) | ||||||
| 
 | 
 | ||||||
| 		self.assertEquals(self._get_ordered_qty("_Test Item", "_Test Warehouse - _TC"), existing_ordered_qty + 10) | 		create_pr_against_po(po.name)	 | ||||||
| 
 | 		self.assertEqual(get_ordered_qty(), existing_ordered_qty + 6) | ||||||
| 		pr = make_purchase_receipt(po.name) |  | ||||||
| 
 |  | ||||||
| 		self.assertEquals(pr.doctype, "Purchase Receipt") |  | ||||||
| 		self.assertEquals(len(pr.get("items", [])), len(test_records[0]["items"])) |  | ||||||
| 		pr.posting_date = "2013-05-12" |  | ||||||
| 		pr.naming_series = "_T-Purchase Receipt-" |  | ||||||
| 		pr.items[0].qty = 4.0 |  | ||||||
| 		pr.insert() |  | ||||||
| 		pr.submit() |  | ||||||
| 		 | 		 | ||||||
| 		po.load_from_db() | 		po.load_from_db() | ||||||
| 		self.assertEquals(po.get("items")[0].received_qty, 4) | 		self.assertEquals(po.get("items")[0].received_qty, 4) | ||||||
| 		self.assertEquals(self._get_ordered_qty("_Test Item", "_Test Warehouse - _TC"), existing_ordered_qty + 6) |  | ||||||
| 
 | 
 | ||||||
| 		frappe.db.set_value('Item', '_Test Item', 'tolerance', 50) | 		frappe.db.set_value('Item', '_Test Item', 'tolerance', 50) | ||||||
| 
 | 
 | ||||||
| 		pr1 = make_purchase_receipt(po.name) | 		pr = create_pr_against_po(po.name, received_qty=8) | ||||||
| 		pr1.naming_series = "_T-Purchase Receipt-" | 		self.assertEqual(get_ordered_qty(), existing_ordered_qty) | ||||||
| 		pr1.posting_date = "2013-05-12" |  | ||||||
| 		pr1.get("items")[0].qty = 8 |  | ||||||
| 		pr1.insert() |  | ||||||
| 		pr1.submit() |  | ||||||
| 		 | 		 | ||||||
| 		po.load_from_db() | 		po.load_from_db() | ||||||
| 		self.assertEquals(po.get("items")[0].received_qty, 12) | 		self.assertEquals(po.get("items")[0].received_qty, 12) | ||||||
| 		self.assertEquals(self._get_ordered_qty("_Test Item", "_Test Warehouse - _TC"), existing_ordered_qty) |  | ||||||
| 
 | 
 | ||||||
| 		pr1.load_from_db() | 		pr.cancel() | ||||||
| 		pr1.cancel() | 		self.assertEqual(get_ordered_qty(), existing_ordered_qty + 6) | ||||||
| 		 | 		 | ||||||
| 		po.load_from_db() | 		po.load_from_db() | ||||||
| 		self.assertEquals(po.get("items")[0].received_qty, 4) | 		self.assertEquals(po.get("items")[0].received_qty, 4) | ||||||
| 		self.assertEquals(self._get_ordered_qty("_Test Item", "_Test Warehouse - _TC"), existing_ordered_qty + 6) |  | ||||||
| 
 | 
 | ||||||
| 	def test_make_purchase_invoice(self): | 	def test_make_purchase_invoice(self): | ||||||
| 		from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_invoice | 		po = create_purchase_order(do_not_submit=True) | ||||||
| 
 | 
 | ||||||
| 		po = frappe.copy_doc(test_records[0]).insert() | 		self.assertRaises(frappe.ValidationError, make_purchase_invoice, po.name) | ||||||
| 
 | 
 | ||||||
| 		self.assertRaises(frappe.ValidationError, make_purchase_invoice, |  | ||||||
| 			po.name) |  | ||||||
| 
 |  | ||||||
| 		po = frappe.get_doc("Purchase Order", po.name) |  | ||||||
| 		po.submit() | 		po.submit() | ||||||
| 		pi = make_purchase_invoice(po.name) | 		pi = make_purchase_invoice(po.name) | ||||||
| 
 | 
 | ||||||
| 		self.assertEquals(pi.doctype, "Purchase Invoice") | 		self.assertEquals(pi.doctype, "Purchase Invoice") | ||||||
| 		self.assertEquals(len(pi.get("items", [])), len(test_records[0]["items"])) | 		self.assertEquals(len(pi.get("items", [])), 1) | ||||||
| 
 |  | ||||||
| 		pi.credit_to = "_Test Payable - _TC" |  | ||||||
| 		pi.posting_date = "2013-05-12" |  | ||||||
| 		pi.bill_no = "NA" |  | ||||||
| 		frappe.get_doc(pi).insert() |  | ||||||
| 
 | 
 | ||||||
| 	def test_subcontracting(self): | 	def test_subcontracting(self): | ||||||
| 		po = frappe.copy_doc(test_records[0]) | 		po = create_purchase_order(item_code="_Test FG Item", is_subcontracted="Yes") | ||||||
| 		po.insert() |  | ||||||
| 		self.assertEquals(len(po.get("supplied_items")), 2) | 		self.assertEquals(len(po.get("supplied_items")), 2) | ||||||
| 
 | 
 | ||||||
| 	def test_warehouse_company_validation(self): | 	def test_warehouse_company_validation(self): | ||||||
| 		from erpnext.stock.utils import InvalidWarehouseCompany | 		from erpnext.stock.utils import InvalidWarehouseCompany | ||||||
| 		po = frappe.copy_doc(test_records[0]) | 		po = create_purchase_order(company="_Test Company 1", do_not_save=True) | ||||||
| 		po.company = "_Test Company 1" |  | ||||||
| 		po.conversion_rate = 0.0167 |  | ||||||
| 		self.assertRaises(InvalidWarehouseCompany, po.insert) | 		self.assertRaises(InvalidWarehouseCompany, po.insert) | ||||||
| 
 | 
 | ||||||
| 	def test_uom_integer_validation(self): | 	def test_uom_integer_validation(self): | ||||||
| 		from erpnext.utilities.transaction_base import UOMMustBeIntegerError | 		from erpnext.utilities.transaction_base import UOMMustBeIntegerError | ||||||
| 		po = frappe.copy_doc(test_records[0]) | 		po = create_purchase_order(qty=3.4, do_not_save=True) | ||||||
| 		po.get("items")[0].qty = 3.4 |  | ||||||
| 		self.assertRaises(UOMMustBeIntegerError, po.insert) | 		self.assertRaises(UOMMustBeIntegerError, po.insert) | ||||||
| 
 | 
 | ||||||
| 	def _get_ordered_qty(self, item_code, warehouse): | def create_purchase_order(**args): | ||||||
| 		return flt(frappe.db.get_value("Bin", {"item_code": item_code, "warehouse": warehouse}, "ordered_qty")) | 	po = frappe.new_doc("Purchase Order") | ||||||
|  | 	args = frappe._dict(args) | ||||||
|  | 	if args.transaction_date: | ||||||
|  | 		po.transaction_date = args.transaction_date | ||||||
| 
 | 
 | ||||||
|  | 	po.company = args.company or "_Test Company" | ||||||
|  | 	po.supplier = args.customer or "_Test Supplier" | ||||||
|  | 	po.is_subcontracted = args.is_subcontracted or "No" | ||||||
|  | 
 | ||||||
|  | 	po.append("items", { | ||||||
|  | 		"item_code": args.item or args.item_code or "_Test Item", | ||||||
|  | 		"warehouse": args.warehouse or "_Test Warehouse - _TC", | ||||||
|  | 		"qty": args.qty or 10, | ||||||
|  | 		"rate": args.rate or 500, | ||||||
|  | 		"schedule_date": add_days(nowdate(), 1) | ||||||
|  | 	}) | ||||||
|  | 	if not args.do_not_save: | ||||||
|  | 		po.insert() | ||||||
|  | 		if not args.do_not_submit: | ||||||
|  | 			po.submit() | ||||||
|  | 			 | ||||||
|  | 	return po | ||||||
|  | 	 | ||||||
|  | def create_pr_against_po(po, received_qty=4): | ||||||
|  | 	pr = make_purchase_receipt(po) | ||||||
|  | 	pr.get("items")[0].qty = received_qty | ||||||
|  | 	pr.insert() | ||||||
|  | 	pr.submit() | ||||||
|  | 	return pr | ||||||
|  | 
 | ||||||
|  | def get_ordered_qty(item_code="_Test Item", warehouse="_Test Warehouse - _TC"): | ||||||
|  | 	return flt(frappe.db.get_value("Bin", {"item_code": item_code, "warehouse": warehouse}, | ||||||
|  | 		"ordered_qty")) | ||||||
| 
 | 
 | ||||||
| test_dependencies = ["BOM", "Item Price"] | test_dependencies = ["BOM", "Item Price"] | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -6,7 +6,7 @@ | |||||||
|   "fg_warehouse": "_Test Warehouse 1 - _TC",  |   "fg_warehouse": "_Test Warehouse 1 - _TC",  | ||||||
|   "production_item": "_Test FG Item",  |   "production_item": "_Test FG Item",  | ||||||
|   "qty": 10.0,  |   "qty": 10.0,  | ||||||
|   "stock_uom": "Nos",  |   "stock_uom": "_Test UOM",  | ||||||
|   "wip_warehouse": "_Test Warehouse - _TC" |   "wip_warehouse": "_Test Warehouse - _TC" | ||||||
|  } |  } | ||||||
| ] | ] | ||||||
| @ -1,342 +1,190 @@ | |||||||
| # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors | # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors | ||||||
| # License: GNU General Public License v3. See license.txt | # License: GNU General Public License v3. See license.txt | ||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
| 
 |  | ||||||
| import frappe | import frappe | ||||||
| from frappe.utils import flt | from frappe.utils import flt, add_days | ||||||
| import frappe.permissions | import frappe.permissions | ||||||
| import unittest | import unittest | ||||||
| import copy | from erpnext.selling.doctype.sales_order.sales_order \ | ||||||
|  | 	import make_material_request, make_delivery_note, make_sales_invoice | ||||||
| 
 | 
 | ||||||
| class TestSalesOrder(unittest.TestCase): | class TestSalesOrder(unittest.TestCase): | ||||||
| 	def tearDown(self): | 	def tearDown(self): | ||||||
| 		frappe.set_user("Administrator") | 		frappe.set_user("Administrator") | ||||||
| 
 | 
 | ||||||
| 	def test_make_material_request(self): | 	def test_make_material_request(self): | ||||||
| 		from erpnext.selling.doctype.sales_order.sales_order import make_material_request | 		so = make_sales_order(do_not_submit=True) | ||||||
| 
 | 
 | ||||||
| 		so = frappe.copy_doc(test_records[0]).insert() | 		self.assertRaises(frappe.ValidationError, make_material_request, so.name) | ||||||
| 
 | 
 | ||||||
| 		self.assertRaises(frappe.ValidationError, make_material_request, | 		so.submit() | ||||||
| 			so.name) |  | ||||||
| 
 |  | ||||||
| 		sales_order = frappe.get_doc("Sales Order", so.name) |  | ||||||
| 		sales_order.submit() |  | ||||||
| 		mr = make_material_request(so.name) | 		mr = make_material_request(so.name) | ||||||
| 
 | 
 | ||||||
| 		self.assertEquals(mr.material_request_type, "Purchase") | 		self.assertEquals(mr.material_request_type, "Purchase") | ||||||
| 		self.assertEquals(len(mr.get("items")), len(sales_order.get("items"))) | 		self.assertEquals(len(mr.get("items")), len(so.get("items"))) | ||||||
| 
 | 
 | ||||||
| 	def test_make_delivery_note(self): | 	def test_make_delivery_note(self): | ||||||
| 		from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note | 		so = make_sales_order(do_not_submit=True) | ||||||
| 
 | 
 | ||||||
| 		so = frappe.copy_doc(test_records[0]).insert() | 		self.assertRaises(frappe.ValidationError, make_delivery_note, so.name) | ||||||
| 
 | 
 | ||||||
| 		self.assertRaises(frappe.ValidationError, make_delivery_note, | 		so.submit() | ||||||
| 			so.name) | 		dn = make_delivery_note(so.name) | ||||||
| 
 |  | ||||||
| 		dn = self.make_next_doc_testcase(so, "Delivery Note") |  | ||||||
| 
 | 
 | ||||||
| 		self.assertEquals(dn.doctype, "Delivery Note") | 		self.assertEquals(dn.doctype, "Delivery Note") | ||||||
| 		self.assertEquals(len(dn.get("items")), len(so.get("items"))) | 		self.assertEquals(len(dn.get("items")), len(so.get("items"))) | ||||||
| 
 | 
 | ||||||
| 	def test_make_sales_invoice(self): | 	def test_make_sales_invoice(self): | ||||||
| 		from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice | 		so = make_sales_order(do_not_submit=True) | ||||||
| 
 | 
 | ||||||
| 		so = frappe.copy_doc(test_records[0]).insert() | 		self.assertRaises(frappe.ValidationError, make_sales_invoice, so.name) | ||||||
| 
 | 
 | ||||||
| 		self.assertRaises(frappe.ValidationError, make_sales_invoice, | 		so.submit() | ||||||
| 			so.name) | 		si = make_sales_invoice(so.name) | ||||||
| 
 | 
 | ||||||
| 		si = self.make_next_doc_testcase(so, "Sales Invoice") |  | ||||||
| 
 |  | ||||||
| 		self.assertEquals(si.doctype, "Sales Invoice") |  | ||||||
| 		self.assertEquals(len(si.get("items")), len(so.get("items"))) | 		self.assertEquals(len(si.get("items")), len(so.get("items"))) | ||||||
| 		self.assertEquals(len(si.get("items")), 1) | 		self.assertEquals(len(si.get("items")), 1) | ||||||
| 
 | 
 | ||||||
| 		si.set("debit_to", "_Test Receivable - _TC") |  | ||||||
| 		si.set("posting_date", "2013-10-10") |  | ||||||
| 		si.insert() | 		si.insert() | ||||||
| 		si.submit() | 		si.submit() | ||||||
| 
 | 
 | ||||||
| 		si1 = self.make_next_doc_testcase(so, "Sales Invoice") | 		si1 = make_sales_invoice(so.name) | ||||||
| 		self.assertEquals(len(si1.get("items")), 0) | 		self.assertEquals(len(si1.get("items")), 0) | ||||||
| 
 | 
 | ||||||
| 	def test_update_qty(self): | 	def test_update_qty(self): | ||||||
| 		so = frappe.copy_doc(test_records[0]).insert() | 		so = make_sales_order() | ||||||
| 
 | 
 | ||||||
| 		dn = self.make_next_doc_testcase(so, "Delivery Note") | 		create_dn_against_so(so.name, 6) | ||||||
| 
 | 
 | ||||||
| 		dn.get("items")[0].qty = 6 | 		so.load_from_db() | ||||||
| 		dn.posting_date = "2013-10-10" | 		self.assertEquals(so.get("items")[0].delivered_qty, 6) | ||||||
| 		dn.insert() |  | ||||||
| 
 | 
 | ||||||
| 		delivery_note = frappe.get_doc("Delivery Note", dn.name) | 		# Check delivered_qty after make_sales_invoice without update_stock checked | ||||||
| 		delivery_note.submit() | 		si1 = make_sales_invoice(so.name) | ||||||
| 
 | 		si1.get("items")[0].qty = 6 | ||||||
| 		sales_order = frappe.get_doc("Sales Order", so.name) |  | ||||||
| 
 |  | ||||||
| 		self.assertEquals(sales_order.get("items")[0].delivered_qty, 6) |  | ||||||
| 
 |  | ||||||
| 		#Check delivered_qty after make_sales_invoice without update_stock checked |  | ||||||
| 		si1 = self.make_next_doc_testcase(sales_order, "Sales Invoice") |  | ||||||
| 
 |  | ||||||
| 		si1.set("debit_to", "_Test Receivable - _TC") |  | ||||||
| 		si1.set("posting_date", "2013-10-10") |  | ||||||
| 		si1.get("items")[0].qty = 1 |  | ||||||
| 		si1.insert() | 		si1.insert() | ||||||
| 		si1.submit() | 		si1.submit() | ||||||
| 
 | 
 | ||||||
| 		sales_order = frappe.get_doc("Sales Order", sales_order.name) | 		so.load_from_db() | ||||||
|  | 		self.assertEquals(so.get("items")[0].delivered_qty, 6) | ||||||
| 
 | 
 | ||||||
| 		self.assertEquals(sales_order.get("items")[0].delivered_qty, 6) | 		# Check delivered_qty after make_sales_invoice with update_stock checked | ||||||
| 
 | 		si2 = make_sales_invoice(so.name) | ||||||
| 		#Check delivered_qty after make_sales_invoice with update_stock checked |  | ||||||
| 		si2 = self.make_next_doc_testcase(sales_order, "Sales Invoice") |  | ||||||
| 
 |  | ||||||
| 		si2.set("debit_to", "_Test Receivable - _TC") |  | ||||||
| 		si2.set("posting_date", "2013-10-10") |  | ||||||
| 		si2.set("update_stock", 1) | 		si2.set("update_stock", 1) | ||||||
| 		si2.get("items")[0].qty = 3 | 		si2.get("items")[0].qty = 3 | ||||||
| 		si2.insert() | 		si2.insert() | ||||||
| 		si2.submit() | 		si2.submit() | ||||||
| 
 | 
 | ||||||
| 		sales_order = frappe.get_doc("Sales Order", sales_order.name) | 		so.load_from_db() | ||||||
| 
 | 		self.assertEquals(so.get("items")[0].delivered_qty, 9) | ||||||
| 		self.assertEquals(sales_order.get("items")[0].delivered_qty, 9) |  | ||||||
| 
 |  | ||||||
| 	def make_next_doc_testcase(self, so, next_doc = None): |  | ||||||
| 
 |  | ||||||
| 		if so.docstatus < 1: |  | ||||||
| 			so.submit() |  | ||||||
| 
 |  | ||||||
| 		if next_doc == "Delivery Note": |  | ||||||
| 			from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note |  | ||||||
| 			next_doc = make_delivery_note(so.name) |  | ||||||
| 
 |  | ||||||
| 		if next_doc == "Sales Invoice": |  | ||||||
| 			from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice |  | ||||||
| 			next_doc = make_sales_invoice(so.name) |  | ||||||
| 
 |  | ||||||
| 		return next_doc |  | ||||||
| 
 |  | ||||||
| 	def create_so(self, so_doc = None): |  | ||||||
| 		if not so_doc: |  | ||||||
| 			so_doc = test_records[0] |  | ||||||
| 
 |  | ||||||
| 		w = frappe.copy_doc(so_doc) |  | ||||||
| 		w.insert() |  | ||||||
| 		w.submit() |  | ||||||
| 
 |  | ||||||
| 		return w |  | ||||||
| 
 |  | ||||||
| 	def create_dn_against_so(self, so, delivered_qty=0): |  | ||||||
| 		from erpnext.stock.doctype.delivery_note.test_delivery_note import test_records as dn_test_records |  | ||||||
| 		from erpnext.stock.doctype.delivery_note.test_delivery_note import _insert_purchase_receipt |  | ||||||
| 
 |  | ||||||
| 		_insert_purchase_receipt(so.get("items")[0].item_code) |  | ||||||
| 
 |  | ||||||
| 		dn = frappe.get_doc(frappe.copy_doc(dn_test_records[0])) |  | ||||||
| 		dn.get("items")[0].item_code = so.get("items")[0].item_code |  | ||||||
| 		dn.get("items")[0].against_sales_order = so.name |  | ||||||
| 		dn.get("items")[0].so_detail = so.get("items")[0].name |  | ||||||
| 		if delivered_qty: |  | ||||||
| 			dn.get("items")[0].qty = delivered_qty |  | ||||||
| 		dn.insert() |  | ||||||
| 		dn.submit() |  | ||||||
| 		return dn |  | ||||||
| 
 |  | ||||||
| 	def get_bin_reserved_qty(self, item_code, warehouse): |  | ||||||
| 		return flt(frappe.db.get_value("Bin", {"item_code": item_code, "warehouse": warehouse}, |  | ||||||
| 			"reserved_qty")) |  | ||||||
| 
 |  | ||||||
| 	def delete_bin(self, item_code, warehouse): |  | ||||||
| 		bin = frappe.db.exists({"doctype": "Bin", "item_code": item_code, |  | ||||||
| 			"warehouse": warehouse}) |  | ||||||
| 		if bin: |  | ||||||
| 			frappe.delete_doc("Bin", bin[0][0]) |  | ||||||
| 
 |  | ||||||
| 	def check_reserved_qty(self, item_code, warehouse, qty): |  | ||||||
| 		bin_reserved_qty = self.get_bin_reserved_qty(item_code, warehouse) |  | ||||||
| 		self.assertEqual(bin_reserved_qty, qty) |  | ||||||
| 
 |  | ||||||
| 	def test_reserved_qty_for_so(self): |  | ||||||
| 		# reset bin |  | ||||||
| 		so_item = test_records[0]["items"][0].copy() |  | ||||||
| 		self.delete_bin(so_item["item_code"], so_item["warehouse"]) |  | ||||||
| 
 |  | ||||||
| 		# submit |  | ||||||
| 		so = self.create_so() |  | ||||||
| 		self.check_reserved_qty(so.get("items")[0].item_code, so.get("items")[0].warehouse, 10.0) |  | ||||||
| 
 |  | ||||||
| 		# cancel |  | ||||||
| 		so.cancel() |  | ||||||
| 		self.check_reserved_qty(so.get("items")[0].item_code, so.get("items")[0].warehouse, 0.0) |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| 	def test_reserved_qty_for_partial_delivery(self): | 	def test_reserved_qty_for_partial_delivery(self): | ||||||
| 		# reset bin | 		existing_reserved_qty = get_reserved_qty() | ||||||
| 		so_item = test_records[0]["items"][0].copy() |  | ||||||
| 		self.delete_bin(so_item["item_code"], so_item["warehouse"]) |  | ||||||
| 		 | 		 | ||||||
| 		# submit so | 		so = make_sales_order() | ||||||
| 		so = self.create_so() | 		self.assertEqual(get_reserved_qty(), existing_reserved_qty + 10) | ||||||
| 
 | 
 | ||||||
| 		# allow negative stock | 		dn = create_dn_against_so(so.name) | ||||||
| 		frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1) | 		self.assertEqual(get_reserved_qty(), existing_reserved_qty + 5) | ||||||
| 
 |  | ||||||
| 		# submit dn |  | ||||||
| 		dn = self.create_dn_against_so(so) |  | ||||||
| 
 |  | ||||||
| 		self.check_reserved_qty(so.get("items")[0].item_code, so.get("items")[0].warehouse, 5.0) |  | ||||||
| 
 | 
 | ||||||
| 		# stop so | 		# stop so | ||||||
| 		so.load_from_db() | 		so.load_from_db() | ||||||
| 		so.stop_sales_order() | 		so.stop_sales_order() | ||||||
| 		self.check_reserved_qty(so.get("items")[0].item_code, so.get("items")[0].warehouse, 0.0) | 		self.assertEqual(get_reserved_qty(), existing_reserved_qty) | ||||||
| 		 | 		 | ||||||
| 		# unstop so | 		# unstop so | ||||||
| 		so.load_from_db() | 		so.load_from_db() | ||||||
| 		so.unstop_sales_order() | 		so.unstop_sales_order() | ||||||
| 		self.check_reserved_qty(so.get("items")[0].item_code, so.get("items")[0].warehouse, 5.0) | 		self.assertEqual(get_reserved_qty(), existing_reserved_qty + 5) | ||||||
| 
 | 
 | ||||||
| 		# cancel dn |  | ||||||
| 		dn.cancel() | 		dn.cancel() | ||||||
| 		self.check_reserved_qty(so.get("items")[0].item_code, so.get("items")[0].warehouse, 10.0) | 		self.assertEqual(get_reserved_qty(), existing_reserved_qty + 10) | ||||||
| 
 |  | ||||||
| 	def test_reserved_qty_for_over_delivery(self): |  | ||||||
| 		# reset bin |  | ||||||
| 		so_item = test_records[0]["items"][0].copy() |  | ||||||
| 		self.delete_bin(so_item["item_code"], so_item["warehouse"]) |  | ||||||
| 
 |  | ||||||
| 		# submit so |  | ||||||
| 		so = self.create_so() |  | ||||||
| 
 |  | ||||||
| 		# allow negative stock |  | ||||||
| 		frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1) |  | ||||||
| 
 |  | ||||||
| 		# set over-delivery tolerance |  | ||||||
| 		frappe.db.set_value('Item', so.get("items")[0].item_code, 'tolerance', 50) |  | ||||||
| 
 |  | ||||||
| 		# submit dn |  | ||||||
| 		dn = self.create_dn_against_so(so, 15) |  | ||||||
| 		self.check_reserved_qty(so.get("items")[0].item_code, so.get("items")[0].warehouse, 0.0) |  | ||||||
| 
 |  | ||||||
| 		# cancel dn |  | ||||||
| 		dn.cancel() |  | ||||||
| 		self.check_reserved_qty(so.get("items")[0].item_code, so.get("items")[0].warehouse, 10.0) |  | ||||||
| 
 |  | ||||||
| 	def test_reserved_qty_for_so_with_packing_list(self): |  | ||||||
| 		from erpnext.selling.doctype.sales_bom.test_sales_bom import test_records as sbom_test_records |  | ||||||
| 
 |  | ||||||
| 		# change item in test so record |  | ||||||
| 		test_record = copy.deepcopy(test_records[0]) |  | ||||||
| 		test_record["items"][0]["item_code"] = "_Test Sales BOM Item" |  | ||||||
| 
 |  | ||||||
| 		# reset bin |  | ||||||
| 		self.delete_bin(sbom_test_records[0]["items"][0]["item_code"], test_record.get("items")[0]["warehouse"]) |  | ||||||
| 		self.delete_bin(sbom_test_records[0]["items"][1]["item_code"], test_record.get("items")[0]["warehouse"]) |  | ||||||
| 
 |  | ||||||
| 		# submit |  | ||||||
| 		so = self.create_so(test_record) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 		self.check_reserved_qty(sbom_test_records[0]["items"][0]["item_code"], |  | ||||||
| 			so.get("items")[0].warehouse, 50.0) |  | ||||||
| 		self.check_reserved_qty(sbom_test_records[0]["items"][1]["item_code"], |  | ||||||
| 			so.get("items")[0].warehouse, 20.0) |  | ||||||
| 		 | 		 | ||||||
| 		# cancel | 		# cancel | ||||||
|  | 		so.load_from_db() | ||||||
| 		so.cancel() | 		so.cancel() | ||||||
| 		self.check_reserved_qty(sbom_test_records[0]["items"][0]["item_code"], | 		self.assertEqual(get_reserved_qty(), existing_reserved_qty) | ||||||
| 			so.get("items")[0].warehouse, 0.0) | 
 | ||||||
| 		self.check_reserved_qty(sbom_test_records[0]["items"][1]["item_code"], | 	def test_reserved_qty_for_over_delivery(self): | ||||||
| 			so.get("items")[0].warehouse, 0.0) | 		# set over-delivery tolerance | ||||||
|  | 		frappe.db.set_value('Item', "_Test Item", 'tolerance', 50) | ||||||
|  | 		 | ||||||
|  | 		existing_reserved_qty = get_reserved_qty() | ||||||
|  | 		 | ||||||
|  | 		so = make_sales_order() | ||||||
|  | 		self.assertEqual(get_reserved_qty(), existing_reserved_qty + 10) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 		dn = create_dn_against_so(so.name, 15) | ||||||
|  | 		self.assertEqual(get_reserved_qty(), existing_reserved_qty) | ||||||
|  | 
 | ||||||
|  | 		dn.cancel() | ||||||
|  | 		self.assertEqual(get_reserved_qty(), existing_reserved_qty + 10) | ||||||
| 
 | 
 | ||||||
| 	def test_reserved_qty_for_partial_delivery_with_packing_list(self): | 	def test_reserved_qty_for_partial_delivery_with_packing_list(self): | ||||||
| 		from erpnext.selling.doctype.sales_bom.test_sales_bom import test_records as sbom_test_records | 		existing_reserved_qty_item1 = get_reserved_qty("_Test Item") | ||||||
|  | 		existing_reserved_qty_item2 = get_reserved_qty("_Test Item Home Desktop 100") | ||||||
| 		 | 		 | ||||||
| 		# change item in test so record | 		so = make_sales_order(item_code="_Test Sales BOM Item") | ||||||
| 		 | 		 | ||||||
| 		test_record = frappe.copy_doc(test_records[0]) | 		self.assertEqual(get_reserved_qty("_Test Item"), existing_reserved_qty_item1 + 50) | ||||||
| 		test_record.get("items")[0].item_code = "_Test Sales BOM Item" | 		self.assertEqual(get_reserved_qty("_Test Item Home Desktop 100"),  | ||||||
|  | 			existing_reserved_qty_item2 + 20) | ||||||
| 		 | 		 | ||||||
| 		# reset bin | 		dn = create_dn_against_so(so.name) | ||||||
| 		self.delete_bin(sbom_test_records[0]["items"][0]["item_code"], test_record.get("items")[0].warehouse) |  | ||||||
| 		self.delete_bin(sbom_test_records[0]["items"][1]["item_code"], test_record.get("items")[0].warehouse) |  | ||||||
| 		 | 		 | ||||||
| 		# submit | 		self.assertEqual(get_reserved_qty("_Test Item"), existing_reserved_qty_item1 + 25) | ||||||
| 		so = self.create_so(test_record) | 		self.assertEqual(get_reserved_qty("_Test Item Home Desktop 100"),  | ||||||
| 
 | 			existing_reserved_qty_item2 + 10) | ||||||
| 		# allow negative stock |  | ||||||
| 		frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1) |  | ||||||
| 
 |  | ||||||
| 		# submit dn |  | ||||||
| 		dn = self.create_dn_against_so(so) |  | ||||||
| 
 |  | ||||||
| 		self.check_reserved_qty(sbom_test_records[0]["items"][0]["item_code"], |  | ||||||
| 			so.get("items")[0].warehouse, 25.0) |  | ||||||
| 		self.check_reserved_qty(sbom_test_records[0]["items"][1]["item_code"], |  | ||||||
| 			so.get("items")[0].warehouse, 10.0) |  | ||||||
| 
 | 
 | ||||||
| 		# stop so | 		# stop so | ||||||
| 		so.load_from_db() | 		so.load_from_db() | ||||||
| 		so.stop_sales_order() | 		so.stop_sales_order() | ||||||
| 		 | 		 | ||||||
| 		self.check_reserved_qty(sbom_test_records[0]["items"][0]["item_code"], | 		self.assertEqual(get_reserved_qty("_Test Item"), existing_reserved_qty_item1) | ||||||
| 			so.get("items")[0].warehouse, 0.0) | 		self.assertEqual(get_reserved_qty("_Test Item Home Desktop 100"), existing_reserved_qty_item2) | ||||||
| 		self.check_reserved_qty(sbom_test_records[0]["items"][1]["item_code"], |  | ||||||
| 			so.get("items")[0].warehouse, 0.0) |  | ||||||
| 
 | 
 | ||||||
| 		# unstop so | 		# unstop so | ||||||
| 		so.load_from_db() | 		so.load_from_db() | ||||||
| 		so.unstop_sales_order() | 		so.unstop_sales_order() | ||||||
| 		self.check_reserved_qty(sbom_test_records[0]["items"][0]["item_code"], |  | ||||||
| 			so.get("items")[0].warehouse, 25.0) |  | ||||||
| 		self.check_reserved_qty(sbom_test_records[0]["items"][1]["item_code"], |  | ||||||
| 			so.get("items")[0].warehouse, 10.0) |  | ||||||
| 		 | 		 | ||||||
| 		# cancel dn | 		self.assertEqual(get_reserved_qty("_Test Item"), existing_reserved_qty_item1 + 25) | ||||||
|  | 		self.assertEqual(get_reserved_qty("_Test Item Home Desktop 100"),  | ||||||
|  | 			existing_reserved_qty_item2 + 10) | ||||||
|  | 
 | ||||||
| 		dn.cancel() | 		dn.cancel() | ||||||
| 		self.check_reserved_qty(sbom_test_records[0]["items"][0]["item_code"], | 		self.assertEqual(get_reserved_qty("_Test Item"), existing_reserved_qty_item1 + 50) | ||||||
| 			so.get("items")[0].warehouse, 50.0) | 		self.assertEqual(get_reserved_qty("_Test Item Home Desktop 100"),  | ||||||
| 		self.check_reserved_qty(sbom_test_records[0]["items"][1]["item_code"], | 			existing_reserved_qty_item2 + 20) | ||||||
| 			so.get("items")[0].warehouse, 20.0) | 		 | ||||||
|  | 		so.load_from_db() | ||||||
|  | 		so.cancel() | ||||||
|  | 		self.assertEqual(get_reserved_qty("_Test Item"), existing_reserved_qty_item1) | ||||||
|  | 		self.assertEqual(get_reserved_qty("_Test Item Home Desktop 100"), existing_reserved_qty_item2) | ||||||
| 
 | 
 | ||||||
| 	def test_reserved_qty_for_over_delivery_with_packing_list(self): | 	def test_reserved_qty_for_over_delivery_with_packing_list(self): | ||||||
| 		from erpnext.selling.doctype.sales_bom.test_sales_bom import test_records as sbom_test_records |  | ||||||
| 
 |  | ||||||
| 		# change item in test so record |  | ||||||
| 		test_record = frappe.copy_doc(test_records[0]) |  | ||||||
| 		test_record.get("items")[0].item_code = "_Test Sales BOM Item" |  | ||||||
| 
 |  | ||||||
| 		# reset bin |  | ||||||
| 		self.delete_bin(sbom_test_records[0]["items"][0]["item_code"], test_record.get("items")[0].warehouse) |  | ||||||
| 		self.delete_bin(sbom_test_records[0]["items"][1]["item_code"], test_record.get("items")[0].warehouse) |  | ||||||
| 
 |  | ||||||
| 		# submit |  | ||||||
| 		so = self.create_so(test_record) |  | ||||||
| 
 |  | ||||||
| 		# allow negative stock |  | ||||||
| 		frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1) |  | ||||||
| 
 |  | ||||||
| 		# set over-delivery tolerance | 		# set over-delivery tolerance | ||||||
| 		frappe.db.set_value('Item', so.get("items")[0].item_code, 'tolerance', 50) | 		frappe.db.set_value('Item', "_Test Sales BOM Item", 'tolerance', 50) | ||||||
| 		 | 		 | ||||||
| 		# submit dn | 		existing_reserved_qty_item1 = get_reserved_qty("_Test Item") | ||||||
| 		dn = self.create_dn_against_so(so, 15) | 		existing_reserved_qty_item2 = get_reserved_qty("_Test Item Home Desktop 100") | ||||||
| 		 | 		 | ||||||
| 		self.check_reserved_qty(sbom_test_records[0]["items"][0]["item_code"], | 		so = make_sales_order(item_code="_Test Sales BOM Item") | ||||||
| 			so.get("items")[0].warehouse, 0.0) | 		 | ||||||
| 		self.check_reserved_qty(sbom_test_records[0]["items"][1]["item_code"], | 		self.assertEqual(get_reserved_qty("_Test Item"), existing_reserved_qty_item1 + 50) | ||||||
| 			so.get("items")[0].warehouse, 0.0) | 		self.assertEqual(get_reserved_qty("_Test Item Home Desktop 100"),  | ||||||
|  | 			existing_reserved_qty_item2 + 20) | ||||||
|  | 		 | ||||||
|  | 		dn = create_dn_against_so(so.name, 15) | ||||||
|  | 		 | ||||||
|  | 		self.assertEqual(get_reserved_qty("_Test Item"), existing_reserved_qty_item1) | ||||||
|  | 		self.assertEqual(get_reserved_qty("_Test Item Home Desktop 100"),  | ||||||
|  | 			existing_reserved_qty_item2) | ||||||
| 		 | 		 | ||||||
| 		# cancel dn |  | ||||||
| 		dn.cancel() | 		dn.cancel() | ||||||
| 		self.check_reserved_qty(sbom_test_records[0]["items"][0]["item_code"], | 		self.assertEqual(get_reserved_qty("_Test Item"), existing_reserved_qty_item1 + 50) | ||||||
| 			so.get("items")[0].warehouse, 50.0) | 		self.assertEqual(get_reserved_qty("_Test Item Home Desktop 100"),  | ||||||
| 		self.check_reserved_qty(sbom_test_records[0]["items"][1]["item_code"], | 			existing_reserved_qty_item2 + 20) | ||||||
| 			so.get("items")[0].warehouse, 20.0) |  | ||||||
| 
 | 
 | ||||||
| 	def test_warehouse_user(self): | 	def test_warehouse_user(self): | ||||||
| 		frappe.permissions.add_user_permission("Warehouse", "_Test Warehouse 1 - _TC", "test@example.com") | 		frappe.permissions.add_user_permission("Warehouse", "_Test Warehouse 1 - _TC", "test@example.com") | ||||||
| @ -353,11 +201,10 @@ class TestSalesOrder(unittest.TestCase): | |||||||
| 
 | 
 | ||||||
| 		frappe.set_user("test@example.com") | 		frappe.set_user("test@example.com") | ||||||
| 
 | 
 | ||||||
| 		so = frappe.copy_doc(test_records[0]) | 		so = make_sales_order(company="_Test Company 1",  | ||||||
| 		so.company = "_Test Company 1" | 			warehouse="_Test Warehouse 2 - _TC1", do_not_save=True) | ||||||
| 		so.conversion_rate = 0.02 | 		so.conversion_rate = 0.02 | ||||||
| 		so.plc_conversion_rate = 0.02 | 		so.plc_conversion_rate = 0.02 | ||||||
| 		so.get("items")[0].warehouse = "_Test Warehouse 2 - _TC1" |  | ||||||
| 		self.assertRaises(frappe.PermissionError, so.insert) | 		self.assertRaises(frappe.PermissionError, so.insert) | ||||||
| 
 | 
 | ||||||
| 		frappe.set_user("test2@example.com") | 		frappe.set_user("test2@example.com") | ||||||
| @ -368,24 +215,50 @@ class TestSalesOrder(unittest.TestCase): | |||||||
| 		frappe.permissions.remove_user_permission("Company", "_Test Company 1", "test2@example.com") | 		frappe.permissions.remove_user_permission("Company", "_Test Company 1", "test2@example.com") | ||||||
| 
 | 
 | ||||||
| 	def test_block_delivery_note_against_cancelled_sales_order(self): | 	def test_block_delivery_note_against_cancelled_sales_order(self): | ||||||
| 		from erpnext.stock.doctype.delivery_note.test_delivery_note import _insert_purchase_receipt | 		so = make_sales_order() | ||||||
| 		from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note |  | ||||||
| 		 | 		 | ||||||
| 		sales_order = frappe.copy_doc(test_records[0]) | 		dn = make_delivery_note(so.name) | ||||||
| 		sales_order.items[0].qty = 5 | 		dn.insert() | ||||||
| 		sales_order.insert() |  | ||||||
| 		sales_order.submit() |  | ||||||
| 		 | 		 | ||||||
| 		_insert_purchase_receipt(sales_order.get("items")[0].item_code) | 		so.cancel() | ||||||
| 		 | 		 | ||||||
| 		delivery_note = make_delivery_note(sales_order.name) | 		self.assertRaises(frappe.CancelledLinkError, dn.submit) | ||||||
| 		delivery_note.posting_date = sales_order.transaction_date |  | ||||||
| 		delivery_note.insert() |  | ||||||
| 		 | 		 | ||||||
| 		sales_order.cancel() | def make_sales_order(**args): | ||||||
|  | 	so = frappe.new_doc("Sales Order") | ||||||
|  | 	args = frappe._dict(args) | ||||||
|  | 	if args.transaction_date: | ||||||
|  | 		so.transaction_date = args.transaction_date | ||||||
| 
 | 
 | ||||||
| 		self.assertRaises(frappe.CancelledLinkError, delivery_note.submit) | 	so.company = args.company or "_Test Company" | ||||||
|  | 	so.customer = args.customer or "_Test Customer" | ||||||
|  | 	so.delivery_date = add_days(so.transaction_date, 10) | ||||||
| 
 | 
 | ||||||
| test_dependencies = ["Sales BOM", "Currency Exchange"] | 	so.append("items", { | ||||||
|  | 		"item_code": args.item or args.item_code or "_Test Item", | ||||||
|  | 		"warehouse": args.warehouse or "_Test Warehouse - _TC", | ||||||
|  | 		"qty": args.qty or 10, | ||||||
|  | 		"rate": args.rate or 100, | ||||||
|  | 		"conversion_factor": 1.0, | ||||||
|  | 	}) | ||||||
|  | 	if not args.do_not_save: | ||||||
|  | 		so.insert() | ||||||
|  | 		if not args.do_not_submit: | ||||||
|  | 			so.submit() | ||||||
| 			 | 			 | ||||||
| test_records = frappe.get_test_records('Sales Order') | 	return so | ||||||
|  | 	 | ||||||
|  | def create_dn_against_so(so, delivered_qty=0): | ||||||
|  | 	frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1) | ||||||
|  | 	 | ||||||
|  | 	dn = make_delivery_note(so) | ||||||
|  | 	dn.get("items")[0].qty = delivered_qty or 5 | ||||||
|  | 	dn.insert() | ||||||
|  | 	dn.submit() | ||||||
|  | 	return dn | ||||||
|  | 
 | ||||||
|  | def get_reserved_qty(item_code="_Test Item", warehouse="_Test Warehouse - _TC"): | ||||||
|  | 	return flt(frappe.db.get_value("Bin", {"item_code": item_code, "warehouse": warehouse}, | ||||||
|  | 		"reserved_qty")) | ||||||
|  | 	 | ||||||
|  | test_dependencies = ["Currency Exchange"] | ||||||
| @ -17,8 +17,6 @@ import install_fixtures | |||||||
| @frappe.whitelist() | @frappe.whitelist() | ||||||
| def setup_account(args=None): | def setup_account(args=None): | ||||||
| 	try: | 	try: | ||||||
| 		frappe.clear_cache() |  | ||||||
| 
 |  | ||||||
| 		if frappe.db.sql("select name from tabCompany"): | 		if frappe.db.sql("select name from tabCompany"): | ||||||
| 			frappe.throw(_("Setup Already Complete!!")) | 			frappe.throw(_("Setup Already Complete!!")) | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -48,7 +48,7 @@ args = { | |||||||
| "supplier_3": "Digital Ocean", | "supplier_3": "Digital Ocean", | ||||||
| "tax_1": "Service Tax", | "tax_1": "Service Tax", | ||||||
| "tax_rate_1": "12.5", | "tax_rate_1": "12.5", | ||||||
| "timezone": "Asia/Calcutta", | "timezone": "America/New_York", | ||||||
| "password": "password", | "password": "password", | ||||||
| "email": "test@erpnext.com", | "email": "test@erpnext.com", | ||||||
| } | } | ||||||
|  | |||||||
| @ -30,9 +30,10 @@ def get_ancestors_of(doctype, name): | |||||||
| 	return result or [] | 	return result or [] | ||||||
| 
 | 
 | ||||||
| def before_tests(): | def before_tests(): | ||||||
|  | 	frappe.clear_cache() | ||||||
| 	# complete setup if missing | 	# complete setup if missing | ||||||
| 	from erpnext.setup.page.setup_wizard.setup_wizard import setup_account | 	from erpnext.setup.page.setup_wizard.setup_wizard import setup_account | ||||||
| 	if not frappe.get_list("Item Group"): | 	if not frappe.get_list("Company"): | ||||||
| 		setup_account({ | 		setup_account({ | ||||||
| 			"currency"			:"USD", | 			"currency"			:"USD", | ||||||
| 			"first_name"		:"Test", | 			"first_name"		:"Test", | ||||||
|  | |||||||
| @ -58,6 +58,9 @@ class TestShoppingCart(unittest.TestCase): | |||||||
| 	def test_add_to_cart(self): | 	def test_add_to_cart(self): | ||||||
| 		self.login_as_lead() | 		self.login_as_lead() | ||||||
| 
 | 
 | ||||||
|  | 		# remove from cart | ||||||
|  | 		self.remove_all_items_from_cart() | ||||||
|  | 		 | ||||||
| 		# add first item | 		# add first item | ||||||
| 		set_item_in_cart("_Test Item", 1) | 		set_item_in_cart("_Test Item", 1) | ||||||
| 		quotation = self.test_get_cart_lead() | 		quotation = self.test_get_cart_lead() | ||||||
| @ -84,7 +87,7 @@ class TestShoppingCart(unittest.TestCase): | |||||||
| 		self.assertEquals(quotation.get("items")[0].item_code, "_Test Item") | 		self.assertEquals(quotation.get("items")[0].item_code, "_Test Item") | ||||||
| 		self.assertEquals(quotation.get("items")[0].qty, 5) | 		self.assertEquals(quotation.get("items")[0].qty, 5) | ||||||
| 		self.assertEquals(quotation.get("items")[0].amount, 50) | 		self.assertEquals(quotation.get("items")[0].amount, 50) | ||||||
| 		self.assertEquals(quotation.base_net_total, 70) | 		self.assertEquals(quotation.net_total, 70) | ||||||
| 		self.assertEquals(len(quotation.get("items")), 2) | 		self.assertEquals(len(quotation.get("items")), 2) | ||||||
| 
 | 
 | ||||||
| 	def test_remove_from_cart(self): | 	def test_remove_from_cart(self): | ||||||
| @ -97,13 +100,13 @@ class TestShoppingCart(unittest.TestCase): | |||||||
| 		self.assertEquals(quotation.get("items")[0].item_code, "_Test Item 2") | 		self.assertEquals(quotation.get("items")[0].item_code, "_Test Item 2") | ||||||
| 		self.assertEquals(quotation.get("items")[0].qty, 1) | 		self.assertEquals(quotation.get("items")[0].qty, 1) | ||||||
| 		self.assertEquals(quotation.get("items")[0].amount, 20) | 		self.assertEquals(quotation.get("items")[0].amount, 20) | ||||||
| 		self.assertEquals(quotation.base_net_total, 20) | 		self.assertEquals(quotation.net_total, 20) | ||||||
| 		self.assertEquals(len(quotation.get("items")), 1) | 		self.assertEquals(len(quotation.get("items")), 1) | ||||||
| 
 | 
 | ||||||
| 		# remove second item | 		# remove second item | ||||||
| 		set_item_in_cart("_Test Item 2", 0) | 		set_item_in_cart("_Test Item 2", 0) | ||||||
| 		quotation = self.test_get_cart_lead() | 		quotation = self.test_get_cart_lead() | ||||||
| 		self.assertEquals(quotation.base_net_total, 0) | 		self.assertEquals(quotation.net_total, 0) | ||||||
| 		self.assertEquals(len(quotation.get("items")), 0) | 		self.assertEquals(len(quotation.get("items")), 0) | ||||||
| 
 | 
 | ||||||
| 	def test_set_billing_address(self): | 	def test_set_billing_address(self): | ||||||
| @ -141,7 +144,7 @@ class TestShoppingCart(unittest.TestCase): | |||||||
| 	def enable_shopping_cart(self): | 	def enable_shopping_cart(self): | ||||||
| 		settings = frappe.get_doc("Shopping Cart Settings", "Shopping Cart Settings") | 		settings = frappe.get_doc("Shopping Cart Settings", "Shopping Cart Settings") | ||||||
| 
 | 
 | ||||||
| 		if settings.default_territory == "_Test Territory Rest Of The World": | 		if settings.get("price_lists"): | ||||||
| 			settings.enabled = 1 | 			settings.enabled = 1 | ||||||
| 		else: | 		else: | ||||||
| 			settings.update({ | 			settings.update({ | ||||||
| @ -225,6 +228,11 @@ class TestShoppingCart(unittest.TestCase): | |||||||
| 			"phone": "+91 0000000000" | 			"phone": "+91 0000000000" | ||||||
| 		}).insert(ignore_permissions=True) | 		}).insert(ignore_permissions=True) | ||||||
| 		 | 		 | ||||||
|  | 	def remove_all_items_from_cart(self): | ||||||
|  | 		quotation = get_quotation() | ||||||
|  | 		quotation.set("items", []) | ||||||
|  | 		quotation.save(ignore_permissions=True) | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| test_dependencies = ["Sales Taxes and Charges Master", "Price List", "Item Price", "Shipping Rule", "Currency Exchange", | test_dependencies = ["Sales Taxes and Charges Master", "Price List", "Item Price", "Shipping Rule", "Currency Exchange", | ||||||
| 	"Customer Group", "Lead", "Customer", "Contact", "Address", "Item"] | 	"Customer Group", "Lead", "Customer", "Contact", "Address", "Item"] | ||||||
|  | |||||||
| @ -5,109 +5,95 @@ | |||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
| import unittest | import unittest | ||||||
| import frappe | import frappe | ||||||
|  | import json | ||||||
| import frappe.defaults | import frappe.defaults | ||||||
| from frappe.utils import cint | from frappe.utils import cint, nowdate, nowtime, cstr, add_days | ||||||
| from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import get_gl_entries, set_perpetual_inventory, test_records as pr_test_records | from erpnext.stock.stock_ledger import get_previous_sle | ||||||
| 
 | from erpnext.accounts.utils import get_balance_on | ||||||
| def _insert_purchase_receipt(item_code=None): | from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt \ | ||||||
| 	if not item_code: | 	import get_gl_entries, set_perpetual_inventory | ||||||
| 		item_code = pr_test_records[0]["items"][0]["item_code"] | from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice | ||||||
| 
 | from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry, make_serialized_item | ||||||
| 	pr = frappe.copy_doc(pr_test_records[0]) | from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos, SerialNoStatusError | ||||||
| 	pr.get("items")[0].item_code = item_code |  | ||||||
| 	pr.insert() |  | ||||||
| 	pr.submit() |  | ||||||
| 
 | 
 | ||||||
| class TestDeliveryNote(unittest.TestCase): | class TestDeliveryNote(unittest.TestCase): | ||||||
| 	def test_over_billing_against_dn(self): | 	def test_over_billing_against_dn(self): | ||||||
| 		self.clear_stock_account_balance() | 		frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1) | ||||||
| 		_insert_purchase_receipt() |  | ||||||
| 		 | 		 | ||||||
| 		from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice | 		dn = create_delivery_note(do_not_submit=True) | ||||||
| 		_insert_purchase_receipt() | 		self.assertRaises(frappe.ValidationError, make_sales_invoice, dn.name) | ||||||
| 		dn = frappe.copy_doc(test_records[0]).insert() |  | ||||||
| 
 | 
 | ||||||
| 		self.assertRaises(frappe.ValidationError, make_sales_invoice, |  | ||||||
| 			dn.name) |  | ||||||
| 
 |  | ||||||
| 		dn = frappe.get_doc("Delivery Note", dn.name) |  | ||||||
| 		dn.submit() | 		dn.submit() | ||||||
| 		si = make_sales_invoice(dn.name) | 		si = make_sales_invoice(dn.name) | ||||||
| 
 |  | ||||||
| 		self.assertEquals(len(si.get("items")), len(dn.get("items"))) | 		self.assertEquals(len(si.get("items")), len(dn.get("items"))) | ||||||
| 
 | 
 | ||||||
| 		# modify amount | 		# modify amount | ||||||
| 		si.get("items")[0].rate = 200 | 		si.get("items")[0].rate = 200 | ||||||
| 		self.assertRaises(frappe.ValidationError, frappe.get_doc(si).insert) | 		self.assertRaises(frappe.ValidationError, frappe.get_doc(si).insert) | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 	def test_delivery_note_no_gl_entry(self): | 	def test_delivery_note_no_gl_entry(self): | ||||||
| 		self.clear_stock_account_balance() |  | ||||||
| 		set_perpetual_inventory(0) | 		set_perpetual_inventory(0) | ||||||
| 		self.assertEqual(cint(frappe.defaults.get_global_default("auto_accounting_for_stock")), 0) | 		self.assertEqual(cint(frappe.defaults.get_global_default("auto_accounting_for_stock")), 0) | ||||||
| 
 | 
 | ||||||
| 		_insert_purchase_receipt() | 		make_stock_entry(target="_Test Warehouse - _TC", qty=5, incoming_rate=100) | ||||||
| 		 | 		 | ||||||
| 		dn = frappe.copy_doc(test_records[0]) | 		stock_queue = json.loads(get_previous_sle({ | ||||||
| 		dn.insert() | 			"item_code": "_Test Item", | ||||||
| 		dn.submit() | 			"warehouse": "_Test Warehouse - _TC", | ||||||
|  | 			"posting_date": nowdate(), | ||||||
|  | 			"posting_time": nowtime() | ||||||
|  | 		}).stock_queue or "[]") | ||||||
| 		 | 		 | ||||||
| 		stock_value, stock_value_difference = frappe.db.get_value("Stock Ledger Entry", | 		dn = create_delivery_note() | ||||||
| 			{"voucher_type": "Delivery Note", "voucher_no": dn.name, | 		 | ||||||
| 				"item_code": "_Test Item"}, ["stock_value", "stock_value_difference"]) | 		sle = frappe.get_doc("Stock Ledger Entry", {"voucher_type": "Delivery Note", "voucher_no": dn.name}) | ||||||
| 		self.assertEqual(stock_value, 0) | 						 | ||||||
| 		self.assertEqual(stock_value_difference, -375) | 		self.assertEqual(sle.stock_value_difference, -1*stock_queue[0][1]) | ||||||
| 
 | 
 | ||||||
| 		self.assertFalse(get_gl_entries("Delivery Note", dn.name)) | 		self.assertFalse(get_gl_entries("Delivery Note", dn.name)) | ||||||
| 
 | 
 | ||||||
| 	def test_delivery_note_gl_entry(self): | 	def test_delivery_note_gl_entry(self): | ||||||
| 		self.clear_stock_account_balance() |  | ||||||
| 		set_perpetual_inventory() | 		set_perpetual_inventory() | ||||||
| 		self.assertEqual(cint(frappe.defaults.get_global_default("auto_accounting_for_stock")), 1) | 		self.assertEqual(cint(frappe.defaults.get_global_default("auto_accounting_for_stock")), 1) | ||||||
| 		frappe.db.set_value("Item", "_Test Item", "valuation_method", "FIFO") | 		frappe.db.set_value("Item", "_Test Item", "valuation_method", "FIFO") | ||||||
| 
 | 
 | ||||||
| 		_insert_purchase_receipt() | 		make_stock_entry(target="_Test Warehouse - _TC", qty=5, incoming_rate=100) | ||||||
| 
 | 
 | ||||||
| 		dn = frappe.copy_doc(test_records[0]) | 		stock_in_hand_account = frappe.db.get_value("Account", {"warehouse": "_Test Warehouse - _TC"}) | ||||||
| 		dn.get("items")[0].expense_account = "Cost of Goods Sold - _TC" | 		prev_bal = get_balance_on(stock_in_hand_account) | ||||||
| 		dn.get("items")[0].cost_center = "Main - _TC" |  | ||||||
| 		 | 		 | ||||||
| 		stock_in_hand_account = frappe.db.get_value("Account", | 		dn = create_delivery_note() | ||||||
| 			{"warehouse": dn.get("items")[0].warehouse}) |  | ||||||
| 
 |  | ||||||
| 		from erpnext.accounts.utils import get_balance_on |  | ||||||
| 		prev_bal = get_balance_on(stock_in_hand_account, dn.posting_date) |  | ||||||
| 
 |  | ||||||
| 		dn.insert() |  | ||||||
| 		dn.submit() |  | ||||||
| 
 | 
 | ||||||
| 		gl_entries = get_gl_entries("Delivery Note", dn.name) | 		gl_entries = get_gl_entries("Delivery Note", dn.name) | ||||||
| 		self.assertTrue(gl_entries) | 		self.assertTrue(gl_entries) | ||||||
|  | 		 | ||||||
|  | 		stock_value_difference = abs(frappe.db.get_value("Stock Ledger Entry",  | ||||||
|  | 			{"voucher_type": "Delivery Note", "voucher_no": dn.name}, "stock_value_difference")) | ||||||
|  | 		 | ||||||
| 		expected_values = { | 		expected_values = { | ||||||
| 			stock_in_hand_account: [0.0, 375.0], | 			stock_in_hand_account: [0.0, stock_value_difference], | ||||||
| 			"Cost of Goods Sold - _TC": [375.0, 0.0] | 			"Cost of Goods Sold - _TC": [stock_value_difference, 0.0] | ||||||
| 		} | 		} | ||||||
| 		for i, gle in enumerate(gl_entries): | 		for i, gle in enumerate(gl_entries): | ||||||
| 			self.assertEquals([gle.debit, gle.credit], expected_values.get(gle.account)) | 			self.assertEquals([gle.debit, gle.credit], expected_values.get(gle.account)) | ||||||
| 
 | 
 | ||||||
| 		# check stock in hand balance | 		# check stock in hand balance | ||||||
| 		bal = get_balance_on(stock_in_hand_account, dn.posting_date) | 		bal = get_balance_on(stock_in_hand_account) | ||||||
| 		self.assertEquals(bal, prev_bal - 375.0) | 		self.assertEquals(bal, prev_bal - stock_value_difference) | ||||||
| 
 | 
 | ||||||
| 		# back dated purchase receipt | 		# back dated incoming entry | ||||||
| 		pr = frappe.copy_doc(pr_test_records[0]) | 		make_stock_entry(posting_date=add_days(nowdate(), -2), target="_Test Warehouse - _TC",  | ||||||
| 		pr.posting_date = "2013-01-01" | 			qty=5, incoming_rate=100) | ||||||
| 		pr.get("items")[0].rate = 100 |  | ||||||
| 		pr.get("items")[0].base_amount = 100 |  | ||||||
| 
 |  | ||||||
| 		pr.insert() |  | ||||||
| 		pr.submit() |  | ||||||
| 
 | 
 | ||||||
| 		gl_entries = get_gl_entries("Delivery Note", dn.name) | 		gl_entries = get_gl_entries("Delivery Note", dn.name) | ||||||
| 		self.assertTrue(gl_entries) | 		self.assertTrue(gl_entries) | ||||||
|  | 		 | ||||||
|  | 		stock_value_difference = abs(frappe.db.get_value("Stock Ledger Entry",  | ||||||
|  | 			{"voucher_type": "Delivery Note", "voucher_no": dn.name}, "stock_value_difference")) | ||||||
|  | 			 | ||||||
| 		expected_values = { | 		expected_values = { | ||||||
| 			stock_in_hand_account: [0.0, 666.67], | 			stock_in_hand_account: [0.0, stock_value_difference], | ||||||
| 			"Cost of Goods Sold - _TC": [666.67, 0.0] | 			"Cost of Goods Sold - _TC": [stock_value_difference, 0.0] | ||||||
| 		} | 		} | ||||||
| 		for i, gle in enumerate(gl_entries): | 		for i, gle in enumerate(gl_entries): | ||||||
| 			self.assertEquals([gle.debit, gle.credit], expected_values.get(gle.account)) | 			self.assertEquals([gle.debit, gle.credit], expected_values.get(gle.account)) | ||||||
| @ -117,38 +103,40 @@ class TestDeliveryNote(unittest.TestCase): | |||||||
| 		set_perpetual_inventory(0) | 		set_perpetual_inventory(0) | ||||||
| 
 | 
 | ||||||
| 	def test_delivery_note_gl_entry_packing_item(self): | 	def test_delivery_note_gl_entry_packing_item(self): | ||||||
| 		self.clear_stock_account_balance() |  | ||||||
| 		set_perpetual_inventory() | 		set_perpetual_inventory() | ||||||
| 
 | 
 | ||||||
| 		_insert_purchase_receipt() | 		make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=10, incoming_rate=100) | ||||||
| 		_insert_purchase_receipt("_Test Item Home Desktop 100") | 		make_stock_entry(item_code="_Test Item Home Desktop 100",  | ||||||
|  | 			target="_Test Warehouse - _TC", qty=10, incoming_rate=100) | ||||||
| 
 | 
 | ||||||
| 		dn = frappe.copy_doc(test_records[0]) | 		stock_in_hand_account = frappe.db.get_value("Account", {"warehouse": "_Test Warehouse - _TC"}) | ||||||
| 		dn.get("items")[0].item_code = "_Test Sales BOM Item" | 		prev_bal = get_balance_on(stock_in_hand_account) | ||||||
| 		dn.get("items")[0].qty = 1 |  | ||||||
| 
 | 
 | ||||||
| 		stock_in_hand_account = frappe.db.get_value("Account", | 		dn = create_delivery_note(item_code="_Test Sales BOM Item") | ||||||
| 			{"warehouse": dn.get("items")[0].warehouse}) |  | ||||||
| 		 | 		 | ||||||
| 		from erpnext.accounts.utils import get_balance_on | 		stock_value_diff_rm1 = abs(frappe.db.get_value("Stock Ledger Entry",  | ||||||
| 		prev_bal = get_balance_on(stock_in_hand_account, dn.posting_date) | 			{"voucher_type": "Delivery Note", "voucher_no": dn.name, "item_code": "_Test Item"},  | ||||||
|  | 			"stock_value_difference")) | ||||||
| 		 | 		 | ||||||
| 		dn.insert() | 		stock_value_diff_rm2 = abs(frappe.db.get_value("Stock Ledger Entry",  | ||||||
| 		dn.submit() | 			{"voucher_type": "Delivery Note", "voucher_no": dn.name,  | ||||||
|  | 				"item_code": "_Test Item Home Desktop 100"}, "stock_value_difference")) | ||||||
|  | 				 | ||||||
|  | 		stock_value_diff = stock_value_diff_rm1 + stock_value_diff_rm2 | ||||||
| 
 | 
 | ||||||
| 		gl_entries = get_gl_entries("Delivery Note", dn.name) | 		gl_entries = get_gl_entries("Delivery Note", dn.name) | ||||||
| 		self.assertTrue(gl_entries) | 		self.assertTrue(gl_entries) | ||||||
| 
 | 
 | ||||||
| 		expected_values = { | 		expected_values = { | ||||||
| 			stock_in_hand_account: [0.0, 525], | 			stock_in_hand_account: [0.0, stock_value_diff], | ||||||
| 			"Cost of Goods Sold - _TC": [525.0, 0.0] | 			"Cost of Goods Sold - _TC": [stock_value_diff, 0.0] | ||||||
| 		} | 		} | ||||||
| 		for i, gle in enumerate(gl_entries): | 		for i, gle in enumerate(gl_entries): | ||||||
| 			self.assertEquals([gle.debit, gle.credit], expected_values.get(gle.account)) | 			self.assertEquals([gle.debit, gle.credit], expected_values.get(gle.account)) | ||||||
| 
 | 
 | ||||||
| 		# check stock in hand balance | 		# check stock in hand balance | ||||||
| 		bal = get_balance_on(stock_in_hand_account, dn.posting_date) | 		bal = get_balance_on(stock_in_hand_account) | ||||||
| 		self.assertEquals(bal, prev_bal - 525.0) | 		self.assertEquals(bal, prev_bal - stock_value_diff) | ||||||
| 
 | 
 | ||||||
| 		dn.cancel() | 		dn.cancel() | ||||||
| 		self.assertFalse(get_gl_entries("Delivery Note", dn.name)) | 		self.assertFalse(get_gl_entries("Delivery Note", dn.name)) | ||||||
| @ -156,62 +144,67 @@ class TestDeliveryNote(unittest.TestCase): | |||||||
| 		set_perpetual_inventory(0) | 		set_perpetual_inventory(0) | ||||||
| 
 | 
 | ||||||
| 	def test_serialized(self): | 	def test_serialized(self): | ||||||
| 		from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item |  | ||||||
| 		from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos |  | ||||||
| 
 |  | ||||||
| 		se = make_serialized_item() | 		se = make_serialized_item() | ||||||
| 		serial_nos = get_serial_nos(se.get("items")[0].serial_no) | 		serial_no = get_serial_nos(se.get("items")[0].serial_no)[0] | ||||||
| 
 | 
 | ||||||
| 		dn = frappe.copy_doc(test_records[0]) | 		dn = create_delivery_note(item_code="_Test Serialized Item With Series", serial_no=serial_no) | ||||||
| 		dn.get("items")[0].item_code = "_Test Serialized Item With Series" |  | ||||||
| 		dn.get("items")[0].qty = 1 |  | ||||||
| 		dn.get("items")[0].serial_no = serial_nos[0] |  | ||||||
| 		dn.insert() |  | ||||||
| 		dn.submit() |  | ||||||
| 
 | 
 | ||||||
| 		self.assertEquals(frappe.db.get_value("Serial No", serial_nos[0], "status"), "Delivered") | 		self.check_serial_no_values(serial_no, { | ||||||
| 		self.assertFalse(frappe.db.get_value("Serial No", serial_nos[0], "warehouse")) | 			"status": "Delivered", | ||||||
| 		self.assertEquals(frappe.db.get_value("Serial No", serial_nos[0], | 			"warehouse": "", | ||||||
| 			"delivery_document_no"), dn.name) | 			"delivery_document_no": dn.name | ||||||
|  | 		}) | ||||||
| 
 | 
 | ||||||
| 		return dn |  | ||||||
| 
 |  | ||||||
| 	def test_serialized_cancel(self): |  | ||||||
| 		from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos |  | ||||||
| 		dn = self.test_serialized() |  | ||||||
| 		dn.cancel() | 		dn.cancel() | ||||||
| 		 | 		 | ||||||
| 		serial_nos = get_serial_nos(dn.get("items")[0].serial_no) | 		self.check_serial_no_values(serial_no, { | ||||||
| 
 | 			"status": "Available", | ||||||
| 		self.assertEquals(frappe.db.get_value("Serial No", serial_nos[0], "status"), "Available") | 			"warehouse": "_Test Warehouse - _TC", | ||||||
| 		self.assertEquals(frappe.db.get_value("Serial No", serial_nos[0], "warehouse"), "_Test Warehouse - _TC") | 			"delivery_document_no": "" | ||||||
| 		self.assertFalse(frappe.db.get_value("Serial No", serial_nos[0], | 		}) | ||||||
| 			"delivery_document_no")) |  | ||||||
| 
 | 
 | ||||||
| 	def test_serialize_status(self): | 	def test_serialize_status(self): | ||||||
| 		from erpnext.stock.doctype.serial_no.serial_no import SerialNoStatusError, get_serial_nos |  | ||||||
| 		from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item |  | ||||||
| 
 |  | ||||||
| 		se = make_serialized_item() | 		se = make_serialized_item() | ||||||
| 		serial_nos = get_serial_nos(se.get("items")[0].serial_no) | 		serial_no = get_serial_nos(se.get("items")[0].serial_no)[0] | ||||||
| 		 | 		 | ||||||
| 		sr = frappe.get_doc("Serial No", serial_nos[0]) | 		frappe.db.set_value("Serial No", serial_no, "status", "Not Available") | ||||||
| 		sr.status = "Not Available" |  | ||||||
| 		sr.save() |  | ||||||
| 
 | 
 | ||||||
| 		dn = frappe.copy_doc(test_records[0]) | 		dn = create_delivery_note(item_code="_Test Serialized Item With Series",  | ||||||
| 		dn.get("items")[0].item_code = "_Test Serialized Item With Series" | 			serial_no=serial_no, do_not_submit=True) | ||||||
| 		dn.get("items")[0].qty = 1 |  | ||||||
| 		dn.get("items")[0].serial_no = serial_nos[0] |  | ||||||
| 		dn.insert() |  | ||||||
| 
 | 
 | ||||||
| 		self.assertRaises(SerialNoStatusError, dn.submit) | 		self.assertRaises(SerialNoStatusError, dn.submit) | ||||||
| 		 | 		 | ||||||
| 	def clear_stock_account_balance(self): | 	def check_serial_no_values(self, serial_no, field_values): | ||||||
| 		frappe.db.sql("""delete from `tabBin`""") | 		for field, value in field_values.items(): | ||||||
| 		frappe.db.sql("delete from `tabStock Ledger Entry`") | 			self.assertEquals(cstr(frappe.db.get_value("Serial No", serial_no, field)), value) | ||||||
| 		frappe.db.sql("delete from `tabGL Entry`") | 
 | ||||||
|  | 
 | ||||||
|  | def create_delivery_note(**args): | ||||||
|  | 	dn = frappe.new_doc("Delivery Note") | ||||||
|  | 	args = frappe._dict(args) | ||||||
|  | 	if args.posting_date: | ||||||
|  | 		dn.posting_date = args.posting_date | ||||||
|  | 	if args.posting_time: | ||||||
|  | 		dn.posting_time = args.posting_time | ||||||
|  | 	 | ||||||
|  | 	dn.company = args.company or "_Test Company" | ||||||
|  | 	dn.customer = args.customer or "_Test Customer" | ||||||
|  | 	 | ||||||
|  | 	dn.append("items", { | ||||||
|  | 		"item_code": args.item or args.item_code or "_Test Item", | ||||||
|  | 		"warehouse": args.warehouse or "_Test Warehouse - _TC", | ||||||
|  | 		"qty": args.qty or 1, | ||||||
|  | 		"rate": args.rate or 100, | ||||||
|  | 		"conversion_factor": 1.0, | ||||||
|  | 		"expense_account": "Cost of Goods Sold - _TC", | ||||||
|  | 		"cost_center": "_Test Cost Center - _TC", | ||||||
|  | 		"serial_no": args.serial_no | ||||||
|  | 	}) | ||||||
|  | 	 | ||||||
|  | 	if not args.do_not_save: | ||||||
|  | 		dn.insert() | ||||||
|  | 		if not args.do_not_submit: | ||||||
|  | 			dn.submit() | ||||||
|  | 	return dn | ||||||
| 	 | 	 | ||||||
| test_dependencies = ["Sales BOM"] | test_dependencies = ["Sales BOM"] | ||||||
| 
 |  | ||||||
| test_records = frappe.get_test_records('Delivery Note') |  | ||||||
|  | |||||||
| @ -7,7 +7,7 @@ | |||||||
|   "customer_name": "_Test Customer",  |   "customer_name": "_Test Customer",  | ||||||
|   "items": [ |   "items": [ | ||||||
|    { |    { | ||||||
|     "base_amount": 500.0,  |     "base_amount": 100.0,  | ||||||
|     "base_rate": 100.0,  |     "base_rate": 100.0,  | ||||||
|     "cost_center": "Main - _TC",  |     "cost_center": "Main - _TC",  | ||||||
|     "description": "CPU",  |     "description": "CPU",  | ||||||
| @ -16,7 +16,7 @@ | |||||||
|     "item_code": "_Test Item",  |     "item_code": "_Test Item",  | ||||||
|     "item_name": "_Test Item",  |     "item_name": "_Test Item",  | ||||||
|     "parentfield": "items",  |     "parentfield": "items",  | ||||||
|     "qty": 5.0,  |     "qty": 1.0,  | ||||||
|     "rate": 100.0,  |     "rate": 100.0,  | ||||||
|     "stock_uom": "_Test UOM",  |     "stock_uom": "_Test UOM",  | ||||||
|     "warehouse": "_Test Warehouse - _TC" |     "warehouse": "_Test Warehouse - _TC" | ||||||
| @ -24,10 +24,10 @@ | |||||||
|   ],  |   ],  | ||||||
|   "doctype": "Delivery Note",  |   "doctype": "Delivery Note",  | ||||||
|   "fiscal_year": "_Test Fiscal Year 2013",  |   "fiscal_year": "_Test Fiscal Year 2013",  | ||||||
|   "base_grand_total": 500.0,  |   "base_grand_total": 100.0,  | ||||||
|   "grand_total": 500.0,  |   "grand_total": 100.0,  | ||||||
|   "naming_series": "_T-Delivery Note-",  |   "naming_series": "_T-Delivery Note-",  | ||||||
|   "base_net_total": 500.0,  |   "base_net_total": 100.0,  | ||||||
|   "plc_conversion_rate": 1.0,  |   "plc_conversion_rate": 1.0,  | ||||||
|   "posting_date": "2013-02-21",  |   "posting_date": "2013-02-21",  | ||||||
|   "posting_time": "9:00:00",  |   "posting_time": "9:00:00",  | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ import frappe | |||||||
| 
 | 
 | ||||||
| from frappe.test_runner import make_test_records | from frappe.test_runner import make_test_records | ||||||
| from erpnext.stock.doctype.item.item import WarehouseNotSet, DuplicateVariant, ItemTemplateCannotHaveStock | from erpnext.stock.doctype.item.item import WarehouseNotSet, DuplicateVariant, ItemTemplateCannotHaveStock | ||||||
|  | from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry | ||||||
| 
 | 
 | ||||||
| test_ignore = ["BOM"] | test_ignore = ["BOM"] | ||||||
| test_dependencies = ["Warehouse"] | test_dependencies = ["Warehouse"] | ||||||
| @ -30,16 +31,7 @@ class TestItem(unittest.TestCase): | |||||||
| 	def test_template_cannot_have_stock(self): | 	def test_template_cannot_have_stock(self): | ||||||
| 		item = self.get_item(10) | 		item = self.get_item(10) | ||||||
| 		 | 		 | ||||||
| 		se = frappe.new_doc("Stock Entry") | 		se = make_stock_entry(item_code=item.name, target="Stores - _TC", qty=1, incoming_rate=1) | ||||||
| 		se.purpose = "Material Receipt" |  | ||||||
| 		se.append("items", { |  | ||||||
| 			"item_code": item.name, |  | ||||||
| 			"t_warehouse": "Stores - _TC", |  | ||||||
| 			"qty": 1, |  | ||||||
| 			"incoming_rate": 1 |  | ||||||
| 		}) |  | ||||||
| 		se.insert() |  | ||||||
| 		se.submit() |  | ||||||
| 
 | 
 | ||||||
| 		item.has_variants = 1 | 		item.has_variants = 1 | ||||||
| 		self.assertRaises(ItemTemplateCannotHaveStock, item.save) | 		self.assertRaises(ItemTemplateCannotHaveStock, item.save) | ||||||
|  | |||||||
| @ -4,6 +4,7 @@ | |||||||
|   "description": "_Test Item 1", |   "description": "_Test Item 1", | ||||||
|   "doctype": "Item", |   "doctype": "Item", | ||||||
|   "expense_account": "_Test Account Cost for Goods Sold - _TC", |   "expense_account": "_Test Account Cost for Goods Sold - _TC", | ||||||
|  |   "cost_center": "_Test Cost Center - _TC", | ||||||
|   "has_batch_no": "No", |   "has_batch_no": "No", | ||||||
|   "has_serial_no": "No", |   "has_serial_no": "No", | ||||||
|   "income_account": "Sales - _TC", |   "income_account": "Sales - _TC", | ||||||
| @ -36,6 +37,7 @@ | |||||||
|   "description": "_Test Item 2", |   "description": "_Test Item 2", | ||||||
|   "doctype": "Item", |   "doctype": "Item", | ||||||
|   "expense_account": "_Test Account Cost for Goods Sold - _TC", |   "expense_account": "_Test Account Cost for Goods Sold - _TC", | ||||||
|  |   "cost_center": "_Test Cost Center - _TC", | ||||||
|   "has_batch_no": "No", |   "has_batch_no": "No", | ||||||
|   "has_serial_no": "No", |   "has_serial_no": "No", | ||||||
|   "income_account": "Sales - _TC", |   "income_account": "Sales - _TC", | ||||||
| @ -59,6 +61,7 @@ | |||||||
|   "description": "_Test Item Home Desktop 100 3", |   "description": "_Test Item Home Desktop 100 3", | ||||||
|   "doctype": "Item", |   "doctype": "Item", | ||||||
|   "expense_account": "_Test Account Cost for Goods Sold - _TC", |   "expense_account": "_Test Account Cost for Goods Sold - _TC", | ||||||
|  |   "cost_center": "_Test Cost Center - _TC", | ||||||
|   "has_batch_no": "No", |   "has_batch_no": "No", | ||||||
|   "has_serial_no": "No", |   "has_serial_no": "No", | ||||||
|   "income_account": "Sales - _TC", |   "income_account": "Sales - _TC", | ||||||
| @ -88,6 +91,7 @@ | |||||||
|   "description": "_Test Item Home Desktop 200 4", |   "description": "_Test Item Home Desktop 200 4", | ||||||
|   "doctype": "Item", |   "doctype": "Item", | ||||||
|   "expense_account": "_Test Account Cost for Goods Sold - _TC", |   "expense_account": "_Test Account Cost for Goods Sold - _TC", | ||||||
|  |   "cost_center": "_Test Cost Center - _TC", | ||||||
|   "has_batch_no": "No", |   "has_batch_no": "No", | ||||||
|   "has_serial_no": "No", |   "has_serial_no": "No", | ||||||
|   "income_account": "Sales - _TC", |   "income_account": "Sales - _TC", | ||||||
| @ -108,6 +112,7 @@ | |||||||
|   "description": "_Test Sales BOM Item 5", |   "description": "_Test Sales BOM Item 5", | ||||||
|   "doctype": "Item", |   "doctype": "Item", | ||||||
|   "expense_account": "_Test Account Cost for Goods Sold - _TC", |   "expense_account": "_Test Account Cost for Goods Sold - _TC", | ||||||
|  |   "cost_center": "_Test Cost Center - _TC", | ||||||
|   "has_batch_no": "No", |   "has_batch_no": "No", | ||||||
|   "has_serial_no": "No", |   "has_serial_no": "No", | ||||||
|   "income_account": "Sales - _TC", |   "income_account": "Sales - _TC", | ||||||
| @ -129,6 +134,7 @@ | |||||||
|   "description": "_Test FG Item 6", |   "description": "_Test FG Item 6", | ||||||
|   "doctype": "Item", |   "doctype": "Item", | ||||||
|   "expense_account": "_Test Account Cost for Goods Sold - _TC", |   "expense_account": "_Test Account Cost for Goods Sold - _TC", | ||||||
|  |   "cost_center": "_Test Cost Center - _TC", | ||||||
|   "has_batch_no": "No", |   "has_batch_no": "No", | ||||||
|   "has_serial_no": "No", |   "has_serial_no": "No", | ||||||
|   "income_account": "Sales - _TC", |   "income_account": "Sales - _TC", | ||||||
| @ -207,6 +213,7 @@ | |||||||
|   "description": "_Test Item Home Desktop Manufactured 10", |   "description": "_Test Item Home Desktop Manufactured 10", | ||||||
|   "doctype": "Item", |   "doctype": "Item", | ||||||
|   "expense_account": "_Test Account Cost for Goods Sold - _TC", |   "expense_account": "_Test Account Cost for Goods Sold - _TC", | ||||||
|  |   "cost_center": "_Test Cost Center - _TC", | ||||||
|   "has_batch_no": "No", |   "has_batch_no": "No", | ||||||
|   "has_serial_no": "No", |   "has_serial_no": "No", | ||||||
|   "income_account": "Sales - _TC", |   "income_account": "Sales - _TC", | ||||||
| @ -227,6 +234,7 @@ | |||||||
|   "description": "_Test FG Item 2 11", |   "description": "_Test FG Item 2 11", | ||||||
|   "doctype": "Item", |   "doctype": "Item", | ||||||
|   "expense_account": "_Test Account Cost for Goods Sold - _TC", |   "expense_account": "_Test Account Cost for Goods Sold - _TC", | ||||||
|  |   "cost_center": "_Test Cost Center - _TC", | ||||||
|   "has_batch_no": "No", |   "has_batch_no": "No", | ||||||
|   "has_serial_no": "No", |   "has_serial_no": "No", | ||||||
|   "income_account": "Sales - _TC", |   "income_account": "Sales - _TC", | ||||||
| @ -248,6 +256,7 @@ | |||||||
|   "description": "_Test Variant Item 12", |   "description": "_Test Variant Item 12", | ||||||
|   "doctype": "Item", |   "doctype": "Item", | ||||||
|   "expense_account": "_Test Account Cost for Goods Sold - _TC", |   "expense_account": "_Test Account Cost for Goods Sold - _TC", | ||||||
|  |   "cost_center": "_Test Cost Center - _TC", | ||||||
|   "has_batch_no": "No", |   "has_batch_no": "No", | ||||||
|   "has_serial_no": "No", |   "has_serial_no": "No", | ||||||
|   "income_account": "Sales - _TC", |   "income_account": "Sales - _TC", | ||||||
|  | |||||||
| @ -6,21 +6,16 @@ from __future__ import unicode_literals | |||||||
| import unittest | import unittest | ||||||
| import frappe | import frappe | ||||||
| import frappe.defaults | import frappe.defaults | ||||||
| from frappe.utils import cint | from frappe.utils import cint, flt | ||||||
| 
 | 
 | ||||||
| class TestPurchaseReceipt(unittest.TestCase): | class TestPurchaseReceipt(unittest.TestCase): | ||||||
| 	def test_make_purchase_invoice(self): | 	def test_make_purchase_invoice(self): | ||||||
| 		self._clear_stock_account_balance() |  | ||||||
| 		set_perpetual_inventory(0) |  | ||||||
| 		from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchase_invoice | 		from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchase_invoice | ||||||
| 
 | 
 | ||||||
| 		pr = frappe.copy_doc(test_records[0]).insert() | 		pr = make_purchase_receipt(do_not_save=True) | ||||||
| 
 | 		self.assertRaises(frappe.ValidationError, make_purchase_invoice, pr.name) | ||||||
| 		self.assertRaises(frappe.ValidationError, make_purchase_invoice, |  | ||||||
| 			pr.name) |  | ||||||
| 
 |  | ||||||
| 		pr = frappe.get_doc("Purchase Receipt", pr.name) |  | ||||||
| 		pr.submit() | 		pr.submit() | ||||||
|  | 
 | ||||||
| 		pi = make_purchase_invoice(pr.name) | 		pi = make_purchase_invoice(pr.name) | ||||||
| 
 | 
 | ||||||
| 		self.assertEquals(pi.doctype, "Purchase Invoice") | 		self.assertEquals(pi.doctype, "Purchase Invoice") | ||||||
| @ -31,28 +26,26 @@ class TestPurchaseReceipt(unittest.TestCase): | |||||||
| 		self.assertRaises(frappe.ValidationError, frappe.get_doc(pi).submit) | 		self.assertRaises(frappe.ValidationError, frappe.get_doc(pi).submit) | ||||||
| 
 | 
 | ||||||
| 	def test_purchase_receipt_no_gl_entry(self): | 	def test_purchase_receipt_no_gl_entry(self): | ||||||
| 		self._clear_stock_account_balance() |  | ||||||
| 		set_perpetual_inventory(0) | 		set_perpetual_inventory(0) | ||||||
| 		pr = frappe.copy_doc(test_records[0]) |  | ||||||
| 		pr.insert() |  | ||||||
| 		pr.submit() |  | ||||||
| 		 | 		 | ||||||
| 		stock_value, stock_value_difference = frappe.db.get_value("Stock Ledger Entry", | 		existing_bin_stock_value = frappe.db.get_value("Bin", {"item_code": "_Test Item", | ||||||
| 			{"voucher_type": "Purchase Receipt", "voucher_no": pr.name, |  | ||||||
| 				"item_code": "_Test Item", "warehouse": "_Test Warehouse - _TC"}, |  | ||||||
| 			["stock_value", "stock_value_difference"]) |  | ||||||
| 		self.assertEqual(stock_value, 375) |  | ||||||
| 		self.assertEqual(stock_value_difference, 375) |  | ||||||
| 
 |  | ||||||
| 		bin_stock_value = frappe.db.get_value("Bin", {"item_code": "_Test Item", |  | ||||||
| 			"warehouse": "_Test Warehouse - _TC"}, "stock_value") | 			"warehouse": "_Test Warehouse - _TC"}, "stock_value") | ||||||
| 		self.assertEqual(bin_stock_value, 375) | 		 | ||||||
|  | 		pr = make_purchase_receipt() | ||||||
|  | 
 | ||||||
|  | 		stock_value_difference = frappe.db.get_value("Stock Ledger Entry", | ||||||
|  | 			{"voucher_type": "Purchase Receipt", "voucher_no": pr.name, | ||||||
|  | 				"item_code": "_Test Item", "warehouse": "_Test Warehouse - _TC"}, "stock_value_difference") | ||||||
|  | 
 | ||||||
|  | 		self.assertEqual(stock_value_difference, 250) | ||||||
|  | 
 | ||||||
|  | 		current_bin_stock_value = frappe.db.get_value("Bin", {"item_code": "_Test Item", | ||||||
|  | 			"warehouse": "_Test Warehouse - _TC"}, "stock_value") | ||||||
|  | 		self.assertEqual(current_bin_stock_value, existing_bin_stock_value + 250) | ||||||
| 
 | 
 | ||||||
| 		self.assertFalse(get_gl_entries("Purchase Receipt", pr.name)) | 		self.assertFalse(get_gl_entries("Purchase Receipt", pr.name)) | ||||||
| 
 | 
 | ||||||
| 	def test_purchase_receipt_gl_entry(self): | 	def test_purchase_receipt_gl_entry(self): | ||||||
| 		self._clear_stock_account_balance() |  | ||||||
| 
 |  | ||||||
| 		set_perpetual_inventory() | 		set_perpetual_inventory() | ||||||
| 		self.assertEqual(cint(frappe.defaults.get_global_default("auto_accounting_for_stock")), 1) | 		self.assertEqual(cint(frappe.defaults.get_global_default("auto_accounting_for_stock")), 1) | ||||||
| 		pr = frappe.copy_doc(test_records[0]) | 		pr = frappe.copy_doc(test_records[0]) | ||||||
| @ -84,39 +77,20 @@ class TestPurchaseReceipt(unittest.TestCase): | |||||||
| 
 | 
 | ||||||
| 		set_perpetual_inventory(0) | 		set_perpetual_inventory(0) | ||||||
| 
 | 
 | ||||||
| 	def _clear_stock_account_balance(self): |  | ||||||
| 		frappe.db.sql("delete from `tabStock Ledger Entry`") |  | ||||||
| 		frappe.db.sql("""delete from `tabBin`""") |  | ||||||
| 		frappe.db.sql("""delete from `tabGL Entry`""") |  | ||||||
| 
 |  | ||||||
| 	def test_subcontracting(self): | 	def test_subcontracting(self): | ||||||
| 		pr = frappe.copy_doc(test_records[1]) | 		pr = make_purchase_receipt(item_code="_Test FG Item", qty=10, rate=500, is_subcontracted="Yes") | ||||||
| 		pr.run_method("calculate_taxes_and_totals") |  | ||||||
| 		pr.insert() |  | ||||||
| 
 |  | ||||||
| 		self.assertEquals(len(pr.get("supplied_items")), 2) | 		self.assertEquals(len(pr.get("supplied_items")), 2) | ||||||
| 		self.assertEquals(pr.get("items")[0].rm_supp_cost, 20750.0) |  | ||||||
| 		 | 		 | ||||||
|  | 		rm_supp_cost = sum([d.amount for d in pr.get("supplied_items")]) | ||||||
|  | 		self.assertEquals(pr.get("items")[0].rm_supp_cost, flt(rm_supp_cost, 2)) | ||||||
| 
 | 
 | ||||||
| 	def test_serial_no_supplier(self): | 	def test_serial_no_supplier(self): | ||||||
| 		pr = frappe.copy_doc(test_records[0]) | 		pr = make_purchase_receipt(item_code="_Test Serialized Item With Series", qty=1) | ||||||
| 		pr.get("items")[0].item_code = "_Test Serialized Item With Series" | 		self.assertEquals(frappe.db.get_value("Serial No", pr.get("items")[0].serial_no, "supplier"),  | ||||||
| 		pr.get("items")[0].qty = 1 | 			pr.supplier) | ||||||
| 		pr.get("items")[0].received_qty = 1 |  | ||||||
| 		pr.insert() |  | ||||||
| 		pr.submit() |  | ||||||
| 		 | 		 | ||||||
| 		self.assertEquals(frappe.db.get_value("Serial No", pr.get("items")[0].serial_no, |  | ||||||
| 			"supplier"), pr.supplier) |  | ||||||
| 
 |  | ||||||
| 		return pr |  | ||||||
| 
 |  | ||||||
| 	def test_serial_no_cancel(self): |  | ||||||
| 		pr = self.test_serial_no_supplier() |  | ||||||
| 		pr.cancel() | 		pr.cancel() | ||||||
| 
 | 		self.assertFalse(frappe.db.get_value("Serial No", pr.get("items")[0].serial_no, "warehouse")) | ||||||
| 		self.assertFalse(frappe.db.get_value("Serial No", pr.get("items")[0].serial_no, |  | ||||||
| 			"warehouse")) |  | ||||||
| 
 | 
 | ||||||
| 	def test_rejected_serial_no(self): | 	def test_rejected_serial_no(self): | ||||||
| 		pr = frappe.copy_doc(test_records[0]) | 		pr = frappe.copy_doc(test_records[0]) | ||||||
| @ -150,7 +124,33 @@ def set_perpetual_inventory(enable=1): | |||||||
| 	accounts_settings.auto_accounting_for_stock = enable | 	accounts_settings.auto_accounting_for_stock = enable | ||||||
| 	accounts_settings.save() | 	accounts_settings.save() | ||||||
| 	 | 	 | ||||||
|  | def make_purchase_receipt(**args): | ||||||
|  | 	pr = frappe.new_doc("Purchase Receipt") | ||||||
|  | 	args = frappe._dict(args) | ||||||
|  | 	if args.posting_date: | ||||||
|  | 		pr.posting_date = args.posting_date | ||||||
|  | 	if args.posting_time: | ||||||
|  | 		pr.posting_time = args.posting_time | ||||||
|  | 	pr.company = args.company or "_Test Company" | ||||||
|  | 	pr.supplier = args.supplier or "_Test Supplier" | ||||||
|  | 	pr.is_subcontracted = args.is_subcontracted or "No" | ||||||
|  | 	pr.supplier_warehouse = "_Test Warehouse 1 - _TC" | ||||||
|  | 	 | ||||||
|  | 	pr.append("items", { | ||||||
|  | 		"item_code": args.item or args.item_code or "_Test Item", | ||||||
|  | 		"warehouse": args.warehouse or "_Test Warehouse - _TC", | ||||||
|  | 		"qty": args.qty or 5, | ||||||
|  | 		"received_qty": args.qty or 5, | ||||||
|  | 		"rate": args.rate or 50, | ||||||
|  | 		"conversion_factor": 1.0, | ||||||
|  | 		"serial_no": args.serial_no | ||||||
|  | 	}) | ||||||
|  | 	if not args.do_not_save: | ||||||
|  | 		pr.insert() | ||||||
|  | 		if not args.do_not_submit: | ||||||
|  | 			pr.submit() | ||||||
|  | 	return pr | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| test_dependencies = ["BOM", "Item Price"] | test_dependencies = ["BOM", "Item Price"] | ||||||
| 
 |  | ||||||
| test_records = frappe.get_test_records('Purchase Receipt') | test_records = frappe.get_test_records('Purchase Receipt') | ||||||
|  | |||||||
| @ -5,7 +5,6 @@ | |||||||
|   "conversion_rate": 1.0,  |   "conversion_rate": 1.0,  | ||||||
|   "currency": "INR",  |   "currency": "INR",  | ||||||
|   "doctype": "Purchase Receipt",  |   "doctype": "Purchase Receipt",  | ||||||
|   "fiscal_year": "_Test Fiscal Year 2013",  |  | ||||||
|   "base_grand_total": 720.0,  |   "base_grand_total": 720.0,  | ||||||
|   "naming_series": "_T-Purchase Receipt-",  |   "naming_series": "_T-Purchase Receipt-",  | ||||||
|   "base_net_total": 500.0,  |   "base_net_total": 500.0,  | ||||||
| @ -47,8 +46,6 @@ | |||||||
| 	"cost_center": "Main - _TC" | 	"cost_center": "Main - _TC" | ||||||
|    } |    } | ||||||
|   ],  |   ],  | ||||||
|   "posting_date": "2013-02-12",  |  | ||||||
|   "posting_time": "15:33:30",  |  | ||||||
|   "items": [ |   "items": [ | ||||||
|    { |    { | ||||||
|     "base_amount": 250.0,  |     "base_amount": 250.0,  | ||||||
| @ -62,7 +59,7 @@ | |||||||
|     "rate": 50.0,  |     "rate": 50.0,  | ||||||
|     "received_qty": 5.0,  |     "received_qty": 5.0,  | ||||||
|     "rejected_qty": 0.0,  |     "rejected_qty": 0.0,  | ||||||
|     "stock_uom": "Nos",  |     "stock_uom": "_Test UOM",  | ||||||
|     "uom": "_Test UOM",  |     "uom": "_Test UOM",  | ||||||
|     "warehouse": "_Test Warehouse - _TC", |     "warehouse": "_Test Warehouse - _TC", | ||||||
| 	"cost_center": "Main - _TC" | 	"cost_center": "Main - _TC" | ||||||
| @ -79,7 +76,7 @@ | |||||||
|     "rate": 50.0,  |     "rate": 50.0,  | ||||||
|     "received_qty": 5.0,  |     "received_qty": 5.0,  | ||||||
|     "rejected_qty": 0.0,  |     "rejected_qty": 0.0,  | ||||||
|     "stock_uom": "Nos",  |     "stock_uom": "_Test UOM",  | ||||||
|     "uom": "_Test UOM",  |     "uom": "_Test UOM",  | ||||||
|     "warehouse": "_Test Warehouse 1 - _TC", |     "warehouse": "_Test Warehouse 1 - _TC", | ||||||
| 	"cost_center": "Main - _TC" | 	"cost_center": "Main - _TC" | ||||||
| @ -87,6 +84,8 @@ | |||||||
|   ],  |   ],  | ||||||
|   "supplier": "_Test Supplier" |   "supplier": "_Test Supplier" | ||||||
|  },  |  },  | ||||||
|  |   | ||||||
|  |   | ||||||
|  { |  { | ||||||
|   "buying_price_list": "_Test Price List",  |   "buying_price_list": "_Test Price List",  | ||||||
|   "company": "_Test Company",  |   "company": "_Test Company",  | ||||||
| @ -112,7 +111,7 @@ | |||||||
|     "rate": 500.0,  |     "rate": 500.0,  | ||||||
|     "received_qty": 10.0,  |     "received_qty": 10.0,  | ||||||
|     "rejected_qty": 0.0,  |     "rejected_qty": 0.0,  | ||||||
|     "stock_uom": "Nos",  |     "stock_uom": "_Test UOM",  | ||||||
|     "uom": "_Test UOM",  |     "uom": "_Test UOM",  | ||||||
|     "warehouse": "_Test Warehouse - _TC", |     "warehouse": "_Test Warehouse - _TC", | ||||||
| 	"cost_center": "Main - _TC" | 	"cost_center": "Main - _TC" | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ from __future__ import unicode_literals | |||||||
| import frappe | import frappe | ||||||
| import frappe.defaults | import frappe.defaults | ||||||
| 
 | 
 | ||||||
| from frappe.utils import cstr, cint, flt, comma_or, nowdate | from frappe.utils import cstr, cint, flt, comma_or, nowdate, get_datetime | ||||||
| 
 | 
 | ||||||
| from frappe import _ | from frappe import _ | ||||||
| from erpnext.stock.utils import get_incoming_rate | from erpnext.stock.utils import get_incoming_rate | ||||||
| @ -298,8 +298,6 @@ class StockEntry(StockController): | |||||||
| 			number_of_fg_items = len([t.t_warehouse for t in self.get("items") if t.t_warehouse]) | 			number_of_fg_items = len([t.t_warehouse for t in self.get("items") if t.t_warehouse]) | ||||||
| 			for d in self.get("items"): | 			for d in self.get("items"): | ||||||
| 				if d.bom_no or (d.t_warehouse and number_of_fg_items == 1): | 				if d.bom_no or (d.t_warehouse and number_of_fg_items == 1): | ||||||
| 					operation_cost_per_unit = 0.0 |  | ||||||
| 					if self.production_order: |  | ||||||
| 					operation_cost_per_unit = self.get_operation_cost_per_unit(d.bom_no, d.qty) | 					operation_cost_per_unit = self.get_operation_cost_per_unit(d.bom_no, d.qty) | ||||||
| 
 | 
 | ||||||
| 					d.incoming_rate = operation_cost_per_unit + (raw_material_cost / flt(d.transfer_qty)) | 					d.incoming_rate = operation_cost_per_unit + (raw_material_cost / flt(d.transfer_qty)) | ||||||
| @ -394,13 +392,13 @@ class StockEntry(StockController): | |||||||
| 				frappe.throw(_("'Update Stock' for Sales Invoice {0} must be set").format(ref.doc.name), NotUpdateStockError) | 				frappe.throw(_("'Update Stock' for Sales Invoice {0} must be set").format(ref.doc.name), NotUpdateStockError) | ||||||
| 
 | 
 | ||||||
| 			# posting date check | 			# posting date check | ||||||
| 			ref_posting_datetime = "%s %s" % (cstr(ref.doc.posting_date), | 			ref_posting_datetime = "%s %s" % (ref.doc.posting_date, ref.doc.posting_time or "00:00:00") | ||||||
| 				cstr(ref.doc.posting_time) or "00:00:00") | 			this_posting_datetime = "%s %s" % (self.posting_date, self.posting_time) | ||||||
| 			this_posting_datetime = "%s %s" % (cstr(self.posting_date), | 			 | ||||||
| 				cstr(self.posting_time)) | 			if get_datetime(ref_posting_datetime) < get_datetime(ref_posting_datetime): | ||||||
| 			if this_posting_datetime < ref_posting_datetime: |  | ||||||
| 				from frappe.utils.dateutils import datetime_in_user_format | 				from frappe.utils.dateutils import datetime_in_user_format | ||||||
| 				frappe.throw(_("Posting timestamp must be after {0}").format(datetime_in_user_format(ref_posting_datetime))) | 				frappe.throw(_("Posting timestamp must be after {0}") | ||||||
|  | 					.format(datetime_in_user_format(ref_posting_datetime))) | ||||||
| 
 | 
 | ||||||
| 			stock_items = get_stock_items_for_return(ref.doc, ref.parentfields) | 			stock_items = get_stock_items_for_return(ref.doc, ref.parentfields) | ||||||
| 			already_returned_item_qty = self.get_already_returned_item_qty(ref.fieldname) | 			already_returned_item_qty = self.get_already_returned_item_qty(ref.fieldname) | ||||||
|  | |||||||
| @ -2,7 +2,6 @@ | |||||||
|  { |  { | ||||||
|   "company": "_Test Company",  |   "company": "_Test Company",  | ||||||
|   "doctype": "Stock Entry",  |   "doctype": "Stock Entry",  | ||||||
|   "fiscal_year": "_Test Fiscal Year 2013",  |  | ||||||
|   "items": [ |   "items": [ | ||||||
|    { |    { | ||||||
|     "conversion_factor": 1.0,  |     "conversion_factor": 1.0,  | ||||||
| @ -19,10 +18,10 @@ | |||||||
|     "uom": "_Test UOM" |     "uom": "_Test UOM" | ||||||
|    } |    } | ||||||
|   ],  |   ],  | ||||||
|   "posting_date": "2013-01-01",  |  | ||||||
|   "posting_time": "17:14:24",  |  | ||||||
|   "purpose": "Material Receipt" |   "purpose": "Material Receipt" | ||||||
|  },  |  },  | ||||||
|  |   | ||||||
|  |   | ||||||
|  { |  { | ||||||
|   "company": "_Test Company",  |   "company": "_Test Company",  | ||||||
|   "doctype": "Stock Entry",  |   "doctype": "Stock Entry",  | ||||||
| @ -47,6 +46,8 @@ | |||||||
|   "posting_time": "17:15",  |   "posting_time": "17:15",  | ||||||
|   "purpose": "Material Issue" |   "purpose": "Material Issue" | ||||||
|  },  |  },  | ||||||
|  |   | ||||||
|  |   | ||||||
|  { |  { | ||||||
|   "company": "_Test Company",  |   "company": "_Test Company",  | ||||||
|   "doctype": "Stock Entry",  |   "doctype": "Stock Entry",  | ||||||
| @ -72,6 +73,8 @@ | |||||||
|   "posting_time": "17:14:24",  |   "posting_time": "17:14:24",  | ||||||
|   "purpose": "Material Transfer" |   "purpose": "Material Transfer" | ||||||
|  },  |  },  | ||||||
|  |   | ||||||
|  |   | ||||||
|  { |  { | ||||||
|   "company": "_Test Company",  |   "company": "_Test Company",  | ||||||
|   "doctype": "Stock Entry",  |   "doctype": "Stock Entry",  | ||||||
| @ -106,8 +109,6 @@ | |||||||
|     "uom": "_Test UOM" |     "uom": "_Test UOM" | ||||||
|    } |    } | ||||||
|   ],  |   ],  | ||||||
|   "posting_date": "2013-01-25",  |  | ||||||
|   "posting_time": "17:14:24",  |  | ||||||
|   "purpose": "Repack" |   "purpose": "Repack" | ||||||
|  } |  } | ||||||
| ] | ] | ||||||
| @ -4,10 +4,16 @@ | |||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
| import frappe, unittest | import frappe, unittest | ||||||
| import frappe.defaults | import frappe.defaults | ||||||
| from frappe.utils import flt, getdate | from frappe.utils import flt, nowdate, nowtime | ||||||
| from erpnext.stock.doctype.serial_no.serial_no import * | from erpnext.stock.doctype.serial_no.serial_no import * | ||||||
| from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory | from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt \ | ||||||
|  | 	import set_perpetual_inventory, make_purchase_receipt | ||||||
| from erpnext.stock.doctype.stock_ledger_entry.stock_ledger_entry import StockFreezeError | from erpnext.stock.doctype.stock_ledger_entry.stock_ledger_entry import StockFreezeError | ||||||
|  | from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchase_invoice | ||||||
|  | from erpnext.stock.stock_ledger import get_previous_sle | ||||||
|  | from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order, create_dn_against_so | ||||||
|  | from erpnext.stock.doctype.stock_entry.stock_entry import make_return_jv, NotUpdateStockError | ||||||
|  | from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation | ||||||
| 
 | 
 | ||||||
| def get_sle(**args): | def get_sle(**args): | ||||||
| 	condition, values = "", [] | 	condition, values = "", [] | ||||||
| @ -20,35 +26,25 @@ def get_sle(**args): | |||||||
| 		order by timestamp(posting_date, posting_time) desc, name desc limit 1"""% condition, | 		order by timestamp(posting_date, posting_time) desc, name desc limit 1"""% condition, | ||||||
| 		values, as_dict=1) | 		values, as_dict=1) | ||||||
| 
 | 
 | ||||||
| def make_zero(item_code, warehouse): |  | ||||||
| 	sle = get_sle(item_code = item_code, warehouse = warehouse) |  | ||||||
| 	qty = sle[0].qty_after_transaction if sle else 0 |  | ||||||
| 	if qty < 0: |  | ||||||
| 		make_stock_entry(item_code=item_code, target=warehouse, qty=abs(qty), incoming_rate=10) |  | ||||||
| 	elif qty > 0: |  | ||||||
| 		make_stock_entry(item_code=item_code, source=warehouse, qty=qty, incoming_rate=10) |  | ||||||
| 
 |  | ||||||
| class TestStockEntry(unittest.TestCase): | class TestStockEntry(unittest.TestCase): | ||||||
| 	def tearDown(self): | 	def tearDown(self): | ||||||
| 		frappe.set_user("Administrator") | 		frappe.set_user("Administrator") | ||||||
| 		set_perpetual_inventory(0) | 		set_perpetual_inventory(0) | ||||||
| 		if hasattr(self, "old_default_company"): |  | ||||||
| 			frappe.db.set_default("company", self.old_default_company) |  | ||||||
| 
 | 
 | ||||||
| 	def test_fifo(self): | 	def test_fifo(self): | ||||||
| 		frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1) | 		frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1) | ||||||
| 		item_code = "_Test Item 2" | 		item_code = "_Test Item 2" | ||||||
| 		warehouse = "_Test Warehouse - _TC" | 		warehouse = "_Test Warehouse - _TC" | ||||||
| 		make_zero(item_code, warehouse) | 		 | ||||||
|  | 		create_stock_reconciliation(item_code="_Test Item 2", warehouse="_Test Warehouse - _TC",  | ||||||
|  | 			qty=0, rate=100) | ||||||
| 
 | 
 | ||||||
| 		make_stock_entry(item_code=item_code, target=warehouse, qty=1, incoming_rate=10) | 		make_stock_entry(item_code=item_code, target=warehouse, qty=1, incoming_rate=10) | ||||||
| 		sle = get_sle(item_code = item_code, warehouse = warehouse)[0] | 		sle = get_sle(item_code = item_code, warehouse = warehouse)[0] | ||||||
| 
 |  | ||||||
| 		self.assertEqual([[1, 10]], eval(sle.stock_queue)) | 		self.assertEqual([[1, 10]], eval(sle.stock_queue)) | ||||||
| 
 | 
 | ||||||
| 		# negative qty | 		# negative qty | ||||||
| 		make_zero(item_code, warehouse) | 		make_stock_entry(item_code=item_code, source=warehouse, qty=2, incoming_rate=10) | ||||||
| 		make_stock_entry(item_code=item_code, source=warehouse, qty=1, incoming_rate=10) |  | ||||||
| 		sle = get_sle(item_code = item_code, warehouse = warehouse)[0] | 		sle = get_sle(item_code = item_code, warehouse = warehouse)[0] | ||||||
| 
 | 
 | ||||||
| 		self.assertEqual([[-1, 10]], eval(sle.stock_queue)) | 		self.assertEqual([[-1, 10]], eval(sle.stock_queue)) | ||||||
| @ -60,10 +56,15 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 		self.assertEqual([[-2, 10]], eval(sle.stock_queue)) | 		self.assertEqual([[-2, 10]], eval(sle.stock_queue)) | ||||||
| 
 | 
 | ||||||
| 		# move stock to positive | 		# move stock to positive | ||||||
| 		make_stock_entry(item_code=item_code, target=warehouse, qty=3, incoming_rate=10) | 		make_stock_entry(item_code=item_code, target=warehouse, qty=3, incoming_rate=20) | ||||||
|  | 		sle = get_sle(item_code = item_code, warehouse = warehouse)[0] | ||||||
|  | 		self.assertEqual([[1, 20]], eval(sle.stock_queue))		 | ||||||
|  | 		 | ||||||
|  | 		# incoming entry with diff rate | ||||||
|  | 		make_stock_entry(item_code=item_code, target=warehouse, qty=1, incoming_rate=30) | ||||||
| 		sle = get_sle(item_code = item_code, warehouse = warehouse)[0] | 		sle = get_sle(item_code = item_code, warehouse = warehouse)[0] | ||||||
| 
 | 
 | ||||||
| 		self.assertEqual([[1, 10]], eval(sle.stock_queue)) | 		self.assertEqual([[1, 20],[1, 30]], eval(sle.stock_queue)) | ||||||
| 
 | 
 | ||||||
| 		frappe.db.set_default("allow_negative_stock", 0)		 | 		frappe.db.set_default("allow_negative_stock", 0)		 | ||||||
| 
 | 
 | ||||||
| @ -92,7 +93,7 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 
 | 
 | ||||||
| 		# update re-level qty so that it is more than projected_qty | 		# update re-level qty so that it is more than projected_qty | ||||||
| 		if projected_qty > template.reorder_levels[0].warehouse_reorder_level: | 		if projected_qty > template.reorder_levels[0].warehouse_reorder_level: | ||||||
| 			template.reorder_levels[0].warehouse_reorder_level += projected_qty | 			template.reorder_levels[0].warehouse_reorder_level = projected_qty | ||||||
| 			template.save() | 			template.save() | ||||||
| 
 | 
 | ||||||
| 		from erpnext.stock.reorder_item import reorder_item | 		from erpnext.stock.reorder_item import reorder_item | ||||||
| @ -108,12 +109,10 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 		self.assertTrue(item_code in items) | 		self.assertTrue(item_code in items) | ||||||
| 
 | 
 | ||||||
| 	def test_material_receipt_gl_entry(self): | 	def test_material_receipt_gl_entry(self): | ||||||
| 		self._clear_stock_account_balance() |  | ||||||
| 		set_perpetual_inventory() | 		set_perpetual_inventory() | ||||||
| 		 | 		 | ||||||
| 		mr = frappe.copy_doc(test_records[0]) | 		mr = make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC",  | ||||||
| 		mr.insert() | 			qty=50, incoming_rate=100) | ||||||
| 		mr.submit() |  | ||||||
| 
 | 
 | ||||||
| 		stock_in_hand_account = frappe.db.get_value("Account", {"account_type": "Warehouse", | 		stock_in_hand_account = frappe.db.get_value("Account", {"account_type": "Warehouse", | ||||||
| 			"warehouse": mr.get("items")[0].t_warehouse}) | 			"warehouse": mr.get("items")[0].t_warehouse}) | ||||||
| @ -136,52 +135,45 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 		self.assertFalse(frappe.db.sql("""select * from `tabGL Entry` | 		self.assertFalse(frappe.db.sql("""select * from `tabGL Entry` | ||||||
| 			where voucher_type='Stock Entry' and voucher_no=%s""", mr.name)) | 			where voucher_type='Stock Entry' and voucher_no=%s""", mr.name)) | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 	def test_material_issue_gl_entry(self): | 	def test_material_issue_gl_entry(self): | ||||||
| 		self._clear_stock_account_balance() |  | ||||||
| 		set_perpetual_inventory() | 		set_perpetual_inventory() | ||||||
| 
 | 
 | ||||||
| 		self._insert_material_receipt() | 		make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC",  | ||||||
|  | 			qty=50, incoming_rate=100) | ||||||
| 		 | 		 | ||||||
| 		mi = frappe.copy_doc(test_records[1]) | 		mi = make_stock_entry(item_code="_Test Item", source="_Test Warehouse - _TC", qty=40) | ||||||
| 		mi.insert() |  | ||||||
| 		mi.submit() |  | ||||||
| 
 | 
 | ||||||
| 		self.check_stock_ledger_entries("Stock Entry", mi.name, | 		self.check_stock_ledger_entries("Stock Entry", mi.name, | ||||||
| 			[["_Test Item", "_Test Warehouse - _TC", -40.0]]) | 			[["_Test Item", "_Test Warehouse - _TC", -40.0]]) | ||||||
| 
 | 
 | ||||||
| 		stock_in_hand_account = frappe.db.get_value("Account", {"account_type": "Warehouse", | 		stock_in_hand_account = frappe.db.get_value("Account", {"account_type": "Warehouse", | ||||||
| 			"warehouse": mi.get("items")[0].s_warehouse}) | 			"warehouse": "_Test Warehouse - _TC"}) | ||||||
|  | 			 | ||||||
|  | 		stock_value_diff = abs(frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Stock Entry",  | ||||||
|  | 			"voucher_no": mi.name}, "stock_value_difference")) | ||||||
| 
 | 
 | ||||||
| 		self.check_gl_entries("Stock Entry", mi.name, | 		self.check_gl_entries("Stock Entry", mi.name, | ||||||
| 			sorted([ | 			sorted([ | ||||||
| 				[stock_in_hand_account, 0.0, 4000.0], | 				[stock_in_hand_account, 0.0, stock_value_diff], | ||||||
| 				["Stock Adjustment - _TC", 4000.0, 0.0] | 				["Stock Adjustment - _TC", stock_value_diff, 0.0] | ||||||
| 			]) | 			]) | ||||||
| 		) | 		) | ||||||
| 
 | 
 | ||||||
| 		mi.cancel() | 		mi.cancel() | ||||||
| 		self.assertFalse(frappe.db.sql("""select * from `tabStock Ledger Entry` | 		 | ||||||
|  | 		self.assertFalse(frappe.db.sql("""select name from `tabStock Ledger Entry` | ||||||
| 			where voucher_type='Stock Entry' and voucher_no=%s""", mi.name)) | 			where voucher_type='Stock Entry' and voucher_no=%s""", mi.name)) | ||||||
| 
 | 
 | ||||||
| 		self.assertFalse(frappe.db.sql("""select * from `tabGL Entry` | 		self.assertFalse(frappe.db.sql("""select name from `tabGL Entry` | ||||||
| 			where voucher_type='Stock Entry' and voucher_no=%s""", mi.name)) | 			where voucher_type='Stock Entry' and voucher_no=%s""", mi.name)) | ||||||
| 
 | 
 | ||||||
| 		self.assertEquals(frappe.db.get_value("Bin", {"warehouse": mi.get("items")[0].s_warehouse, |  | ||||||
| 			"item_code": mi.get("items")[0].item_code}, "actual_qty"), 50) |  | ||||||
| 
 |  | ||||||
| 		self.assertEquals(frappe.db.get_value("Bin", {"warehouse": mi.get("items")[0].s_warehouse, |  | ||||||
| 			"item_code": mi.get("items")[0].item_code}, "stock_value"), 5000) |  | ||||||
| 
 |  | ||||||
| 	def test_material_transfer_gl_entry(self): | 	def test_material_transfer_gl_entry(self): | ||||||
| 		self._clear_stock_account_balance() |  | ||||||
| 		set_perpetual_inventory() | 		set_perpetual_inventory() | ||||||
| 		 | 		 | ||||||
| 		self._insert_material_receipt() | 		create_stock_reconciliation(qty=100, rate=100) | ||||||
| 			 | 			 | ||||||
| 		mtn = frappe.copy_doc(test_records[2]) | 		mtn = make_stock_entry(item_code="_Test Item", source="_Test Warehouse - _TC",  | ||||||
| 		mtn.insert() | 			target="_Test Warehouse 1 - _TC", qty=45) | ||||||
| 		mtn.submit() |  | ||||||
| 			 | 			 | ||||||
| 		self.check_stock_ledger_entries("Stock Entry", mtn.name, | 		self.check_stock_ledger_entries("Stock Entry", mtn.name, | ||||||
| 			[["_Test Item", "_Test Warehouse - _TC", -45.0], ["_Test Item", "_Test Warehouse 1 - _TC", 45.0]]) | 			[["_Test Item", "_Test Warehouse - _TC", -45.0], ["_Test Item", "_Test Warehouse 1 - _TC", 45.0]]) | ||||||
| @ -192,15 +184,16 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 		fixed_asset_account = frappe.db.get_value("Account", {"account_type": "Warehouse", | 		fixed_asset_account = frappe.db.get_value("Account", {"account_type": "Warehouse", | ||||||
| 			"warehouse": mtn.get("items")[0].t_warehouse}) | 			"warehouse": mtn.get("items")[0].t_warehouse}) | ||||||
| 
 | 
 | ||||||
|  | 		stock_value_diff = abs(frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Stock Entry",  | ||||||
|  | 			"voucher_no": mtn.name, "warehouse": "_Test Warehouse - _TC"}, "stock_value_difference")) | ||||||
| 
 | 
 | ||||||
| 		self.check_gl_entries("Stock Entry", mtn.name, | 		self.check_gl_entries("Stock Entry", mtn.name, | ||||||
| 			sorted([ | 			sorted([ | ||||||
| 				[stock_in_hand_account, 0.0, 4500.0], | 				[stock_in_hand_account, 0.0, stock_value_diff], | ||||||
| 				[fixed_asset_account, 4500.0, 0.0], | 				[fixed_asset_account, stock_value_diff, 0.0], | ||||||
| 			]) | 			]) | ||||||
| 		) | 		) | ||||||
| 		 | 		 | ||||||
| 
 |  | ||||||
| 		mtn.cancel() | 		mtn.cancel() | ||||||
| 		self.assertFalse(frappe.db.sql("""select * from `tabStock Ledger Entry` | 		self.assertFalse(frappe.db.sql("""select * from `tabStock Ledger Entry` | ||||||
| 			where voucher_type='Stock Entry' and voucher_no=%s""", mtn.name)) | 			where voucher_type='Stock Entry' and voucher_no=%s""", mtn.name)) | ||||||
| @ -208,14 +201,16 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 		self.assertFalse(frappe.db.sql("""select * from `tabGL Entry` | 		self.assertFalse(frappe.db.sql("""select * from `tabGL Entry` | ||||||
| 			where voucher_type='Stock Entry' and voucher_no=%s""", mtn.name)) | 			where voucher_type='Stock Entry' and voucher_no=%s""", mtn.name)) | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 	def test_repack_no_change_in_valuation(self): | 	def test_repack_no_change_in_valuation(self): | ||||||
| 		self._clear_stock_account_balance() | 		set_perpetual_inventory(0) | ||||||
| 		set_perpetual_inventory() |  | ||||||
| 
 | 
 | ||||||
| 		self._insert_material_receipt() | 		make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, incoming_rate=100) | ||||||
|  | 		make_stock_entry(item_code="_Test Item Home Desktop 100", target="_Test Warehouse - _TC",  | ||||||
|  | 			qty=50, incoming_rate=100) | ||||||
| 
 | 
 | ||||||
| 		repack = frappe.copy_doc(test_records[3]) | 		repack = frappe.copy_doc(test_records[3]) | ||||||
|  | 		repack.posting_date = nowdate() | ||||||
|  | 		repack.posting_time = nowtime() | ||||||
| 		repack.insert() | 		repack.insert() | ||||||
| 		repack.submit() | 		repack.submit() | ||||||
| 
 | 
 | ||||||
| @ -231,23 +226,32 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 		set_perpetual_inventory(0) | 		set_perpetual_inventory(0) | ||||||
| 
 | 
 | ||||||
| 	def test_repack_with_change_in_valuation(self): | 	def test_repack_with_change_in_valuation(self): | ||||||
| 		self._clear_stock_account_balance() |  | ||||||
| 		set_perpetual_inventory() | 		set_perpetual_inventory() | ||||||
| 
 | 
 | ||||||
| 		self._insert_material_receipt() | 		make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, incoming_rate=100) | ||||||
| 		 | 		 | ||||||
| 		repack = frappe.copy_doc(test_records[3]) | 		repack = frappe.copy_doc(test_records[3]) | ||||||
| 		repack.get("items")[1].incoming_rate = 6000 | 		repack.posting_date = nowdate() | ||||||
|  | 		repack.posting_time = nowtime() | ||||||
|  | 		repack.additional_operating_cost = 1000.0 | ||||||
| 		repack.insert() | 		repack.insert() | ||||||
| 		repack.submit() | 		repack.submit() | ||||||
| 
 | 
 | ||||||
| 		stock_in_hand_account = frappe.db.get_value("Account", {"account_type": "Warehouse", | 		stock_in_hand_account = frappe.db.get_value("Account", {"account_type": "Warehouse", | ||||||
| 			"warehouse": repack.get("items")[1].t_warehouse}) | 			"warehouse": repack.get("items")[1].t_warehouse}) | ||||||
| 			 | 			 | ||||||
|  | 		rm_stock_value_diff = abs(frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Stock Entry",  | ||||||
|  | 			"voucher_no": repack.name, "item_code": "_Test Item"}, "stock_value_difference")) | ||||||
|  | 		 | ||||||
|  | 		fg_stock_value_diff = abs(frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Stock Entry",  | ||||||
|  | 			"voucher_no": repack.name, "item_code": "_Test Item Home Desktop 100"}, "stock_value_difference")) | ||||||
|  | 		 | ||||||
|  | 		stock_value_diff = flt(fg_stock_value_diff - rm_stock_value_diff, 2) | ||||||
|  | 
 | ||||||
| 		self.check_gl_entries("Stock Entry", repack.name, | 		self.check_gl_entries("Stock Entry", repack.name, | ||||||
| 			sorted([ | 			sorted([ | ||||||
| 				[stock_in_hand_account, 1000.0, 0.0], | 				[stock_in_hand_account, stock_value_diff, 0.0], | ||||||
| 				["Stock Adjustment - _TC", 0.0, 1000.0], | 				["Stock Adjustment - _TC", 0.0, stock_value_diff], | ||||||
| 			]) | 			]) | ||||||
| 		) | 		) | ||||||
| 		set_perpetual_inventory(0) | 		set_perpetual_inventory(0) | ||||||
| @ -274,6 +278,7 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 		gl_entries = frappe.db.sql("""select account, debit, credit | 		gl_entries = frappe.db.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) | 			order by account asc, debit asc""", (voucher_type, voucher_no), as_list=1) | ||||||
|  | 						 | ||||||
| 		self.assertTrue(gl_entries) | 		self.assertTrue(gl_entries) | ||||||
| 		gl_entries.sort(key=lambda x: x[0]) | 		gl_entries.sort(key=lambda x: x[0]) | ||||||
| 
 | 
 | ||||||
| @ -282,180 +287,107 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 			self.assertEquals(expected_gl_entries[i][1], gle[1]) | 			self.assertEquals(expected_gl_entries[i][1], gle[1]) | ||||||
| 			self.assertEquals(expected_gl_entries[i][2], gle[2]) | 			self.assertEquals(expected_gl_entries[i][2], gle[2]) | ||||||
| 
 | 
 | ||||||
| 	def _insert_material_receipt(self): |  | ||||||
| 		self._clear_stock_account_balance() |  | ||||||
| 		se1 = frappe.copy_doc(test_records[0]) |  | ||||||
| 		se1.insert() |  | ||||||
| 		se1.submit() |  | ||||||
| 
 |  | ||||||
| 		se2 = frappe.copy_doc(test_records[0]) |  | ||||||
| 		se2.get("items")[0].item_code = "_Test Item Home Desktop 100" |  | ||||||
| 		se2.insert() |  | ||||||
| 		se2.submit() |  | ||||||
| 
 |  | ||||||
| 		frappe.db.set_default("company", self.old_default_company) |  | ||||||
| 
 |  | ||||||
| 	def _get_actual_qty(self): |  | ||||||
| 		return flt(frappe.db.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): | 	def _test_sales_invoice_return(self, item_code, delivered_qty, returned_qty): | ||||||
| 		from erpnext.stock.doctype.stock_entry.stock_entry import NotUpdateStockError | 		from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice | ||||||
| 
 | 
 | ||||||
| 		from erpnext.accounts.doctype.sales_invoice.test_sales_invoice \ | 		si = create_sales_invoice(item_code=item_code, qty=delivered_qty) | ||||||
| 			import test_records as sales_invoice_test_records |  | ||||||
| 
 | 
 | ||||||
| 		# invalid sales invoice as update stock not checked | 		se = make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=returned_qty,  | ||||||
| 		si = frappe.copy_doc(sales_invoice_test_records[1]) | 			purpose="Sales Return", sales_invoice_no=si.name, do_not_save=True) | ||||||
| 		si.insert() |  | ||||||
| 		si.submit() |  | ||||||
| 
 |  | ||||||
| 		se = frappe.copy_doc(test_records[0]) |  | ||||||
| 		se.purpose = "Sales Return" |  | ||||||
| 		se.sales_invoice_no = si.name |  | ||||||
| 		se.get("items")[0].qty = returned_qty |  | ||||||
| 		se.get("items")[0].transfer_qty = returned_qty |  | ||||||
| 		self.assertRaises(NotUpdateStockError, se.insert) | 		self.assertRaises(NotUpdateStockError, se.insert) | ||||||
| 
 | 
 | ||||||
| 		self._insert_material_receipt() | 		make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=200, incoming_rate=100) | ||||||
| 
 | 
 | ||||||
| 		# check currency available qty in bin | 		# check currency available qty in bin | ||||||
| 		actual_qty_0 = self._get_actual_qty() | 		actual_qty_0 = get_qty_after_transaction() | ||||||
| 
 | 
 | ||||||
| 		# insert a pos invoice with update stock | 		# insert a pos invoice with update stock | ||||||
| 		si = frappe.copy_doc(sales_invoice_test_records[1]) | 		si = create_sales_invoice(update_stock=1, item_code=item_code, qty=5) | ||||||
| 		si.update_stock = 1 |  | ||||||
| 		si.get("items")[0].warehouse = "_Test Warehouse - _TC" |  | ||||||
| 		si.get("items")[0].item_code = item_code |  | ||||||
| 		si.get("items")[0].qty = 5.0 |  | ||||||
| 		si.insert() |  | ||||||
| 		si.submit() |  | ||||||
| 
 | 
 | ||||||
| 		# check available bin qty after invoice submission | 		# check available bin qty after invoice submission | ||||||
| 		actual_qty_1 = self._get_actual_qty() | 		actual_qty_1 = get_qty_after_transaction() | ||||||
| 
 | 
 | ||||||
| 		self.assertEquals(actual_qty_0 - delivered_qty, actual_qty_1) | 		self.assertEquals(actual_qty_0 - delivered_qty, actual_qty_1) | ||||||
| 
 | 
 | ||||||
| 		# check if item is validated | 		# check if item is validated | ||||||
| 		se = frappe.copy_doc(test_records[0]) | 		se = make_stock_entry(item_code="_Test Item Home Desktop 200", target="_Test Warehouse - _TC",  | ||||||
| 		se.purpose = "Sales Return" | 			qty=returned_qty, purpose="Sales Return", sales_invoice_no=si.name, do_not_save=True) | ||||||
| 		se.sales_invoice_no = si.name |  | ||||||
| 		se.posting_date = "2013-03-10" |  | ||||||
| 		se.fiscal_year = "_Test Fiscal Year 2013" |  | ||||||
| 		se.get("items")[0].item_code = "_Test Item Home Desktop 200" |  | ||||||
| 		se.get("items")[0].qty = returned_qty |  | ||||||
| 		se.get("items")[0].transfer_qty = returned_qty |  | ||||||
| 
 | 
 | ||||||
| 		# check if stock entry gets submitted |  | ||||||
| 		self.assertRaises(frappe.DoesNotExistError, se.insert) | 		self.assertRaises(frappe.DoesNotExistError, se.insert) | ||||||
| 
 | 
 | ||||||
| 		# try again | 		# try again | ||||||
| 		se = frappe.copy_doc(test_records[0]) | 		se = make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC",  | ||||||
| 		se.purpose = "Sales Return" | 			qty=returned_qty, purpose="Sales Return", sales_invoice_no=si.name) | ||||||
| 		se.posting_date = "2013-03-10" |  | ||||||
| 		se.fiscal_year = "_Test Fiscal Year 2013" |  | ||||||
| 		se.sales_invoice_no = si.name |  | ||||||
| 		se.get("items")[0].qty = returned_qty |  | ||||||
| 		se.get("items")[0].transfer_qty = returned_qty |  | ||||||
| 		# in both cases item code remains _Test Item when returning |  | ||||||
| 		se.insert() |  | ||||||
| 
 |  | ||||||
| 		se.submit() |  | ||||||
| 
 | 
 | ||||||
| 		# check if available qty is increased | 		# check if available qty is increased | ||||||
| 		actual_qty_2 = self._get_actual_qty() | 		actual_qty_2 = get_qty_after_transaction() | ||||||
| 
 | 
 | ||||||
| 		self.assertEquals(actual_qty_1 + returned_qty, actual_qty_2) | 		self.assertEquals(actual_qty_1 + returned_qty, actual_qty_2) | ||||||
| 
 | 
 | ||||||
| 		return se | 		return se | ||||||
| 
 | 
 | ||||||
| 	def test_sales_invoice_return_of_non_packing_item(self): | 	def test_sales_invoice_return_of_non_packing_item(self): | ||||||
| 		self._clear_stock_account_balance() |  | ||||||
| 		self._test_sales_invoice_return("_Test Item", 5, 2) | 		self._test_sales_invoice_return("_Test Item", 5, 2) | ||||||
| 
 | 
 | ||||||
| 	def test_sales_invoice_return_of_packing_item(self): | 	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) | 		self._test_sales_invoice_return("_Test Sales BOM Item", 25, 20) | ||||||
| 
 | 
 | ||||||
| 	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() | 		from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note | ||||||
| 
 |  | ||||||
| 		from erpnext.stock.doctype.delivery_note.test_delivery_note \ |  | ||||||
| 			import test_records as delivery_note_test_records |  | ||||||
| 		 | 		 | ||||||
| 		from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice | 		from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice | ||||||
| 		 | 		 | ||||||
| 		actual_qty_0 = self._get_actual_qty() | 		make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, incoming_rate=100) | ||||||
| 		# make a delivery note based on this invoice |  | ||||||
| 		dn = frappe.copy_doc(delivery_note_test_records[0]) |  | ||||||
| 		dn.get("items")[0].item_code = item_code |  | ||||||
| 		dn.insert() |  | ||||||
| 		dn.submit() |  | ||||||
| 
 | 
 | ||||||
| 		actual_qty_1 = self._get_actual_qty() | 		actual_qty_0 = get_qty_after_transaction() | ||||||
|  | 		# make a delivery note based on this invoice | ||||||
|  | 		dn = create_delivery_note(item_code="_Test Item",  | ||||||
|  | 			warehouse="_Test Warehouse - _TC", qty=delivered_qty) | ||||||
|  | 
 | ||||||
|  | 		actual_qty_1 = get_qty_after_transaction() | ||||||
| 
 | 
 | ||||||
| 		self.assertEquals(actual_qty_0 - delivered_qty, actual_qty_1) | 		self.assertEquals(actual_qty_0 - delivered_qty, actual_qty_1) | ||||||
| 
 | 
 | ||||||
| 		si_doc = make_sales_invoice(dn.name) | 		si = make_sales_invoice(dn.name) | ||||||
| 
 |  | ||||||
| 		si = frappe.get_doc(si_doc) |  | ||||||
| 		si.posting_date = dn.posting_date |  | ||||||
| 		si.debit_to = "_Test Receivable - _TC" |  | ||||||
| 		for d in si.get("items"): |  | ||||||
| 			d.income_account = "Sales - _TC" |  | ||||||
| 			d.cost_center = "_Test Cost Center - _TC" |  | ||||||
| 		si.insert() | 		si.insert() | ||||||
| 		si.submit() | 		si.submit() | ||||||
| 
 | 
 | ||||||
| 		# insert and submit stock entry for sales return | 		# insert and submit stock entry for sales return | ||||||
| 		se = frappe.copy_doc(test_records[0]) | 		se = make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC",  | ||||||
| 		se.purpose = "Sales Return" | 			qty=returned_qty, purpose="Sales Return", delivery_note_no=dn.name) | ||||||
| 		se.delivery_note_no = dn.name |  | ||||||
| 		se.posting_date = "2013-03-10" |  | ||||||
| 		se.fiscal_year = "_Test Fiscal Year 2013" |  | ||||||
| 		se.get("items")[0].qty = se.get("items")[0].transfer_qty = returned_qty |  | ||||||
| 
 | 
 | ||||||
| 		se.insert() | 		actual_qty_2 = get_qty_after_transaction() | ||||||
| 		se.submit() |  | ||||||
| 
 |  | ||||||
| 		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 | 		return se | ||||||
| 
 | 
 | ||||||
| 	def test_delivery_note_return_of_non_packing_item(self): | 	def test_delivery_note_return_of_non_packing_item(self): | ||||||
| 		self._clear_stock_account_balance() |  | ||||||
| 		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._clear_stock_account_balance() |  | ||||||
| 		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): | 	def _test_sales_return_jv(self, se): | ||||||
| 		from erpnext.stock.doctype.stock_entry.stock_entry import make_return_jv |  | ||||||
| 		jv = make_return_jv(se.name) | 		jv = make_return_jv(se.name) | ||||||
| 
 | 
 | ||||||
| 		self.assertEqual(len(jv.get("accounts")), 2) | 		self.assertEqual(len(jv.get("accounts")), 2) | ||||||
| 		self.assertEqual(jv.get("voucher_type"), "Credit Note") | 		self.assertEqual(jv.get("voucher_type"), "Credit Note") | ||||||
| 		self.assertEqual(jv.get("posting_date"), se.posting_date) | 		self.assertEqual(jv.get("posting_date"), se.posting_date) | ||||||
| 		self.assertEqual(jv.get("accounts")[0].get("account"), "_Test Receivable - _TC") | 		self.assertEqual(jv.get("accounts")[0].get("account"), "Debtors - _TC") | ||||||
| 		self.assertEqual(jv.get("accounts")[0].get("party_type"), "Customer") | 		self.assertEqual(jv.get("accounts")[0].get("party_type"), "Customer") | ||||||
| 		self.assertEqual(jv.get("accounts")[0].get("party"), "_Test Customer") | 		self.assertEqual(jv.get("accounts")[0].get("party"), "_Test Customer") | ||||||
| 		self.assertTrue(jv.get("accounts")[0].get("against_invoice")) | 		self.assertTrue(jv.get("accounts")[0].get("against_invoice")) | ||||||
| 		self.assertEqual(jv.get("accounts")[1].get("account"), "Sales - _TC") | 		self.assertEqual(jv.get("accounts")[1].get("account"), "Sales - _TC") | ||||||
| 
 | 
 | ||||||
| 	def test_make_return_jv_for_sales_invoice_non_packing_item(self): | 	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) | 		se = self._test_sales_invoice_return("_Test Item", 5, 2) | ||||||
| 		self._test_sales_return_jv(se) | 		self._test_sales_return_jv(se) | ||||||
| 
 | 
 | ||||||
| 	def test_make_return_jv_for_sales_invoice_packing_item(self): | 	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) | 		se = self._test_sales_invoice_return("_Test Sales BOM Item", 25, 20) | ||||||
| 		self._test_sales_return_jv(se) | 		self._test_sales_return_jv(se) | ||||||
| 
 | 
 | ||||||
| 	def test_make_return_jv_for_delivery_note_non_packing_item(self): | 	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) | 		se = self._test_delivery_note_return("_Test Item", 5, 2) | ||||||
| 		self._test_sales_return_jv(se) | 		self._test_sales_return_jv(se) | ||||||
| 
 | 
 | ||||||
| @ -463,7 +395,6 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 		self._test_sales_return_jv(se) | 		self._test_sales_return_jv(se) | ||||||
| 
 | 
 | ||||||
| 	def test_make_return_jv_for_delivery_note_packing_item(self): | 	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) | 		se = self._test_delivery_note_return("_Test Sales BOM Item", 25, 20) | ||||||
| 		self._test_sales_return_jv(se) | 		self._test_sales_return_jv(se) | ||||||
| 
 | 
 | ||||||
| @ -471,69 +402,37 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 		self._test_sales_return_jv(se) | 		self._test_sales_return_jv(se) | ||||||
| 
 | 
 | ||||||
| 	def _test_delivery_note_return_against_sales_order(self, item_code, delivered_qty, returned_qty): | 	def _test_delivery_note_return_against_sales_order(self, item_code, delivered_qty, returned_qty): | ||||||
| 		self._insert_material_receipt() | 		from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice | ||||||
| 		 | 		 | ||||||
| 		from erpnext.selling.doctype.sales_order.test_sales_order import test_records as sales_order_test_records | 		actual_qty_0 = get_qty_after_transaction() | ||||||
| 		from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice, make_delivery_note |  | ||||||
| 		 | 		 | ||||||
| 		actual_qty_0 = self._get_actual_qty() | 		so = make_sales_order(qty=50) | ||||||
| 
 | 
 | ||||||
| 		so = frappe.copy_doc(sales_order_test_records[0]) | 		dn = create_dn_against_so(so.name, delivered_qty) | ||||||
| 		so.get("items")[0].item_code = item_code |  | ||||||
| 		so.get("items")[0].qty = 5.0 |  | ||||||
| 		so.insert() |  | ||||||
| 		so.submit() |  | ||||||
| 		 | 		 | ||||||
| 		dn = make_delivery_note(so.name) | 		actual_qty_1 = get_qty_after_transaction() | ||||||
| 		dn.status = "Draft" |  | ||||||
| 		dn.posting_date = so.delivery_date |  | ||||||
| 		dn.insert() |  | ||||||
| 		dn.submit() |  | ||||||
| 
 |  | ||||||
| 		actual_qty_1 = self._get_actual_qty() |  | ||||||
| 		self.assertEquals(actual_qty_0 - delivered_qty, actual_qty_1) | 		self.assertEquals(actual_qty_0 - delivered_qty, actual_qty_1) | ||||||
| 
 | 
 | ||||||
| 		si = make_sales_invoice(so.name) | 		si = make_sales_invoice(so.name) | ||||||
| 		si.posting_date = dn.posting_date |  | ||||||
| 		si.debit_to = "_Test Receivable - _TC" |  | ||||||
| 		for d in si.get("items"): |  | ||||||
| 			d.income_account = "Sales - _TC" |  | ||||||
| 			d.cost_center = "_Test Cost Center - _TC" |  | ||||||
| 		si.insert() | 		si.insert() | ||||||
| 		si.submit() | 		si.submit() | ||||||
| 
 | 
 | ||||||
| 		# insert and submit stock entry for sales return | 		# insert and submit stock entry for sales return | ||||||
| 		se = frappe.copy_doc(test_records[0]) | 		se = make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC",  | ||||||
| 		se.purpose = "Sales Return" | 			qty=returned_qty, purpose="Sales Return", delivery_note_no=dn.name) | ||||||
| 		se.delivery_note_no = dn.name |  | ||||||
| 		se.posting_date = "2013-03-10" |  | ||||||
| 		se.fiscal_year = "_Test Fiscal Year 2013" |  | ||||||
| 		se.get("items")[0].qty = se.get("items")[0].transfer_qty = returned_qty |  | ||||||
| 
 | 
 | ||||||
| 		se.insert() | 		actual_qty_2 = get_qty_after_transaction() | ||||||
| 		se.submit() |  | ||||||
| 
 |  | ||||||
| 		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 | 		return se | ||||||
| 
 | 
 | ||||||
| 	def test_purchase_receipt_return(self): | 	def test_purchase_receipt_return(self): | ||||||
| 		self._clear_stock_account_balance() | 		actual_qty_0 = get_qty_after_transaction() | ||||||
| 
 |  | ||||||
| 		actual_qty_0 = self._get_actual_qty() |  | ||||||
| 
 |  | ||||||
| 		from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt \ |  | ||||||
| 			import test_records as purchase_receipt_test_records |  | ||||||
| 
 |  | ||||||
| 		from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchase_invoice |  | ||||||
| 
 | 
 | ||||||
| 		# submit purchase receipt | 		# submit purchase receipt | ||||||
| 		pr = frappe.copy_doc(purchase_receipt_test_records[0]) | 		pr = make_purchase_receipt(item_code="_Test Item", warehouse="_Test Warehouse - _TC", qty=5) | ||||||
| 		pr.insert() |  | ||||||
| 		pr.submit() |  | ||||||
| 
 | 
 | ||||||
| 		actual_qty_1 = self._get_actual_qty() | 		actual_qty_1 = get_qty_after_transaction() | ||||||
| 
 | 
 | ||||||
| 		self.assertEquals(actual_qty_0 + 5, actual_qty_1) | 		self.assertEquals(actual_qty_0 + 5, actual_qty_1) | ||||||
| 
 | 
 | ||||||
| @ -549,52 +448,31 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 		for d in pi.get("taxes"): | 		for d in pi.get("taxes"): | ||||||
| 			d.cost_center = "_Test Cost Center - _TC" | 			d.cost_center = "_Test Cost Center - _TC" | ||||||
| 
 | 
 | ||||||
| 		pi.run_method("calculate_taxes_and_totals") |  | ||||||
| 		pi.bill_no = "NA" |  | ||||||
| 		pi.insert() | 		pi.insert() | ||||||
| 		pi.submit() | 		pi.submit() | ||||||
| 
 | 
 | ||||||
| 		# submit purchase return | 		# submit purchase return | ||||||
| 		se = frappe.copy_doc(test_records[0]) | 		se = make_stock_entry(item_code="_Test Item", source="_Test Warehouse - _TC",  | ||||||
| 		se.purpose = "Purchase Return" | 			qty=5, purpose="Purchase Return", purchase_receipt_no=pr.name) | ||||||
| 		se.purchase_receipt_no = pr.name |  | ||||||
| 		se.posting_date = "2013-03-01" |  | ||||||
| 		se.fiscal_year = "_Test Fiscal Year 2013" |  | ||||||
| 		se.difference_account = "_Test Account Stock Adjustment - _TC" |  | ||||||
| 		se.get("items")[0].qty = se.get("items")[0].transfer_qty = 5 |  | ||||||
| 		se.get("items")[0].s_warehouse = "_Test Warehouse - _TC" |  | ||||||
| 		se.insert() |  | ||||||
| 		se.submit() |  | ||||||
| 
 | 
 | ||||||
| 		actual_qty_2 = self._get_actual_qty() | 		actual_qty_2 = get_qty_after_transaction() | ||||||
| 
 | 
 | ||||||
| 		self.assertEquals(actual_qty_1 - 5, actual_qty_2) | 		self.assertEquals(actual_qty_1 - 5, actual_qty_2) | ||||||
| 
 | 
 | ||||||
| 		frappe.db.set_default("company", self.old_default_company) |  | ||||||
| 
 |  | ||||||
| 		return se, pr.name | 		return se, pr.name | ||||||
| 
 | 
 | ||||||
| 	def test_over_stock_return(self): | 	def test_over_stock_return(self): | ||||||
| 		from erpnext.stock.doctype.stock_entry.stock_entry import StockOverReturnError | 		from erpnext.stock.doctype.stock_entry.stock_entry import StockOverReturnError | ||||||
| 		self._clear_stock_account_balance() |  | ||||||
| 
 | 
 | ||||||
| 		# out of 10, 5 gets returned | 		# out of 10, 5 gets returned | ||||||
| 		prev_se, 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 | 		se = make_stock_entry(item_code="_Test Item", source="_Test Warehouse - _TC",  | ||||||
| 		se = frappe.copy_doc(test_records[0]) | 			qty=6, purpose="Purchase Return", purchase_receipt_no=pr_docname, do_not_save=True) | ||||||
| 		se.purpose = "Purchase Return" |  | ||||||
| 		se.purchase_receipt_no = pr_docname |  | ||||||
| 		se.difference_account = "_Test Account Stock Adjustment - _TC" |  | ||||||
| 		se.posting_date = "2013-03-01" |  | ||||||
| 		se.fiscal_year = "_Test Fiscal Year 2013" |  | ||||||
| 		se.get("items")[0].qty = se.get("items")[0].transfer_qty = 6 |  | ||||||
| 		se.get("items")[0].s_warehouse = "_Test Warehouse - _TC" |  | ||||||
| 		 | 		 | ||||||
| 		self.assertRaises(StockOverReturnError, se.insert) | 		self.assertRaises(StockOverReturnError, se.insert) | ||||||
| 
 | 
 | ||||||
| 	def _test_purchase_return_jv(self, se): | 	def _test_purchase_return_jv(self, se): | ||||||
| 		from erpnext.stock.doctype.stock_entry.stock_entry import make_return_jv |  | ||||||
| 		jv = make_return_jv(se.name) | 		jv = make_return_jv(se.name) | ||||||
| 
 | 
 | ||||||
| 		self.assertEqual(len(jv.get("accounts")), 2) | 		self.assertEqual(len(jv.get("accounts")), 2) | ||||||
| @ -606,7 +484,6 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 		self.assertTrue(jv.get("accounts")[0].get("against_voucher")) | 		self.assertTrue(jv.get("accounts")[0].get("against_voucher")) | ||||||
| 
 | 
 | ||||||
| 	def test_make_return_jv_for_purchase_receipt(self): | 	def test_make_return_jv_for_purchase_receipt(self): | ||||||
| 		self._clear_stock_account_balance() |  | ||||||
| 		se, pr_name = self.test_purchase_receipt_return() | 		se, pr_name = self.test_purchase_receipt_return() | ||||||
| 		self._test_purchase_return_jv(se) | 		self._test_purchase_return_jv(se) | ||||||
| 
 | 
 | ||||||
| @ -614,9 +491,8 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 		self._test_purchase_return_jv(se) | 		self._test_purchase_return_jv(se) | ||||||
| 
 | 
 | ||||||
| 	def _test_purchase_return_return_against_purchase_order(self): | 	def _test_purchase_return_return_against_purchase_order(self): | ||||||
| 		self._clear_stock_account_balance() |  | ||||||
| 
 | 
 | ||||||
| 		actual_qty_0 = self._get_actual_qty() | 		actual_qty_0 = get_qty_after_transaction() | ||||||
| 
 | 
 | ||||||
| 		from erpnext.buying.doctype.purchase_order.test_purchase_order \ | 		from erpnext.buying.doctype.purchase_order.test_purchase_order \ | ||||||
| 			import test_records as purchase_order_test_records | 			import test_records as purchase_order_test_records | ||||||
| @ -626,6 +502,7 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 
 | 
 | ||||||
| 		# submit purchase receipt | 		# submit purchase receipt | ||||||
| 		po = frappe.copy_doc(purchase_order_test_records[0]) | 		po = frappe.copy_doc(purchase_order_test_records[0]) | ||||||
|  | 		po.transaction_date = nowdate() | ||||||
| 		po.is_subcontracted = None | 		po.is_subcontracted = None | ||||||
| 		po.get("items")[0].item_code = "_Test Item" | 		po.get("items")[0].item_code = "_Test Item" | ||||||
| 		po.get("items")[0].rate = 50 | 		po.get("items")[0].rate = 50 | ||||||
| @ -639,7 +516,7 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 		pr.insert() | 		pr.insert() | ||||||
| 		pr.submit() | 		pr.submit() | ||||||
| 
 | 
 | ||||||
| 		actual_qty_1 = self._get_actual_qty() | 		actual_qty_1 = get_qty_after_transaction() | ||||||
| 
 | 
 | ||||||
| 		self.assertEquals(actual_qty_0 + 10, actual_qty_1) | 		self.assertEquals(actual_qty_0 + 10, actual_qty_1) | ||||||
| 
 | 
 | ||||||
| @ -660,33 +537,15 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 		pi.submit() | 		pi.submit() | ||||||
| 
 | 
 | ||||||
| 		# submit purchase return | 		# submit purchase return | ||||||
| 		se = frappe.copy_doc(test_records[0]) | 		se = make_stock_entry(item_code="_Test Item", source="_Test Warehouse - _TC",  | ||||||
| 		se.purpose = "Purchase Return" | 			qty=5, purpose="Purchase Return", purchase_receipt_no=pr.name) | ||||||
| 		se.purchase_receipt_no = pr.name |  | ||||||
| 		se.difference_account = "_Test Account Stock Adjustment - _TC" |  | ||||||
| 		se.posting_date = "2013-03-01" |  | ||||||
| 		se.fiscal_year = "_Test Fiscal Year 2013" |  | ||||||
| 		se.get("items")[0].qty = se.get("items")[0].transfer_qty = 5 |  | ||||||
| 		se.get("items")[0].s_warehouse = "_Test Warehouse - _TC" |  | ||||||
| 		se.insert() |  | ||||||
| 		se.submit() |  | ||||||
| 
 | 
 | ||||||
| 		actual_qty_2 = self._get_actual_qty() | 		actual_qty_2 = get_qty_after_transaction() | ||||||
| 
 | 
 | ||||||
| 		self.assertEquals(actual_qty_1 - 5, actual_qty_2) | 		self.assertEquals(actual_qty_1 - 5, actual_qty_2) | ||||||
| 
 | 
 | ||||||
| 		frappe.db.set_default("company", self.old_default_company) |  | ||||||
| 
 |  | ||||||
| 		return se, pr.name | 		return se, pr.name | ||||||
| 
 | 
 | ||||||
| 	def _clear_stock_account_balance(self): |  | ||||||
| 		frappe.db.sql("delete from `tabStock Ledger Entry`") |  | ||||||
| 		frappe.db.sql("""delete from `tabBin`""") |  | ||||||
| 		frappe.db.sql("""delete from `tabGL Entry`""") |  | ||||||
| 
 |  | ||||||
| 		self.old_default_company = frappe.db.get_default("company") |  | ||||||
| 		frappe.db.set_default("company", "_Test Company") |  | ||||||
| 
 |  | ||||||
| 	def test_serial_no_not_reqd(self): | 	def test_serial_no_not_reqd(self): | ||||||
| 		se = frappe.copy_doc(test_records[0]) | 		se = frappe.copy_doc(test_records[0]) | ||||||
| 		se.get("items")[0].serial_no = "ABCD" | 		se.get("items")[0].serial_no = "ABCD" | ||||||
| @ -720,7 +579,6 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 		self.assertRaises(SerialNoQtyError, se.submit) | 		self.assertRaises(SerialNoQtyError, se.submit) | ||||||
| 
 | 
 | ||||||
| 	def test_serial_no_transfer_in(self): | 	def test_serial_no_transfer_in(self): | ||||||
| 		self._clear_stock_account_balance() |  | ||||||
| 		se = frappe.copy_doc(test_records[0]) | 		se = frappe.copy_doc(test_records[0]) | ||||||
| 		se.get("items")[0].item_code = "_Test Serialized Item" | 		se.get("items")[0].item_code = "_Test Serialized Item" | ||||||
| 		se.get("items")[0].qty = 2 | 		se.get("items")[0].qty = 2 | ||||||
| @ -736,7 +594,6 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 		self.assertFalse(frappe.db.get_value("Serial No", "ABCD", "warehouse")) | 		self.assertFalse(frappe.db.get_value("Serial No", "ABCD", "warehouse")) | ||||||
| 
 | 
 | ||||||
| 	def test_serial_no_not_exists(self): | 	def test_serial_no_not_exists(self): | ||||||
| 		self._clear_stock_account_balance() |  | ||||||
| 		frappe.db.sql("delete from `tabSerial No` where name in ('ABCD', 'EFGH')") | 		frappe.db.sql("delete from `tabSerial No` where name in ('ABCD', 'EFGH')") | ||||||
| 		make_serialized_item(target_warehouse="_Test Warehouse 1 - _TC") | 		make_serialized_item(target_warehouse="_Test Warehouse 1 - _TC") | ||||||
| 		se = frappe.copy_doc(test_records[0]) | 		se = frappe.copy_doc(test_records[0]) | ||||||
| @ -752,7 +609,6 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 		self.assertRaises(SerialNoNotExistsError, se.submit) | 		self.assertRaises(SerialNoNotExistsError, se.submit) | ||||||
| 
 | 
 | ||||||
| 	def test_serial_duplicate(self): | 	def test_serial_duplicate(self): | ||||||
| 		self._clear_stock_account_balance() |  | ||||||
| 		se, serial_nos = self.test_serial_by_series() | 		se, serial_nos = self.test_serial_by_series() | ||||||
| 
 | 
 | ||||||
| 		se = frappe.copy_doc(test_records[0]) | 		se = frappe.copy_doc(test_records[0]) | ||||||
| @ -764,7 +620,6 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 		self.assertRaises(SerialNoDuplicateError, se.submit) | 		self.assertRaises(SerialNoDuplicateError, se.submit) | ||||||
| 
 | 
 | ||||||
| 	def test_serial_by_series(self): | 	def test_serial_by_series(self): | ||||||
| 		self._clear_stock_account_balance() |  | ||||||
| 		se = make_serialized_item() | 		se = make_serialized_item() | ||||||
| 
 | 
 | ||||||
| 		serial_nos = get_serial_nos(se.get("items")[0].serial_no) | 		serial_nos = get_serial_nos(se.get("items")[0].serial_no) | ||||||
| @ -790,7 +645,6 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 		self.assertRaises(SerialNoItemError, se.submit) | 		self.assertRaises(SerialNoItemError, se.submit) | ||||||
| 
 | 
 | ||||||
| 	def test_serial_move(self): | 	def test_serial_move(self): | ||||||
| 		self._clear_stock_account_balance() |  | ||||||
| 		se = make_serialized_item() | 		se = make_serialized_item() | ||||||
| 		serial_no = get_serial_nos(se.get("items")[0].serial_no)[0] | 		serial_no = get_serial_nos(se.get("items")[0].serial_no)[0] | ||||||
| 
 | 
 | ||||||
| @ -810,7 +664,6 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 		self.assertTrue(frappe.db.get_value("Serial No", serial_no, "warehouse"), "_Test Warehouse - _TC") | 		self.assertTrue(frappe.db.get_value("Serial No", serial_no, "warehouse"), "_Test Warehouse - _TC") | ||||||
| 
 | 
 | ||||||
| 	def test_serial_warehouse_error(self): | 	def test_serial_warehouse_error(self): | ||||||
| 		self._clear_stock_account_balance() |  | ||||||
| 		make_serialized_item(target_warehouse="_Test Warehouse 1 - _TC") | 		make_serialized_item(target_warehouse="_Test Warehouse 1 - _TC") | ||||||
| 
 | 
 | ||||||
| 		t = make_serialized_item() | 		t = make_serialized_item() | ||||||
| @ -828,7 +681,6 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 		self.assertRaises(SerialNoWarehouseError, se.submit) | 		self.assertRaises(SerialNoWarehouseError, se.submit) | ||||||
| 
 | 
 | ||||||
| 	def test_serial_cancel(self): | 	def test_serial_cancel(self): | ||||||
| 		self._clear_stock_account_balance() |  | ||||||
| 		se, serial_nos = self.test_serial_by_series() | 		se, serial_nos = self.test_serial_by_series() | ||||||
| 		se.cancel() | 		se.cancel() | ||||||
| 
 | 
 | ||||||
| @ -837,7 +689,6 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 
 | 
 | ||||||
| 	def test_warehouse_company_validation(self): | 	def test_warehouse_company_validation(self): | ||||||
| 		set_perpetual_inventory(0) | 		set_perpetual_inventory(0) | ||||||
| 		self._clear_stock_account_balance() |  | ||||||
| 		frappe.get_doc("User", "test2@example.com")\ | 		frappe.get_doc("User", "test2@example.com")\ | ||||||
| 			.add_roles("Sales User", "Sales Manager", "Material User", "Material Manager") | 			.add_roles("Sales User", "Sales Manager", "Material User", "Material Manager") | ||||||
| 		frappe.set_user("test2@example.com") | 		frappe.set_user("test2@example.com") | ||||||
| @ -880,25 +731,26 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 			"test2@example.com", parenttype="User Permission") | 			"test2@example.com", parenttype="User Permission") | ||||||
| 
 | 
 | ||||||
| 	def test_freeze_stocks(self): | 	def test_freeze_stocks(self): | ||||||
| 		self._clear_stock_account_balance() |  | ||||||
| 		frappe.db.set_value('Stock Settings', None,'stock_auth_role', '') | 		frappe.db.set_value('Stock Settings', None,'stock_auth_role', '') | ||||||
| 
 | 
 | ||||||
| 		# test freeze_stocks_upto | 		# test freeze_stocks_upto | ||||||
| 		date_newer_than_test_records = add_days(getdate(test_records[0]['posting_date']), 5) | 		frappe.db.set_value("Stock Settings", None, "stock_frozen_upto", add_days(nowdate(), 5)) | ||||||
| 		frappe.db.set_value("Stock Settings", None, "stock_frozen_upto", date_newer_than_test_records) |  | ||||||
| 		se = frappe.copy_doc(test_records[0]).insert() | 		se = frappe.copy_doc(test_records[0]).insert() | ||||||
| 		self.assertRaises (StockFreezeError, se.submit) | 		self.assertRaises(StockFreezeError, se.submit) | ||||||
|  | 
 | ||||||
| 		frappe.db.set_value("Stock Settings", None, "stock_frozen_upto", '') | 		frappe.db.set_value("Stock Settings", None, "stock_frozen_upto", '') | ||||||
| 
 | 
 | ||||||
| 		# test freeze_stocks_upto_days | 		# test freeze_stocks_upto_days | ||||||
| 		frappe.db.set_value("Stock Settings", None, "stock_frozen_upto_days", 7) | 		frappe.db.set_value("Stock Settings", None, "stock_frozen_upto_days", 7) | ||||||
| 		se = frappe.copy_doc(test_records[0]).insert() | 		se = frappe.copy_doc(test_records[0]) | ||||||
| 		self.assertRaises (StockFreezeError, se.submit) | 		se.posting_date = add_days(nowdate(), -15) | ||||||
|  | 		se.insert() | ||||||
|  | 		self.assertRaises(StockFreezeError, se.submit) | ||||||
| 		frappe.db.set_value("Stock Settings", None, "stock_frozen_upto_days", 0) | 		frappe.db.set_value("Stock Settings", None, "stock_frozen_upto_days", 0) | ||||||
| 
 | 
 | ||||||
| 	def test_production_order(self): | 	def test_production_order(self): | ||||||
| 		bom_no = frappe.db.get_value("BOM", {"item": "_Test FG Item 2", | 		bom_no, bom_operation_cost = frappe.db.get_value("BOM", {"item": "_Test FG Item 2", | ||||||
| 			"is_default": 1, "docstatus": 1}) | 			"is_default": 1, "docstatus": 1}, ["name", "operating_cost"]) | ||||||
| 
 | 
 | ||||||
| 		production_order = frappe.new_doc("Production Order") | 		production_order = frappe.new_doc("Production Order") | ||||||
| 		production_order.update({ | 		production_order.update({ | ||||||
| @ -907,13 +759,13 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 			"production_item": "_Test FG Item 2", | 			"production_item": "_Test FG Item 2", | ||||||
| 			"bom_no": bom_no, | 			"bom_no": bom_no, | ||||||
| 			"qty": 1.0, | 			"qty": 1.0, | ||||||
| 			"stock_uom": "Nos", | 			"stock_uom": "_Test UOM", | ||||||
| 			"wip_warehouse": "_Test Warehouse - _TC" | 			"wip_warehouse": "_Test Warehouse - _TC" | ||||||
| 		}) | 		}) | ||||||
| 		production_order.insert() | 		production_order.insert() | ||||||
| 		production_order.submit() | 		production_order.submit() | ||||||
| 
 | 
 | ||||||
| 		self._insert_material_receipt() | 		make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, incoming_rate=100) | ||||||
| 
 | 
 | ||||||
| 		stock_entry = frappe.new_doc("Stock Entry") | 		stock_entry = frappe.new_doc("Stock Entry") | ||||||
| 		stock_entry.update({ | 		stock_entry.update({ | ||||||
| @ -925,10 +777,15 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 		}) | 		}) | ||||||
| 		stock_entry.get_items() | 		stock_entry.get_items() | ||||||
| 
 | 
 | ||||||
| 		fg_rate = [d.amount for d in stock_entry.get("items") if d.item_code=="_Test FG Item 2"][0] | 		rm_cost = 0 | ||||||
| 		self.assertEqual(fg_rate, 1200.00) | 		for d in stock_entry.get("items"): | ||||||
| 		fg_rate = [d.amount for d in stock_entry.get("items") if d.item_code=="_Test Item"][0] | 			if d.s_warehouse: | ||||||
| 		self.assertEqual(fg_rate, 100.00) | 				rm_cost += flt(d.amount) | ||||||
|  | 								 | ||||||
|  | 		fg_cost = filter(lambda x: x.item_code=="_Test FG Item 2", stock_entry.get("items"))[0].amount | ||||||
|  | 		 | ||||||
|  | 		self.assertEqual(fg_cost, rm_cost + bom_operation_cost + stock_entry.additional_operating_cost) | ||||||
|  | 		 | ||||||
| 
 | 
 | ||||||
| 	def test_variant_production_order(self): | 	def test_variant_production_order(self): | ||||||
| 		bom_no = frappe.db.get_value("BOM", {"item": "_Test Variant Item", | 		bom_no = frappe.db.get_value("BOM", {"item": "_Test Variant Item", | ||||||
| @ -941,7 +798,7 @@ class TestStockEntry(unittest.TestCase): | |||||||
| 			"production_item": "_Test Variant Item-S", | 			"production_item": "_Test Variant Item-S", | ||||||
| 			"bom_no": bom_no, | 			"bom_no": bom_no, | ||||||
| 			"qty": 1.0, | 			"qty": 1.0, | ||||||
| 			"stock_uom": "Nos", | 			"stock_uom": "_Test UOM", | ||||||
| 			"wip_warehouse": "_Test Warehouse - _TC" | 			"wip_warehouse": "_Test Warehouse - _TC" | ||||||
| 		}) | 		}) | ||||||
| 		production_order.insert() | 		production_order.insert() | ||||||
| @ -968,12 +825,15 @@ def make_serialized_item(item_code=None, serial_no=None, target_warehouse=None): | |||||||
| 	return se | 	return se | ||||||
| 
 | 
 | ||||||
| def make_stock_entry(**args): | def make_stock_entry(**args): | ||||||
|  | 	from erpnext.accounts.utils import get_fiscal_year | ||||||
|  | 	 | ||||||
| 	s = frappe.new_doc("Stock Entry") | 	s = frappe.new_doc("Stock Entry") | ||||||
| 	args = frappe._dict(args) | 	args = frappe._dict(args) | ||||||
| 	if args.posting_date: | 	if args.posting_date: | ||||||
| 		s.posting_date = args.posting_date | 		s.posting_date = args.posting_date | ||||||
| 	if args.posting_time: | 	if args.posting_time: | ||||||
| 		s.posting_time = args.posting_time | 		s.posting_time = args.posting_time | ||||||
|  | 	 | ||||||
| 	if not args.purpose: | 	if not args.purpose: | ||||||
| 		if args.source and args.target: | 		if args.source and args.target: | ||||||
| 			s.purpose = "Material Transfer" | 			s.purpose = "Material Transfer" | ||||||
| @ -981,19 +841,43 @@ def make_stock_entry(**args): | |||||||
| 			s.purpose = "Material Issue" | 			s.purpose = "Material Issue" | ||||||
| 		else: | 		else: | ||||||
| 			s.purpose = "Material Receipt" | 			s.purpose = "Material Receipt" | ||||||
|  | 	else: | ||||||
|  | 		s.purpose = args.purpose | ||||||
|  | 		 | ||||||
| 	s.company = args.company or "_Test Company" | 	s.company = args.company or "_Test Company" | ||||||
|  | 	s.fiscal_year = get_fiscal_year(s.posting_date)[0] | ||||||
|  | 	s.purchase_receipt_no = args.purchase_receipt_no | ||||||
|  | 	s.delivery_note_no = args.delivery_note_no | ||||||
|  | 	s.sales_invoice_no = args.sales_invoice_no | ||||||
|  | 	s.difference_account = args.difference_account or "Stock Adjustment - _TC" | ||||||
|  | 	 | ||||||
| 	s.append("items", { | 	s.append("items", { | ||||||
| 		"item_code": args.item or args.item_code, | 		"item_code": args.item or args.item_code or "_Test Item", | ||||||
| 		"s_warehouse": args.from_warehouse or args.source, | 		"s_warehouse": args.from_warehouse or args.source, | ||||||
| 		"t_warehouse": args.to_warehouse or args.target, | 		"t_warehouse": args.to_warehouse or args.target, | ||||||
| 		"qty": args.qty, | 		"qty": args.qty, | ||||||
| 		"incoming_rate": args.incoming_rate, | 		"incoming_rate": args.incoming_rate, | ||||||
| 		"conversion_factor": 1.0 | 		"expense_account": args.expense_account or "Stock Adjustment - _TC", | ||||||
|  | 		"conversion_factor": 1.0, | ||||||
|  | 		"cost_center": "_Test Cost Center - _TC" | ||||||
| 	}) | 	}) | ||||||
| 	s.posting_date= "2013-01-01" | 	 | ||||||
| 	s.fiscal_year= "_Test Fiscal Year 2013" | 	if not args.do_not_save: | ||||||
| 		s.insert() | 		s.insert() | ||||||
|  | 		if not args.do_not_submit: | ||||||
| 			s.submit() | 			s.submit() | ||||||
| 	return s | 	return s | ||||||
| 	 | 	 | ||||||
|  | def get_qty_after_transaction(**args): | ||||||
|  | 	args = frappe._dict(args) | ||||||
|  | 	 | ||||||
|  | 	last_sle = get_previous_sle({ | ||||||
|  | 		"item_code": args.item_code or "_Test Item", | ||||||
|  | 		"warehouse": args.warehouse or "_Test Warehouse - _TC", | ||||||
|  | 		"posting_date": args.posting_date or nowdate(), | ||||||
|  | 		"posting_time": args.posting_time or nowtime() | ||||||
|  | 	}) | ||||||
|  | 	 | ||||||
|  | 	return flt(last_sle.get("qty_after_transaction")) | ||||||
|  | 
 | ||||||
| test_records = frappe.get_test_records('Stock Entry') | test_records = frappe.get_test_records('Stock Entry') | ||||||
|  | |||||||
| @ -6,274 +6,114 @@ | |||||||
| 
 | 
 | ||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
| import frappe, unittest | import frappe, unittest | ||||||
| from frappe.utils import flt | from frappe.utils import flt, nowdate, nowtime | ||||||
| import json |  | ||||||
| from erpnext.accounts.utils import get_fiscal_year, get_stock_and_account_difference | from erpnext.accounts.utils import get_fiscal_year, get_stock_and_account_difference | ||||||
| 
 | from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory | ||||||
|  | from erpnext.stock.stock_ledger import get_previous_sle, update_entries_after | ||||||
| 
 | 
 | ||||||
| class TestStockReconciliation(unittest.TestCase): | class TestStockReconciliation(unittest.TestCase): | ||||||
| 	def setUp(self): | 	def setUp(self): | ||||||
| 		frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1) | 		frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1) | ||||||
|  | 		self.insert_existing_sle() | ||||||
| 
 | 
 | ||||||
| 	def test_reco_for_fifo(self): | 	def test_reco_for_fifo(self): | ||||||
| 		frappe.defaults.set_global_default("auto_accounting_for_stock", 0) | 		self._test_reco_sle_gle("FIFO") | ||||||
| 		# [[qty, valuation_rate, posting_date, |  | ||||||
| 		#		posting_time, expected_stock_value, bin_qty, bin_valuation]] |  | ||||||
| 		input_data = [ |  | ||||||
| 			[50, 1000, "2012-12-26", "12:00", 50000, 45, 48000], |  | ||||||
| 			[5, 1000, "2012-12-26", "12:00", 5000, 0, 0], |  | ||||||
| 			[15, 1000, "2012-12-26", "12:00", 15000, 10, 12000], |  | ||||||
| 			[25, 900, "2012-12-26", "12:00", 22500, 20, 22500], |  | ||||||
| 			[20, 500, "2012-12-26", "12:00", 10000, 15, 18000], |  | ||||||
| 			[50, 1000, "2013-01-01", "12:00", 50000, 65, 68000], |  | ||||||
| 			[5, 1000, "2013-01-01", "12:00", 5000, 20, 23000], |  | ||||||
| 			["", 1000, "2012-12-26", "12:05", 15000, 10, 12000], |  | ||||||
| 			[20, "", "2012-12-26", "12:05", 16000, 15, 18000], |  | ||||||
| 			[10, 2000, "2012-12-26", "12:10", 20000, 5, 6000], |  | ||||||
| 			[1, 1000, "2012-12-01", "00:00", 1000, 11, 13200], |  | ||||||
| 			[0, "", "2012-12-26", "12:10", 0, -5, -6000] |  | ||||||
| 		] |  | ||||||
| 
 |  | ||||||
| 		for d in input_data: |  | ||||||
| 			self.cleanup_data() |  | ||||||
| 			self.insert_existing_sle("FIFO") |  | ||||||
| 			stock_reco = self.submit_stock_reconciliation(d[0], d[1], d[2], d[3]) |  | ||||||
| 
 |  | ||||||
| 			# check stock value |  | ||||||
| 			res = frappe.db.sql("""select stock_value from `tabStock Ledger Entry` |  | ||||||
| 				where item_code = '_Test Item' and warehouse = '_Test Warehouse - _TC' |  | ||||||
| 				and posting_date = %s and posting_time = %s order by name desc limit 1""", |  | ||||||
| 				(d[2], d[3])) |  | ||||||
| 			self.assertEqual(res and flt(res[0][0]) or 0, d[4]) |  | ||||||
| 
 |  | ||||||
| 			# check bin qty and stock value |  | ||||||
| 			bin = frappe.db.sql("""select actual_qty, stock_value from `tabBin` |  | ||||||
| 				where item_code = '_Test Item' and warehouse = '_Test Warehouse - _TC'""") |  | ||||||
| 
 |  | ||||||
| 			self.assertEqual(bin and [flt(bin[0][0]), flt(bin[0][1])] or [], [d[5], d[6]]) |  | ||||||
| 
 |  | ||||||
| 			# no gl entries |  | ||||||
| 			gl_entries = frappe.db.sql("""select name from `tabGL Entry` |  | ||||||
| 				where voucher_type = 'Stock Reconciliation' and voucher_no = %s""", |  | ||||||
| 				 stock_reco.name) |  | ||||||
| 			self.assertFalse(gl_entries) |  | ||||||
| 
 |  | ||||||
| 		 | 		 | ||||||
| 	def test_reco_for_moving_average(self): | 	def test_reco_for_moving_average(self): | ||||||
| 		frappe.defaults.set_global_default("auto_accounting_for_stock", 0) | 		self._test_reco_sle_gle("Moving Average") | ||||||
|  | 		 | ||||||
|  | 	def _test_reco_sle_gle(self, valuation_method): | ||||||
|  | 		set_perpetual_inventory() | ||||||
| 		# [[qty, valuation_rate, posting_date, | 		# [[qty, valuation_rate, posting_date, | ||||||
| 		#		posting_time, expected_stock_value, bin_qty, bin_valuation]] | 		#		posting_time, expected_stock_value, bin_qty, bin_valuation]] | ||||||
| 		input_data = [ |  | ||||||
| 			[50, 1000, "2012-12-26", "12:00", 50000, 45, 48000], |  | ||||||
| 			[5, 1000, "2012-12-26", "12:00", 5000, 0, 0], |  | ||||||
| 			[15, 1000, "2012-12-26", "12:00", 15000, 10, 11500], |  | ||||||
| 			[25, 900, "2012-12-26", "12:00", 22500, 20, 22500], |  | ||||||
| 			[20, 500, "2012-12-26", "12:00", 10000, 15, 18000], |  | ||||||
| 			[50, 1000, "2013-01-01", "12:00", 50000, 65, 68000], |  | ||||||
| 			[5, 1000, "2013-01-01", "12:00", 5000, 20, 23000], |  | ||||||
| 			["", 1000, "2012-12-26", "12:05", 15000, 10, 11500], |  | ||||||
| 			[20, "", "2012-12-26", "12:05", 18000, 15, 18000], |  | ||||||
| 			[10, 2000, "2012-12-26", "12:10", 20000, 5, 7600], |  | ||||||
| 			[1, 1000, "2012-12-01", "00:00", 1000, 11, 12512.73], |  | ||||||
| 			[0, "", "2012-12-26", "12:10", 0, -5, -5142.86] |  | ||||||
| 
 |  | ||||||
| 		] |  | ||||||
| 
 |  | ||||||
| 		for d in input_data: |  | ||||||
| 			self.cleanup_data() |  | ||||||
| 			self.insert_existing_sle("Moving Average") |  | ||||||
| 			stock_reco = self.submit_stock_reconciliation(d[0], d[1], d[2], d[3]) |  | ||||||
| 
 |  | ||||||
| 			# check stock value in sle |  | ||||||
| 			res = frappe.db.sql("""select stock_value from `tabStock Ledger Entry` |  | ||||||
| 				where item_code = '_Test Item' and warehouse = '_Test Warehouse - _TC' |  | ||||||
| 				and posting_date = %s and posting_time = %s order by name desc limit 1""", |  | ||||||
| 				(d[2], d[3])) |  | ||||||
| 
 |  | ||||||
| 			self.assertEqual(res and flt(res[0][0], 4) or 0, d[4]) |  | ||||||
| 
 |  | ||||||
| 			# bin qty and stock value |  | ||||||
| 			bin = frappe.db.sql("""select actual_qty, stock_value from `tabBin` |  | ||||||
| 				where item_code = '_Test Item' and warehouse = '_Test Warehouse - _TC'""") |  | ||||||
| 
 |  | ||||||
| 			self.assertEqual(bin and [flt(bin[0][0]), flt(bin[0][1], 4)] or [], |  | ||||||
| 				[flt(d[5]), flt(d[6])]) |  | ||||||
| 
 |  | ||||||
| 			# no gl entries |  | ||||||
| 			gl_entries = frappe.db.sql("""select name from `tabGL Entry` |  | ||||||
| 				where voucher_type = 'Stock Reconciliation' and voucher_no = %s""", |  | ||||||
| 				stock_reco.name) |  | ||||||
| 			self.assertFalse(gl_entries) |  | ||||||
| 
 |  | ||||||
| 	def test_reco_fifo_gl_entries(self): |  | ||||||
| 		frappe.defaults.set_global_default("auto_accounting_for_stock", 1) |  | ||||||
| 
 |  | ||||||
| 		# [[qty, valuation_rate, posting_date, posting_time, stock_in_hand_debit]] |  | ||||||
| 		input_data = [ | 		input_data = [ | ||||||
| 			[50, 1000, "2012-12-26", "12:00"], | 			[50, 1000, "2012-12-26", "12:00"], | ||||||
| 			[5, 1000, "2012-12-26", "12:00"], |  | ||||||
| 			[15, 1000, "2012-12-26", "12:00"], |  | ||||||
| 			[25, 900, "2012-12-26", "12:00"], | 			[25, 900, "2012-12-26", "12:00"], | ||||||
| 			[20, 500, "2012-12-26", "12:00"], | 			["", 1000, "2012-12-20", "12:05"], | ||||||
| 			["", 1000, "2012-12-26", "12:05"], |  | ||||||
| 			[20, "", "2012-12-26", "12:05"], | 			[20, "", "2012-12-26", "12:05"], | ||||||
| 			[10, 2000, "2012-12-26", "12:10"], | 			[0, "", "2012-12-31", "12:10"] | ||||||
| 			[0, "", "2012-12-26", "12:10"], |  | ||||||
| 			[50, 1000, "2013-01-01", "12:00"], |  | ||||||
| 			[5, 1000, "2013-01-01", "12:00"], |  | ||||||
| 			[1, 1000, "2012-12-01", "00:00"], |  | ||||||
| 		] | 		] | ||||||
| 
 | 
 | ||||||
| 		for d in input_data: | 		for d in input_data: | ||||||
| 			self.cleanup_data() | 			repost_stock_as_per_valuation_method(valuation_method) | ||||||
| 			self.insert_existing_sle("FIFO") |  | ||||||
| 			self.assertFalse(get_stock_and_account_difference(["_Test Account Stock In Hand - _TC"])) |  | ||||||
| 			stock_reco = self.submit_stock_reconciliation(d[0], d[1], d[2], d[3]) |  | ||||||
| 			 | 			 | ||||||
| 
 | 			last_sle = get_previous_sle({ | ||||||
| 			self.assertFalse(get_stock_and_account_difference(["_Test Account Stock In Hand - _TC"])) |  | ||||||
| 
 |  | ||||||
| 			stock_reco.cancel() |  | ||||||
| 			self.assertFalse(get_stock_and_account_difference(["_Test Account Stock In Hand - _TC"])) |  | ||||||
| 
 |  | ||||||
| 		frappe.defaults.set_global_default("auto_accounting_for_stock", 0) |  | ||||||
| 
 |  | ||||||
| 	def test_reco_moving_average_gl_entries(self): |  | ||||||
| 		frappe.defaults.set_global_default("auto_accounting_for_stock", 1) |  | ||||||
| 
 |  | ||||||
| 		# [[qty, valuation_rate, posting_date, |  | ||||||
| 		#		posting_time, stock_in_hand_debit]] |  | ||||||
| 		input_data = [ |  | ||||||
| 			[50, 1000, "2012-12-26", "12:00", 36500], |  | ||||||
| 			[5, 1000, "2012-12-26", "12:00", -8500], |  | ||||||
| 			[15, 1000, "2012-12-26", "12:00", 1500], |  | ||||||
| 			[25, 900, "2012-12-26", "12:00", 9000], |  | ||||||
| 			[20, 500, "2012-12-26", "12:00", -3500], |  | ||||||
| 			["", 1000, "2012-12-26", "12:05", 1500], |  | ||||||
| 			[20, "", "2012-12-26", "12:05", 4500], |  | ||||||
| 			[10, 2000, "2012-12-26", "12:10", 6500], |  | ||||||
| 			[0, "", "2012-12-26", "12:10", -13500], |  | ||||||
| 			[50, 1000, "2013-01-01", "12:00", 50000], |  | ||||||
| 			[5, 1000, "2013-01-01", "12:00", 5000], |  | ||||||
| 			[1, 1000, "2012-12-01", "00:00", 1000], |  | ||||||
| 
 |  | ||||||
| 		] |  | ||||||
| 
 |  | ||||||
| 		for d in input_data: |  | ||||||
| 			self.cleanup_data() |  | ||||||
| 			self.insert_existing_sle("Moving Average") |  | ||||||
| 			stock_reco = self.submit_stock_reconciliation(d[0], d[1], d[2], d[3]) |  | ||||||
| 			self.assertFalse(get_stock_and_account_difference(["_Test Warehouse - _TC"])) |  | ||||||
| 
 |  | ||||||
| 			# cancel |  | ||||||
| 			stock_reco.cancel() |  | ||||||
| 			self.assertFalse(get_stock_and_account_difference(["_Test Warehouse - _TC"])) |  | ||||||
| 
 |  | ||||||
| 		frappe.defaults.set_global_default("auto_accounting_for_stock", 0) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 	def cleanup_data(self): |  | ||||||
| 		frappe.db.sql("delete from `tabStock Ledger Entry`") |  | ||||||
| 		frappe.db.sql("delete from tabBin") |  | ||||||
| 		frappe.db.sql("delete from `tabGL Entry`") |  | ||||||
| 
 |  | ||||||
| 	def submit_stock_reconciliation(self, qty, rate, posting_date, posting_time): |  | ||||||
| 		stock_reco = frappe.get_doc({ |  | ||||||
| 			"doctype": "Stock Reconciliation", |  | ||||||
| 			"posting_date": posting_date, |  | ||||||
| 			"posting_time": posting_time, |  | ||||||
| 			"fiscal_year": get_fiscal_year(posting_date)[0], |  | ||||||
| 			"company": "_Test Company", |  | ||||||
| 			"expense_account": "Stock Adjustment - _TC", |  | ||||||
| 			"cost_center": "_Test Cost Center - _TC", |  | ||||||
| 			"items": [{ |  | ||||||
| 				"item_code": "_Test Item", | 				"item_code": "_Test Item", | ||||||
| 				"warehouse": "_Test Warehouse - _TC", | 				"warehouse": "_Test Warehouse - _TC", | ||||||
| 				"qty": qty, | 				"posting_date": d[2], | ||||||
| 				"valuation_rate": rate | 				"posting_time": d[3] | ||||||
| 			}] |  | ||||||
| 			}) | 			}) | ||||||
| 		stock_reco.insert() |  | ||||||
| 		stock_reco.submit() |  | ||||||
| 		frappe.db.commit() |  | ||||||
| 		return stock_reco |  | ||||||
| 
 | 
 | ||||||
| 	def insert_existing_sle(self, valuation_method): | 			# submit stock reconciliation | ||||||
|  | 			stock_reco = create_stock_reconciliation(qty=d[0], rate=d[1],  | ||||||
|  | 				posting_date=d[2], posting_time=d[3]) | ||||||
|  | 			 | ||||||
|  | 			# check stock value | ||||||
|  | 			sle = frappe.db.sql("""select * from `tabStock Ledger Entry`  | ||||||
|  | 				where voucher_type='Stock Reconciliation' and voucher_no=%s""", stock_reco.name, as_dict=1) | ||||||
|  | 			 | ||||||
|  | 			qty_after_transaction = flt(d[0]) if d[0] != "" else flt(last_sle.get("qty_after_transaction")) | ||||||
|  | 				 | ||||||
|  | 			valuation_rate = flt(d[1]) if d[1] != "" else flt(last_sle.get("valuation_rate")) | ||||||
|  | 			 | ||||||
|  | 			if qty_after_transaction == last_sle.get("qty_after_transaction") \ | ||||||
|  | 				and valuation_rate == last_sle.get("valuation_rate"): | ||||||
|  | 					self.assertFalse(sle) | ||||||
|  | 			else: | ||||||
|  | 				self.assertEqual(sle[0].qty_after_transaction, qty_after_transaction) | ||||||
|  | 				self.assertEqual(sle[0].stock_value, qty_after_transaction * valuation_rate) | ||||||
|  | 			 | ||||||
|  | 				# no gl entries | ||||||
|  | 				self.assertTrue(frappe.db.get_value("Stock Ledger Entry",  | ||||||
|  | 					{"voucher_type": "Stock Reconciliation", "voucher_no": stock_reco.name})) | ||||||
|  | 				self.assertFalse(get_stock_and_account_difference(["_Test Account Stock In Hand - _TC"])) | ||||||
|  | 					 | ||||||
|  | 			stock_reco.cancel() | ||||||
|  | 			 | ||||||
|  | 			self.assertFalse(frappe.db.get_value("Stock Ledger Entry",  | ||||||
|  | 				{"voucher_type": "Stock Reconciliation", "voucher_no": stock_reco.name})) | ||||||
|  | 				 | ||||||
|  | 			self.assertFalse(frappe.db.get_value("GL Entry",  | ||||||
|  | 				{"voucher_type": "Stock Reconciliation", "voucher_no": stock_reco.name})) | ||||||
|  | 				 | ||||||
|  | 			set_perpetual_inventory(0) | ||||||
|  | 
 | ||||||
|  | 	def insert_existing_sle(self): | ||||||
|  | 		from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry | ||||||
|  | 			 | ||||||
|  | 		make_stock_entry(posting_date="2012-12-15", posting_time="02:00", item_code="_Test Item",  | ||||||
|  | 			target="_Test Warehouse - _TC", qty=10, incoming_rate=700) | ||||||
|  | 
 | ||||||
|  | 		make_stock_entry(posting_date="2012-12-25", posting_time="03:00", item_code="_Test Item",  | ||||||
|  | 			source="_Test Warehouse - _TC", qty=15) | ||||||
|  | 
 | ||||||
|  | 		make_stock_entry(posting_date="2013-01-05", posting_time="07:00", item_code="_Test Item",  | ||||||
|  | 			target="_Test Warehouse - _TC", qty=15, incoming_rate=1200) | ||||||
|  | 			 | ||||||
|  | def create_stock_reconciliation(**args): | ||||||
|  | 	args = frappe._dict(args) | ||||||
|  | 	sr = frappe.new_doc("Stock Reconciliation") | ||||||
|  | 	sr.posting_date = args.posting_date or nowdate() | ||||||
|  | 	sr.posting_time = args.posting_time or nowtime() | ||||||
|  | 	sr.company = args.company or "_Test Company" | ||||||
|  | 	sr.fiscal_year = get_fiscal_year(sr.posting_date)[0] | ||||||
|  | 	sr.expense_account = args.expense_account or "Stock Adjustment - _TC" | ||||||
|  | 	sr.cost_center = args.cost_center or "_Test Cost Center - _TC" | ||||||
|  | 	sr.append("items", { | ||||||
|  | 		"item_code": args.item_code or "_Test Item", | ||||||
|  | 		"warehouse": args.warehouse or "_Test Warehouse - _TC", | ||||||
|  | 		"qty": args.qty, | ||||||
|  | 		"valuation_rate": args.rate | ||||||
|  | 	}) | ||||||
|  | 	sr.insert() | ||||||
|  | 	sr.submit() | ||||||
|  | 	return sr | ||||||
|  | 
 | ||||||
|  | def repost_stock_as_per_valuation_method(valuation_method): | ||||||
| 	frappe.db.set_value("Item", "_Test Item", "valuation_method", valuation_method) | 	frappe.db.set_value("Item", "_Test Item", "valuation_method", valuation_method) | ||||||
| 		frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1) | 	update_entries_after({ | ||||||
| 
 |  | ||||||
| 		stock_entry = { |  | ||||||
| 			"company": "_Test Company", |  | ||||||
| 			"doctype": "Stock Entry", |  | ||||||
| 			"posting_date": "2012-12-12", |  | ||||||
| 			"posting_time": "01:00", |  | ||||||
| 			"purpose": "Material Receipt", |  | ||||||
| 			"fiscal_year": "_Test Fiscal Year 2012", |  | ||||||
| 			"items": [ |  | ||||||
| 				{ |  | ||||||
| 					"conversion_factor": 1.0, |  | ||||||
| 					"doctype": "Stock Entry Detail", |  | ||||||
| 		"item_code": "_Test Item", | 		"item_code": "_Test Item", | ||||||
| 					"parentfield": "items", | 		"warehouse": "_Test Warehouse - _TC", | ||||||
| 					"incoming_rate": 1000, | 	}, allow_negative_stock=1) | ||||||
| 					"qty": 20.0, |  | ||||||
| 					"stock_uom": "_Test UOM", |  | ||||||
| 					"transfer_qty": 20.0, |  | ||||||
| 					"uom": "_Test UOM", |  | ||||||
| 					"t_warehouse": "_Test Warehouse - _TC", |  | ||||||
| 					"expense_account": "Stock Adjustment - _TC", |  | ||||||
| 					"cost_center": "_Test Cost Center - _TC" |  | ||||||
| 				} |  | ||||||
| 			] |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		pr = frappe.copy_doc(stock_entry) |  | ||||||
| 		pr.insert() |  | ||||||
| 		pr.submit() |  | ||||||
| 
 |  | ||||||
| 		pr1 = frappe.copy_doc(stock_entry) |  | ||||||
| 		pr1.posting_date = "2012-12-15" |  | ||||||
| 		pr1.posting_time = "02:00" |  | ||||||
| 		pr1.get("items")[0].qty = 10 |  | ||||||
| 		pr1.get("items")[0].transfer_qty = 10 |  | ||||||
| 		pr1.get("items")[0].incoming_rate = 700 |  | ||||||
| 		pr1.insert() |  | ||||||
| 		pr1.submit() |  | ||||||
| 
 |  | ||||||
| 		pr2 = frappe.copy_doc(stock_entry) |  | ||||||
| 		pr2.posting_date = "2012-12-25" |  | ||||||
| 		pr2.posting_time = "03:00" |  | ||||||
| 		pr2.purpose = "Material Issue" |  | ||||||
| 		pr2.get("items")[0].s_warehouse = "_Test Warehouse - _TC" |  | ||||||
| 		pr2.get("items")[0].t_warehouse = None |  | ||||||
| 		pr2.get("items")[0].qty = 15 |  | ||||||
| 		pr2.get("items")[0].transfer_qty = 15 |  | ||||||
| 		pr2.get("items")[0].incoming_rate = 0 |  | ||||||
| 		pr2.insert() |  | ||||||
| 		pr2.submit() |  | ||||||
| 
 |  | ||||||
| 		pr3 = frappe.copy_doc(stock_entry) |  | ||||||
| 		pr3.posting_date = "2012-12-31" |  | ||||||
| 		pr3.posting_time = "08:00" |  | ||||||
| 		pr3.purpose = "Material Issue" |  | ||||||
| 		pr3.get("items")[0].s_warehouse = "_Test Warehouse - _TC" |  | ||||||
| 		pr3.get("items")[0].t_warehouse = None |  | ||||||
| 		pr3.get("items")[0].qty = 20 |  | ||||||
| 		pr3.get("items")[0].transfer_qty = 20 |  | ||||||
| 		pr3.get("items")[0].incoming_rate = 0 |  | ||||||
| 		pr3.insert() |  | ||||||
| 		pr3.submit() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 		pr4 = frappe.copy_doc(stock_entry) |  | ||||||
| 		pr4.posting_date = "2013-01-05" |  | ||||||
| 		pr4.fiscal_year = "_Test Fiscal Year 2013" |  | ||||||
| 		pr4.posting_time = "07:00" |  | ||||||
| 		pr4.get("items")[0].qty = 15 |  | ||||||
| 		pr4.get("items")[0].transfer_qty = 15 |  | ||||||
| 		pr4.get("items")[0].incoming_rate = 1200 |  | ||||||
| 		pr4.insert() |  | ||||||
| 		pr4.submit() |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| test_dependencies = ["Item", "Warehouse"] | test_dependencies = ["Item", "Warehouse"] | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user