Merge branch 'model-cleanup' of github.com:frappe/erpnext into model-cleanup

This commit is contained in:
Rushabh Mehta 2014-04-07 15:09:25 +05:30
commit 322d39f3a6
28 changed files with 427 additions and 429 deletions

View File

@ -9,7 +9,7 @@ from frappe import _
from frappe.model.document import Document from frappe.model.document import Document
class GlEntry(Document): class GLEntry(Document):
def validate(self): def validate(self):
self.check_mandatory() self.check_mandatory()

View File

@ -353,13 +353,13 @@ def get_payment_entry_from_sales_invoice(sales_invoice):
jv.remark = 'Payment received against Sales Invoice {0}. {1}'.format(si.name, si.remarks) jv.remark = 'Payment received against Sales Invoice {0}. {1}'.format(si.name, si.remarks)
# credit customer # credit customer
jv.doclist[1].account = si.debit_to jv.get("entries")[0].account = si.debit_to
jv.doclist[1].balance = get_balance_on(si.debit_to) jv.get("entries")[0].balance = get_balance_on(si.debit_to)
jv.doclist[1].credit = si.outstanding_amount jv.get("entries")[0].credit = si.outstanding_amount
jv.doclist[1].against_invoice = si.name jv.get("entries")[0].against_invoice = si.name
# debit bank # debit bank
jv.doclist[2].debit = si.outstanding_amount jv.get("entries")[1].debit = si.outstanding_amount
return jv.as_dict() return jv.as_dict()
@ -371,13 +371,13 @@ def get_payment_entry_from_purchase_invoice(purchase_invoice):
jv.remark = 'Payment against Purchase Invoice {0}. {1}'.format(pi.name, pi.remarks) jv.remark = 'Payment against Purchase Invoice {0}. {1}'.format(pi.name, pi.remarks)
# credit supplier # credit supplier
jv.doclist[1].account = pi.credit_to jv.get("entries")[0].account = pi.credit_to
jv.doclist[1].balance = get_balance_on(pi.credit_to) jv.get("entries")[0].balance = get_balance_on(pi.credit_to)
jv.doclist[1].debit = pi.outstanding_amount jv.get("entries")[0].debit = pi.outstanding_amount
jv.doclist[1].against_voucher = pi.name jv.get("entries")[0].against_voucher = pi.name
# credit bank # credit bank
jv.doclist[2].credit = pi.outstanding_amount jv.get("entries")[1].credit = pi.outstanding_amount
return jv.as_dict() return jv.as_dict()

View File

@ -9,7 +9,7 @@ import frappe
class TestJournalVoucher(unittest.TestCase): class TestJournalVoucher(unittest.TestCase):
def test_journal_voucher_with_against_jv(self): def test_journal_voucher_with_against_jv(self):
self.clear_account_balance() self.clear_account_balance()
jv_invoice = frappe.copy_doc(test_records[2]) jv_invoice = frappe.copy_doc(test_records[1])
jv_invoice.insert() jv_invoice.insert()
jv_invoice.submit() jv_invoice.submit()
@ -17,7 +17,7 @@ class TestJournalVoucher(unittest.TestCase):
where against_jv=%s""", jv_invoice.name)) where against_jv=%s""", jv_invoice.name))
jv_payment = frappe.copy_doc(test_records[0]) jv_payment = frappe.copy_doc(test_records[0])
jv_payment.doclist[1].against_jv = jv_invoice.name jv_payment.get("entries")[0].against_jv = jv_invoice.name
jv_payment.insert() jv_payment.insert()
jv_payment.submit() jv_payment.submit()
@ -38,7 +38,7 @@ class TestJournalVoucher(unittest.TestCase):
set_perpetual_inventory() set_perpetual_inventory()
jv = frappe.copy_doc(test_records[0]) jv = frappe.copy_doc(test_records[0])
jv.doclist[1].account = "_Test Warehouse - _TC" jv.get("entries")[0].account = "_Test Warehouse - _TC"
jv.insert() jv.insert()
from erpnext.accounts.general_ledger import StockAccountInvalidTransaction from erpnext.accounts.general_ledger import StockAccountInvalidTransaction
@ -51,10 +51,10 @@ class TestJournalVoucher(unittest.TestCase):
self.clear_account_balance() self.clear_account_balance()
jv = frappe.copy_doc(test_records[0]) jv = frappe.copy_doc(test_records[0])
jv.doclist[2].account = "_Test Account Cost for Goods Sold - _TC" jv.get("entries")[1].account = "_Test Account Cost for Goods Sold - _TC"
jv.doclist[2].cost_center = "_Test Cost Center - _TC" jv.get("entries")[1].cost_center = "_Test Cost Center - _TC"
jv.doclist[2].debit = 20000.0 jv.get("entries")[1].debit = 20000.0
jv.doclist[1].credit = 20000.0 jv.get("entries")[0].credit = 20000.0
jv.insert() jv.insert()
jv.submit() jv.submit()
self.assertTrue(frappe.db.get_value("GL Entry", self.assertTrue(frappe.db.get_value("GL Entry",
@ -66,10 +66,10 @@ class TestJournalVoucher(unittest.TestCase):
self.clear_account_balance() self.clear_account_balance()
jv = frappe.copy_doc(test_records[0]) jv = frappe.copy_doc(test_records[0])
jv.doclist[2].account = "_Test Account Cost for Goods Sold - _TC" jv.get("entries")[1].account = "_Test Account Cost for Goods Sold - _TC"
jv.doclist[2].cost_center = "_Test Cost Center - _TC" jv.get("entries")[1].cost_center = "_Test Cost Center - _TC"
jv.doclist[2].debit = 20000.0 jv.get("entries")[1].debit = 20000.0
jv.doclist[1].credit = 20000.0 jv.get("entries")[0].credit = 20000.0
jv.insert() jv.insert()
self.assertRaises(BudgetError, jv.submit) self.assertRaises(BudgetError, jv.submit)
@ -85,10 +85,10 @@ class TestJournalVoucher(unittest.TestCase):
jv = frappe.copy_doc(test_records[0]) jv = frappe.copy_doc(test_records[0])
jv.posting_date = "2013-08-12" jv.posting_date = "2013-08-12"
jv.doclist[2].account = "_Test Account Cost for Goods Sold - _TC" jv.get("entries")[1].account = "_Test Account Cost for Goods Sold - _TC"
jv.doclist[2].cost_center = "_Test Cost Center - _TC" jv.get("entries")[1].cost_center = "_Test Cost Center - _TC"
jv.doclist[2].debit = 150000.0 jv.get("entries")[1].debit = 150000.0
jv.doclist[1].credit = 150000.0 jv.get("entries")[0].credit = 150000.0
jv.insert() jv.insert()
self.assertRaises(BudgetError, jv.submit) self.assertRaises(BudgetError, jv.submit)
@ -101,20 +101,20 @@ class TestJournalVoucher(unittest.TestCase):
self.clear_account_balance() self.clear_account_balance()
jv = frappe.copy_doc(test_records[0]) jv = frappe.copy_doc(test_records[0])
jv.doclist[1].account = "_Test Account Cost for Goods Sold - _TC" jv.get("entries")[0].account = "_Test Account Cost for Goods Sold - _TC"
jv.doclist[1].cost_center = "_Test Cost Center - _TC" jv.get("entries")[0].cost_center = "_Test Cost Center - _TC"
jv.doclist[1].credit = 30000.0 jv.get("entries")[0].credit = 30000.0
jv.doclist[2].debit = 30000.0 jv.get("entries")[1].debit = 30000.0
jv.submit() jv.submit()
self.assertTrue(frappe.db.get_value("GL Entry", self.assertTrue(frappe.db.get_value("GL Entry",
{"voucher_type": "Journal Voucher", "voucher_no": jv.name})) {"voucher_type": "Journal Voucher", "voucher_no": jv.name}))
jv1 = frappe.copy_doc(test_records[0]) jv1 = frappe.copy_doc(test_records[0])
jv1.doclist[2].account = "_Test Account Cost for Goods Sold - _TC" jv1.get("entries")[1].account = "_Test Account Cost for Goods Sold - _TC"
jv1.doclist[2].cost_center = "_Test Cost Center - _TC" jv1.get("entries")[1].cost_center = "_Test Cost Center - _TC"
jv1.doclist[2].debit = 40000.0 jv1.get("entries")[1].debit = 40000.0
jv1.doclist[1].credit = 40000.0 jv1.get("entries")[0].credit = 40000.0
jv1.submit() jv1.submit()
self.assertTrue(frappe.db.get_value("GL Entry", self.assertTrue(frappe.db.get_value("GL Entry",

View File

@ -17,9 +17,9 @@ class TestPeriodClosingVoucher(unittest.TestCase):
jv.submit() jv.submit()
jv1 = frappe.copy_doc(jv_records[0]) jv1 = frappe.copy_doc(jv_records[0])
jv1.doclist[2].account = "_Test Account Cost for Goods Sold - _TC" jv1.get("entries")[1].account = "_Test Account Cost for Goods Sold - _TC"
jv1.doclist[2].debit = 600.0 jv1.get("entries")[1].debit = 600.0
jv1.doclist[1].credit = 600.0 jv1.get("entries")[0].credit = 600.0
jv1.insert() jv1.insert()
jv1.submit() jv1.submit()

View File

@ -23,7 +23,7 @@ class TestPurchaseInvoice(unittest.TestCase):
wrapper.insert() wrapper.insert()
wrapper.submit() wrapper.submit()
wrapper.load_from_db() wrapper.load_from_db()
dl = wrapper.doclist dl = wrapper
expected_gl_entries = { expected_gl_entries = {
"_Test Supplier - _TC": [0, 1512.30], "_Test Supplier - _TC": [0, 1512.30],
@ -37,7 +37,7 @@ class TestPurchaseInvoice(unittest.TestCase):
"_Test Account Discount - _TC": [0, 168.03], "_Test Account Discount - _TC": [0, 168.03],
} }
gl_entries = frappe.db.sql("""select account, debit, credit from `tabGL Entry` gl_entries = frappe.db.sql("""select account, debit, credit from `tabGL Entry`
where voucher_type = 'Purchase Invoice' and voucher_no = %s""", dl[0].name, as_dict=1) where voucher_type = 'Purchase Invoice' and voucher_no = %s""", dl.name, as_dict=1)
for d in gl_entries: for d in gl_entries:
self.assertEqual([d.debit, d.credit], expected_gl_entries.get(d.account)) self.assertEqual([d.debit, d.credit], expected_gl_entries.get(d.account))
@ -74,10 +74,10 @@ class TestPurchaseInvoice(unittest.TestCase):
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)
pi = frappe.copy_doc(test_records[1]) pi = frappe.copy_doc(test_records[1])
pi.doclist[1].item_code = "_Test Non Stock Item" pi.get("entries")[0].item_code = "_Test Non Stock Item"
pi.doclist[1].expense_account = "_Test Account Cost for Goods Sold - _TC" pi.get("entries")[0].expense_account = "_Test Account Cost for Goods Sold - _TC"
pi.doclist.pop(2) pi.get("entries").pop(2)
pi.doclist.pop(3) pi.get("entries").pop(1)
pi.insert() pi.insert()
pi.submit() pi.submit()
@ -112,7 +112,7 @@ class TestPurchaseInvoice(unittest.TestCase):
self.assertEqual(item.item_tax_amount, expected_values[i][1]) self.assertEqual(item.item_tax_amount, expected_values[i][1])
self.assertEqual(item.valuation_rate, expected_values[i][2]) self.assertEqual(item.valuation_rate, expected_values[i][2])
self.assertEqual(wrapper.doclist[0].net_total, 1250) self.assertEqual(wrapper.net_total, 1250)
# tax amounts # tax amounts
expected_values = [ expected_values = [
@ -133,7 +133,7 @@ class TestPurchaseInvoice(unittest.TestCase):
def test_purchase_invoice_with_subcontracted_item(self): def test_purchase_invoice_with_subcontracted_item(self):
wrapper = frappe.copy_doc(test_records[0]) wrapper = frappe.copy_doc(test_records[0])
wrapper.doclist[1].item_code = "_Test FG Item" wrapper.get("entries")[0].item_code = "_Test FG Item"
wrapper.insert() wrapper.insert()
wrapper.load_from_db() wrapper.load_from_db()
@ -146,7 +146,7 @@ class TestPurchaseInvoice(unittest.TestCase):
self.assertEqual(item.item_tax_amount, expected_values[i][1]) self.assertEqual(item.item_tax_amount, expected_values[i][1])
self.assertEqual(item.valuation_rate, expected_values[i][2]) self.assertEqual(item.valuation_rate, expected_values[i][2])
self.assertEqual(wrapper.doclist[0].net_total, 1250) self.assertEqual(wrapper.net_total, 1250)
# tax amounts # tax amounts
expected_values = [ expected_values = [
@ -176,7 +176,7 @@ class TestPurchaseInvoice(unittest.TestCase):
pi = frappe.copy_doc(test_records[0]) pi = frappe.copy_doc(test_records[0])
pi.append("advance_allocation_details", { pi.append("advance_allocation_details", {
"journal_voucher": jv.name, "journal_voucher": jv.name,
"jv_detail_no": jv.doclist[1].name, "jv_detail_no": jv.get("entries")[0].name,
"advance_amount": 400, "advance_amount": 400,
"allocated_amount": 300, "allocated_amount": 300,
"remarks": jv.remark "remarks": jv.remark

View File

@ -202,7 +202,7 @@ class SalesInvoice(SellingController):
self.terms = frappe.db.get_value("Terms and Conditions", self.tc_name, "terms") self.terms = frappe.db.get_value("Terms and Conditions", self.tc_name, "terms")
# fetch charges # fetch charges
if self.charge and not len(self.get("other_charges")): if self.taxes_and_charges and not len(self.get("other_charges")):
self.set_taxes("other_charges", "taxes_and_charges") self.set_taxes("other_charges", "taxes_and_charges")
def get_advances(self): def get_advances(self):

View File

@ -20,7 +20,7 @@ class TestSalesInvoice(unittest.TestCase):
w.docstatus = '0' w.docstatus = '0'
w.insert() w.insert()
w2 = [d for d in w.doclist] w2 = frappe.copy_doc(test_records[0])
w.submit() w.submit()
w = frappe.get_doc(w2) w = frappe.get_doc(w2)
@ -89,10 +89,10 @@ class TestSalesInvoice(unittest.TestCase):
si = frappe.copy_doc(test_records[2]) si = frappe.copy_doc(test_records[2])
si.currency = "USD" si.currency = "USD"
si.conversion_rate = 50 si.conversion_rate = 50
si.doclist[1].rate = 1 si.get("entries")[0].rate = 1
si.doclist[1].price_list_rate = 1 si.get("entries")[0].price_list_rate = 1
si.doclist[2].rate = 3 si.get("entries")[1].rate = 3
si.doclist[2].price_list_rate = 3 si.get("entries")[1].price_list_rate = 3
si.insert() si.insert()
expected_values = { expected_values = {
@ -243,16 +243,16 @@ class TestSalesInvoice(unittest.TestCase):
for i, tax in enumerate(si.get("other_charges")): for i, tax in enumerate(si.get("other_charges")):
tax.idx = i+1 tax.idx = i+1
si.doclist[1].price_list_rate = 62.5 si.get("entries")[0].price_list_rate = 62.5
si.doclist[1].price_list_rate = 191 si.get("entries")[0].price_list_rate = 191
for i in [3, 5, 6, 7, 8, 9]: for i in [2, 4, 5, 6, 7, 8]:
si.doclist[i].included_in_print_rate = 1 si.get("other_charges")[i].included_in_print_rate = 1
# tax type "Actual" cannot be inclusive # tax type "Actual" cannot be inclusive
self.assertRaises(frappe.ValidationError, si.insert) self.assertRaises(frappe.ValidationError, si.insert)
# taxes above included type 'On Previous Row Total' should also be included # taxes above included type 'On Previous Row Total' should also be included
si.doclist[3].included_in_print_rate = 0 si.get("other_charges")[0].included_in_print_rate = 0
self.assertRaises(frappe.ValidationError, si.insert) self.assertRaises(frappe.ValidationError, si.insert)
def test_sales_invoice_calculation_base_currency_with_tax_inclusive_price(self): def test_sales_invoice_calculation_base_currency_with_tax_inclusive_price(self):
@ -305,11 +305,11 @@ class TestSalesInvoice(unittest.TestCase):
si = frappe.copy_doc(test_records[3]) si = frappe.copy_doc(test_records[3])
si.currency = "USD" si.currency = "USD"
si.conversion_rate = 50 si.conversion_rate = 50
si.doclist[1].price_list_rate = 55.56 si.get("entries")[0].price_list_rate = 55.56
si.doclist[1].discount_percentage = 10 si.get("entries")[0].discount_percentage = 10
si.doclist[2].price_list_rate = 187.5 si.get("entries")[1].price_list_rate = 187.5
si.doclist[2].discount_percentage = 20 si.get("entries")[1].discount_percentage = 20
si.doclist[9].rate = 5000 si.get("other_charges")[5].rate = 5000
si.insert() si.insert()
@ -365,7 +365,7 @@ class TestSalesInvoice(unittest.TestCase):
import test_records as jv_test_records import test_records as jv_test_records
jv = frappe.get_doc(frappe.copy_doc(jv_test_records[0])) jv = frappe.get_doc(frappe.copy_doc(jv_test_records[0]))
jv.doclist[1].against_invoice = w.name jv.get("entries")[0].against_invoice = w.name
jv.insert() jv.insert()
jv.submit() jv.submit()
@ -381,7 +381,7 @@ class TestSalesInvoice(unittest.TestCase):
tlb.submit() tlb.submit()
si = frappe.get_doc(frappe.copy_doc(test_records[0])) si = frappe.get_doc(frappe.copy_doc(test_records[0]))
si.doclist[1].time_log_batch = "_T-Time Log Batch-00001" si.get("entries")[0].time_log_batch = "_T-Time Log Batch-00001"
si.insert() si.insert()
si.submit() si.submit()
@ -501,16 +501,16 @@ class TestSalesInvoice(unittest.TestCase):
as pr_test_records as pr_test_records
pr = frappe.copy_doc(pr_test_records[0]) pr = frappe.copy_doc(pr_test_records[0])
pr.naming_series = "_T-Purchase Receipt-" pr.naming_series = "_T-Purchase Receipt-"
pr.doclist[1].warehouse = "_Test Warehouse No Account - _TC" pr.get("entries")[0].warehouse = "_Test Warehouse No Account - _TC"
pr.insert() pr.insert()
pr.submit() pr.submit()
si_doclist = frappe.copy_doc(test_records[1]) si_doc = frappe.copy_doc(test_records[1])
si_doclist[0]["update_stock"] = 1 si_doc["update_stock"] = 1
si_doclist[0]["posting_time"] = "12:05" si_doc["posting_time"] = "12:05"
si_doclist[1]["warehouse"] = "_Test Warehouse No Account - _TC" si_doc.get("entries")["warehouse"] = "_Test Warehouse No Account - _TC"
si = frappe.copy_doc(si_doclist) si = frappe.copy_doc(si_doc)
si.insert() si.insert()
si.submit() si.submit()
@ -530,9 +530,9 @@ class TestSalesInvoice(unittest.TestCase):
expected_gl_entries = sorted([ expected_gl_entries = sorted([
[si.debit_to, 630.0, 0.0], [si.debit_to, 630.0, 0.0],
[si_doclist[1]["income_account"], 0.0, 500.0], [si_doc.get("entries")["income_account"], 0.0, 500.0],
[si_doclist[2]["account_head"], 0.0, 80.0], [si_doc.get("other_charges")[0]["account_head"], 0.0, 80.0],
[si_doclist[3]["account_head"], 0.0, 50.0], [si_doc.get("other_charges")[1]["account_head"], 0.0, 50.0],
]) ])
for i, gle in enumerate(gl_entries): for i, gle in enumerate(gl_entries):
self.assertEquals(expected_gl_entries[i][0], gle.account) self.assertEquals(expected_gl_entries[i][0], gle.account)
@ -638,7 +638,7 @@ class TestSalesInvoice(unittest.TestCase):
si.append("advance_adjustment_details", { si.append("advance_adjustment_details", {
"doctype": "Sales Invoice Advance", "doctype": "Sales Invoice Advance",
"journal_voucher": jv.name, "journal_voucher": jv.name,
"jv_detail_no": jv.doclist[1].name, "jv_detail_no": jv.get("entries")[0].name,
"advance_amount": 400, "advance_amount": 400,
"allocated_amount": 300, "allocated_amount": 300,
"remarks": jv.remark "remarks": jv.remark
@ -677,13 +677,13 @@ class TestSalesInvoice(unittest.TestCase):
}) })
# monthly # monthly
si1 = frappe.copy_doc(base_si.doclist) si1 = frappe.copy_doc(base_si)
si1.insert() si1.insert()
si1.submit() si1.submit()
self._test_recurring_invoice(si1, True) self._test_recurring_invoice(si1, True)
# monthly without a first and last day period # monthly without a first and last day period
si2 = frappe.copy_doc(base_si.doclist) si2 = frappe.copy_doc(base_si)
si2.update({ si2.update({
"invoice_period_from_date": today, "invoice_period_from_date": today,
"invoice_period_to_date": add_to_date(today, days=30) "invoice_period_to_date": add_to_date(today, days=30)
@ -693,7 +693,7 @@ class TestSalesInvoice(unittest.TestCase):
self._test_recurring_invoice(si2, False) self._test_recurring_invoice(si2, False)
# quarterly # quarterly
si3 = frappe.copy_doc(base_si.doclist) si3 = frappe.copy_doc(base_si)
si3.update({ si3.update({
"recurring_type": "Quarterly", "recurring_type": "Quarterly",
"invoice_period_from_date": get_first_day(today), "invoice_period_from_date": get_first_day(today),
@ -704,7 +704,7 @@ class TestSalesInvoice(unittest.TestCase):
self._test_recurring_invoice(si3, True) self._test_recurring_invoice(si3, True)
# quarterly without a first and last day period # quarterly without a first and last day period
si4 = frappe.copy_doc(base_si.doclist) si4 = frappe.copy_doc(base_si)
si4.update({ si4.update({
"recurring_type": "Quarterly", "recurring_type": "Quarterly",
"invoice_period_from_date": today, "invoice_period_from_date": today,
@ -715,7 +715,7 @@ class TestSalesInvoice(unittest.TestCase):
self._test_recurring_invoice(si4, False) self._test_recurring_invoice(si4, False)
# yearly # yearly
si5 = frappe.copy_doc(base_si.doclist) si5 = frappe.copy_doc(base_si)
si5.update({ si5.update({
"recurring_type": "Yearly", "recurring_type": "Yearly",
"invoice_period_from_date": get_first_day(today), "invoice_period_from_date": get_first_day(today),
@ -726,7 +726,7 @@ class TestSalesInvoice(unittest.TestCase):
self._test_recurring_invoice(si5, True) self._test_recurring_invoice(si5, True)
# yearly without a first and last day period # yearly without a first and last day period
si6 = frappe.copy_doc(base_si.doclist) si6 = frappe.copy_doc(base_si)
si6.update({ si6.update({
"recurring_type": "Yearly", "recurring_type": "Yearly",
"invoice_period_from_date": today, "invoice_period_from_date": today,
@ -737,7 +737,7 @@ class TestSalesInvoice(unittest.TestCase):
self._test_recurring_invoice(si6, False) self._test_recurring_invoice(si6, False)
# change posting date but keep recuring day to be today # change posting date but keep recuring day to be today
si7 = frappe.copy_doc(base_si.doclist) si7 = frappe.copy_doc(base_si)
si7.update({ si7.update({
"posting_date": add_to_date(today, days=-1) "posting_date": add_to_date(today, days=-1)
}) })
@ -808,13 +808,13 @@ class TestSalesInvoice(unittest.TestCase):
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos 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.doclist[1].serial_no) serial_nos = get_serial_nos(se.get("entries")[0].serial_no)
si = frappe.copy_doc(test_records[0]) si = frappe.copy_doc(test_records[0])
si.update_stock = 1 si.update_stock = 1
si.doclist[1].item_code = "_Test Serialized Item With Series" si.get("entries")[0].item_code = "_Test Serialized Item With Series"
si.doclist[1].qty = 1 si.get("entries")[0].qty = 1
si.doclist[1].serial_no = serial_nos[0] si.get("entries")[0].serial_no = serial_nos[0]
si.insert() si.insert()
si.submit() si.submit()
@ -830,7 +830,7 @@ class TestSalesInvoice(unittest.TestCase):
si = self.test_serialized() si = self.test_serialized()
si.cancel() si.cancel()
serial_nos = get_serial_nos(si.doclist[1].serial_no) serial_nos = get_serial_nos(si.get("entries")[0].serial_no)
self.assertEquals(frappe.db.get_value("Serial No", serial_nos[0], "status"), "Available") self.assertEquals(frappe.db.get_value("Serial No", serial_nos[0], "status"), "Available")
self.assertEquals(frappe.db.get_value("Serial No", serial_nos[0], "warehouse"), "_Test Warehouse - _TC") self.assertEquals(frappe.db.get_value("Serial No", serial_nos[0], "warehouse"), "_Test Warehouse - _TC")
@ -842,7 +842,7 @@ class TestSalesInvoice(unittest.TestCase):
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
se = make_serialized_item() se = make_serialized_item()
serial_nos = get_serial_nos(se.doclist[1].serial_no) serial_nos = get_serial_nos(se.get("entries")[0].serial_no)
sr = frappe.get_doc("Serial No", serial_nos[0]) sr = frappe.get_doc("Serial No", serial_nos[0])
sr.status = "Not Available" sr.status = "Not Available"
@ -850,9 +850,9 @@ class TestSalesInvoice(unittest.TestCase):
si = frappe.copy_doc(test_records[0]) si = frappe.copy_doc(test_records[0])
si.update_stock = 1 si.update_stock = 1
si.doclist[1].item_code = "_Test Serialized Item With Series" si.get("entries")[0].item_code = "_Test Serialized Item With Series"
si.doclist[1].qty = 1 si.get("entries")[0].qty = 1
si.doclist[1].serial_no = serial_nos[0] si.get("entries")[0].serial_no = serial_nos[0]
si.insert() si.insert()
self.assertRaises(SerialNoStatusError, si.submit) self.assertRaises(SerialNoStatusError, si.submit)

View File

@ -10,12 +10,12 @@ test_records = frappe.get_test_records('Shipping Rule')
class TestShippingRule(unittest.TestCase): class TestShippingRule(unittest.TestCase):
def test_from_greater_than_to(self): def test_from_greater_than_to(self):
shipping_rule = frappe.copy_doc(test_records[0]) shipping_rule = frappe.copy_doc(test_records[0])
shipping_rule.doclist[1].from_value = 101 shipping_rule.get("shipping_rule_conditions")[0].from_value = 101
self.assertRaises(FromGreaterThanToError, shipping_rule.insert) self.assertRaises(FromGreaterThanToError, shipping_rule.insert)
def test_many_zero_to_values(self): def test_many_zero_to_values(self):
shipping_rule = frappe.copy_doc(test_records[0]) shipping_rule = frappe.copy_doc(test_records[0])
shipping_rule.doclist[1].to_value = 0 shipping_rule.get("shipping_rule_conditions")[0].to_value = 0
self.assertRaises(ManyBlankToValuesError, shipping_rule.insert) self.assertRaises(ManyBlankToValuesError, shipping_rule.insert)
def test_overlapping_conditions(self): def test_overlapping_conditions(self):
@ -27,8 +27,8 @@ class TestShippingRule(unittest.TestCase):
((50, 150), (50, 150)), ((50, 150), (50, 150)),
]: ]:
shipping_rule = frappe.copy_doc(test_records[0]) shipping_rule = frappe.copy_doc(test_records[0])
shipping_rule.doclist[1].from_value = range_a[0] shipping_rule.get("shipping_rule_conditions")[0].from_value = range_a[0]
shipping_rule.doclist[1].to_value = range_a[1] shipping_rule.get("shipping_rule_conditions")[0].to_value = range_a[1]
shipping_rule.doclist[2].from_value = range_b[0] shipping_rule.get("shipping_rule_conditions")[1].from_value = range_b[0]
shipping_rule.doclist[2].to_value = range_b[1] shipping_rule.get("shipping_rule_conditions")[1].to_value = range_b[1]
self.assertRaises(OverlappingConditionError, shipping_rule.insert) self.assertRaises(OverlappingConditionError, shipping_rule.insert)

View File

@ -41,7 +41,7 @@ class TestPurchaseOrder(unittest.TestCase):
po = frappe.get_doc("Purchase Order", po.name) po = frappe.get_doc("Purchase Order", po.name)
po.is_subcontracted = "No" po.is_subcontracted = "No"
po.doclist[1].item_code = "_Test Item" po.get("po_details")[0].item_code = "_Test Item"
po.submit() po.submit()
self.assertEquals(frappe.db.get_value("Bin", {"item_code": "_Test Item", self.assertEquals(frappe.db.get_value("Bin", {"item_code": "_Test Item",
@ -107,7 +107,7 @@ class TestPurchaseOrder(unittest.TestCase):
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 = frappe.copy_doc(test_records[0])
po.doclist[1].qty = 3.4 po.get("po_details")[0].qty = 3.4
self.assertRaises(UOMMustBeIntegerError, po.insert) self.assertRaises(UOMMustBeIntegerError, po.insert)

View File

@ -21,7 +21,7 @@ class TestPurchaseOrder(unittest.TestCase):
po = make_purchase_order(sq.name) po = make_purchase_order(sq.name)
self.assertEquals(po[0]["doctype"], "Purchase Order") self.assertEquals(po[0]["doctype"], "Purchase Order")
self.assertEquals(len(po), len(sq.doclist)) self.assertEquals(len(po), len(sq))
po[0]["naming_series"] = "_T-Purchase Order-" po[0]["naming_series"] = "_T-Purchase Order-"

View File

@ -369,7 +369,7 @@ class AccountsController(TransactionBase):
'voucher_type': self.doctype, 'voucher_type': self.doctype,
'voucher_no': self.name, 'voucher_no': self.name,
'aging_date': self.get("aging_date") or self.posting_date, 'aging_date': self.get("aging_date") or self.posting_date,
'remarks': self.remarks, 'remarks': self.get("remarks"),
'fiscal_year': self.fiscal_year, 'fiscal_year': self.fiscal_year,
'debit': 0, 'debit': 0,
'credit': 0, 'credit': 0,

View File

@ -336,8 +336,8 @@ class SellingController(StockController):
'qty': d.qty, 'qty': d.qty,
'reserved_qty': reserved_qty_for_main_item, 'reserved_qty': reserved_qty_for_main_item,
'uom': d.stock_uom, 'uom': d.stock_uom,
'batch_no': cstr(d.batch_no).strip(), 'batch_no': cstr(d.get("batch_no")).strip(),
'serial_no': cstr(d.serial_no).strip(), 'serial_no': cstr(d.get("serial_no")).strip(),
'name': d.name 'name': d.name
})) }))
return il return il

View File

@ -49,7 +49,7 @@ class StockController(AccountsController):
"account": warehouse_account[sle.warehouse], "account": warehouse_account[sle.warehouse],
"against": detail.expense_account, "against": detail.expense_account,
"cost_center": detail.cost_center, "cost_center": detail.cost_center,
"remarks": self.remarks or "Accounting Entry for Stock", "remarks": self.get("remarks") or "Accounting Entry for Stock",
"debit": flt(sle.stock_value_difference, 2) "debit": flt(sle.stock_value_difference, 2)
})) }))
@ -58,7 +58,7 @@ class StockController(AccountsController):
"account": detail.expense_account, "account": detail.expense_account,
"against": warehouse_account[sle.warehouse], "against": warehouse_account[sle.warehouse],
"cost_center": detail.cost_center, "cost_center": detail.cost_center,
"remarks": self.remarks or "Accounting Entry for Stock", "remarks": self.get("remarks") or "Accounting Entry for Stock",
"credit": flt(sle.stock_value_difference, 2) "credit": flt(sle.stock_value_difference, 2)
})) }))
elif sle.warehouse not in warehouse_with_no_account: elif sle.warehouse not in warehouse_with_no_account:
@ -103,8 +103,15 @@ class StockController(AccountsController):
for d in item_doclist: for d in item_doclist:
if d.item_code and d.item_code not in items: if d.item_code and d.item_code not in items:
items.append(d.item_code) items.append(d.item_code)
if d.warehouse and d.warehouse not in warehouses:
if d.get("warehouse") and d.warehouse not in warehouses:
warehouses.append(d.warehouse) warehouses.append(d.warehouse)
if self.doctype == "Stock Entry":
if d.get("s_warehouse") and d.s_warehouse not in warehouses:
warehouses.append(d.s_warehouse)
if d.get("t_warehouse") and d.t_warehouse not in warehouses:
warehouses.append(d.t_warehouse)
warehouse_account = {wh: warehouse_account[wh] for wh in warehouses warehouse_account = {wh: warehouse_account[wh] for wh in warehouses
if warehouse_account.get(wh)} if warehouse_account.get(wh)}
@ -234,20 +241,20 @@ class StockController(AccountsController):
def get_sl_entries(self, d, args): def get_sl_entries(self, d, args):
sl_dict = { sl_dict = {
"item_code": d.item_code, "item_code": d.item_code,
"warehouse": d.warehouse, "warehouse": d.get("warehouse", None),
"posting_date": self.posting_date, "posting_date": self.posting_date,
"posting_time": self.posting_time, "posting_time": self.posting_time,
"voucher_type": self.doctype, "voucher_type": self.doctype,
"voucher_no": self.name, "voucher_no": self.name,
"voucher_detail_no": d.name, "voucher_detail_no": d.name,
"actual_qty": (self.docstatus==1 and 1 or -1)*flt(d.stock_qty), "actual_qty": (self.docstatus==1 and 1 or -1)*flt(d.get("stock_qty")),
"stock_uom": d.stock_uom, "stock_uom": d.stock_uom,
"incoming_rate": 0, "incoming_rate": 0,
"company": self.company, "company": self.company,
"fiscal_year": self.fiscal_year, "fiscal_year": self.fiscal_year,
"batch_no": cstr(d.batch_no).strip(), "batch_no": cstr(d.batch_no).strip(),
"serial_no": d.serial_no, "serial_no": d.serial_no,
"project": d.project_name, "project": d.get("project_name"),
"is_cancelled": self.docstatus==2 and "Yes" or "No" "is_cancelled": self.docstatus==2 and "Yes" or "No"
} }

View File

@ -27,7 +27,7 @@ class TestProductionOrder(unittest.TestCase):
mr1.submit() mr1.submit()
mr2 = frappe.copy_doc(se_test_records[0]) mr2 = frappe.copy_doc(se_test_records[0])
mr2.doclist[1].item_code = "_Test Item Home Desktop 100" mr2.get("mtn_details")[0].item_code = "_Test Item Home Desktop 100"
mr2.insert() mr2.insert()
mr2.submit() mr2.submit()

View File

@ -17,7 +17,7 @@ class TimeLogBatchTest(unittest.TestCase):
self.assertEquals(frappe.db.get_value("Time Log", time_log.name, "status"), "Submitted") self.assertEquals(frappe.db.get_value("Time Log", time_log.name, "status"), "Submitted")
tlb = frappe.copy_doc(test_records[0]) tlb = frappe.copy_doc(test_records[0])
tlb.doclist[1].time_log = time_log.name tlb["time_log_batch_details"][0].time_log = time_log.name
tlb.insert() tlb.insert()
tlb.submit() tlb.submit()

View File

@ -22,7 +22,7 @@ class TestSalesOrder(unittest.TestCase):
mr = make_material_request(so.name) mr = make_material_request(so.name)
self.assertEquals(mr[0]["material_request_type"], "Purchase") self.assertEquals(mr[0]["material_request_type"], "Purchase")
self.assertEquals(len(mr), len(sales_order.doclist)) self.assertEquals(len(mr), len(sales_order))
def test_make_delivery_note(self): def test_make_delivery_note(self):
from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note
@ -37,7 +37,7 @@ class TestSalesOrder(unittest.TestCase):
dn = make_delivery_note(so.name) dn = make_delivery_note(so.name)
self.assertEquals(dn[0]["doctype"], "Delivery Note") self.assertEquals(dn[0]["doctype"], "Delivery Note")
self.assertEquals(len(dn), len(sales_order.doclist)) self.assertEquals(len(dn), len(sales_order))
def test_make_sales_invoice(self): def test_make_sales_invoice(self):
from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice
@ -52,7 +52,7 @@ class TestSalesOrder(unittest.TestCase):
si = make_sales_invoice(so.name) si = make_sales_invoice(so.name)
self.assertEquals(si[0]["doctype"], "Sales Invoice") self.assertEquals(si[0]["doctype"], "Sales Invoice")
self.assertEquals(len(si), len(sales_order.doclist)) self.assertEquals(len(si), len(sales_order))
self.assertEquals(len([d for d in si if d["doctype"]=="Sales Invoice Item"]), 1) self.assertEquals(len([d for d in si if d["doctype"]=="Sales Invoice Item"]), 1)
si = frappe.get_doc(si) si = frappe.get_doc(si)
@ -64,11 +64,11 @@ class TestSalesOrder(unittest.TestCase):
self.assertEquals(len([d for d in si1 if d["doctype"]=="Sales Invoice Item"]), 0) self.assertEquals(len([d for d in si1 if d["doctype"]=="Sales Invoice Item"]), 0)
def create_so(self, so_doclist = None): def create_so(self, so_doc = None):
if not so_doclist: if not so_doc:
so_doclist = test_records[0] so_doc = test_records[0]
w = frappe.copy_doc(so_doclist) w = frappe.copy_doc(so_doc)
w.insert() w.insert()
w.submit() w.submit()
@ -78,14 +78,14 @@ class TestSalesOrder(unittest.TestCase):
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 test_records as dn_test_records
from erpnext.stock.doctype.delivery_note.test_delivery_note import _insert_purchase_receipt from erpnext.stock.doctype.delivery_note.test_delivery_note import _insert_purchase_receipt
_insert_purchase_receipt(so.doclist[1].item_code) _insert_purchase_receipt(so.get("sales_order_details")[0].item_code)
dn = frappe.get_doc(frappe.copy_doc(dn_test_records[0])) dn = frappe.get_doc(frappe.copy_doc(dn_test_records[0]))
dn.doclist[1].item_code = so.doclist[1].item_code dn.get("delivery_note_details")[0].item_code = so.get("sales_order_details")[0].item_code
dn.doclist[1].against_sales_order = so.name dn.get("delivery_note_details")[0].against_sales_order = so.name
dn.doclist[1].prevdoc_detail_docname = so.doclist[1].name dn.get("delivery_note_details")[0].prevdoc_detail_docname = so.get("sales_order_details")[0].name
if delivered_qty: if delivered_qty:
dn.doclist[1].qty = delivered_qty dn.get("delivery_note_details")[0].qty = delivered_qty
dn.insert() dn.insert()
dn.submit() dn.submit()
return dn return dn
@ -110,11 +110,11 @@ class TestSalesOrder(unittest.TestCase):
# submit # submit
so = self.create_so() so = self.create_so()
self.check_reserved_qty(so.doclist[1].item_code, so.doclist[1].warehouse, 10.0) self.check_reserved_qty(so.get("sales_order_details")[0].item_code, so.get("sales_order_details")[0].warehouse, 10.0)
# cancel # cancel
so.cancel() so.cancel()
self.check_reserved_qty(so.doclist[1].item_code, so.doclist[1].warehouse, 0.0) self.check_reserved_qty(so.get("sales_order_details")[0].item_code, so.get("sales_order_details")[0].warehouse, 0.0)
def test_reserved_qty_for_partial_delivery(self): def test_reserved_qty_for_partial_delivery(self):
@ -130,21 +130,21 @@ class TestSalesOrder(unittest.TestCase):
# submit dn # submit dn
dn = self.create_dn_against_so(so) dn = self.create_dn_against_so(so)
self.check_reserved_qty(so.doclist[1].item_code, so.doclist[1].warehouse, 5.0) self.check_reserved_qty(so.get("sales_order_details")[0].item_code, so.get("sales_order_details")[0].warehouse, 5.0)
# stop so # stop so
so.load_from_db() so.load_from_db()
so.obj.stop_sales_order() so.obj.stop_sales_order()
self.check_reserved_qty(so.doclist[1].item_code, so.doclist[1].warehouse, 0.0) self.check_reserved_qty(so.get("sales_order_details")[0].item_code, so.get("sales_order_details")[0].warehouse, 0.0)
# unstop so # unstop so
so.load_from_db() so.load_from_db()
so.obj.unstop_sales_order() so.obj.unstop_sales_order()
self.check_reserved_qty(so.doclist[1].item_code, so.doclist[1].warehouse, 5.0) self.check_reserved_qty(so.get("sales_order_details")[0].item_code, so.get("sales_order_details")[0].warehouse, 5.0)
# cancel dn # cancel dn
dn.cancel() dn.cancel()
self.check_reserved_qty(so.doclist[1].item_code, so.doclist[1].warehouse, 10.0) self.check_reserved_qty(so.get("sales_order_details")[0].item_code, so.get("sales_order_details")[0].warehouse, 10.0)
def test_reserved_qty_for_over_delivery(self): def test_reserved_qty_for_over_delivery(self):
# reset bin # reset bin
@ -157,15 +157,15 @@ class TestSalesOrder(unittest.TestCase):
frappe.db.set_default("allow_negative_stock", 1) frappe.db.set_default("allow_negative_stock", 1)
# set over-delivery tolerance # set over-delivery tolerance
frappe.db.set_value('Item', so.doclist[1].item_code, 'tolerance', 50) frappe.db.set_value('Item', so.get("sales_order_details")[0].item_code, 'tolerance', 50)
# submit dn # submit dn
dn = self.create_dn_against_so(so, 15) dn = self.create_dn_against_so(so, 15)
self.check_reserved_qty(so.doclist[1].item_code, so.doclist[1].warehouse, 0.0) self.check_reserved_qty(so.get("sales_order_details")[0].item_code, so.get("sales_order_details")[0].warehouse, 0.0)
# cancel dn # cancel dn
dn.cancel() dn.cancel()
self.check_reserved_qty(so.doclist[1].item_code, so.doclist[1].warehouse, 10.0) self.check_reserved_qty(so.get("sales_order_details")[0].item_code, so.get("sales_order_details")[0].warehouse, 10.0)
def test_reserved_qty_for_so_with_packing_list(self): 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 from erpnext.selling.doctype.sales_bom.test_sales_bom import test_records as sbom_test_records
@ -183,16 +183,16 @@ class TestSalesOrder(unittest.TestCase):
self.check_reserved_qty(sbom_test_records[0][1]["item_code"], self.check_reserved_qty(sbom_test_records[0][1]["item_code"],
so.doclist[1].warehouse, 50.0) so.get("sales_order_details")[0].warehouse, 50.0)
self.check_reserved_qty(sbom_test_records[0][2]["item_code"], self.check_reserved_qty(sbom_test_records[0][2]["item_code"],
so.doclist[1].warehouse, 20.0) so.get("sales_order_details")[0].warehouse, 20.0)
# cancel # cancel
so.cancel() so.cancel()
self.check_reserved_qty(sbom_test_records[0][1]["item_code"], self.check_reserved_qty(sbom_test_records[0][1]["item_code"],
so.doclist[1].warehouse, 0.0) so.get("sales_order_details")[0].warehouse, 0.0)
self.check_reserved_qty(sbom_test_records[0][2]["item_code"], self.check_reserved_qty(sbom_test_records[0][2]["item_code"],
so.doclist[1].warehouse, 0.0) so.get("sales_order_details")[0].warehouse, 0.0)
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 from erpnext.selling.doctype.sales_bom.test_sales_bom import test_records as sbom_test_records
@ -216,33 +216,33 @@ class TestSalesOrder(unittest.TestCase):
dn = self.create_dn_against_so(so) dn = self.create_dn_against_so(so)
self.check_reserved_qty(sbom_test_records[0][1]["item_code"], self.check_reserved_qty(sbom_test_records[0][1]["item_code"],
so.doclist[1].warehouse, 25.0) so.get("sales_order_details")[0].warehouse, 25.0)
self.check_reserved_qty(sbom_test_records[0][2]["item_code"], self.check_reserved_qty(sbom_test_records[0][2]["item_code"],
so.doclist[1].warehouse, 10.0) so.get("sales_order_details")[0].warehouse, 10.0)
# stop so # stop so
so.load_from_db() so.load_from_db()
so.obj.stop_sales_order() so.obj.stop_sales_order()
self.check_reserved_qty(sbom_test_records[0][1]["item_code"], self.check_reserved_qty(sbom_test_records[0][1]["item_code"],
so.doclist[1].warehouse, 0.0) so.get("sales_order_details")[0].warehouse, 0.0)
self.check_reserved_qty(sbom_test_records[0][2]["item_code"], self.check_reserved_qty(sbom_test_records[0][2]["item_code"],
so.doclist[1].warehouse, 0.0) so.get("sales_order_details")[0].warehouse, 0.0)
# unstop so # unstop so
so.load_from_db() so.load_from_db()
so.obj.unstop_sales_order() so.obj.unstop_sales_order()
self.check_reserved_qty(sbom_test_records[0][1]["item_code"], self.check_reserved_qty(sbom_test_records[0][1]["item_code"],
so.doclist[1].warehouse, 25.0) so.get("sales_order_details")[0].warehouse, 25.0)
self.check_reserved_qty(sbom_test_records[0][2]["item_code"], self.check_reserved_qty(sbom_test_records[0][2]["item_code"],
so.doclist[1].warehouse, 10.0) so.get("sales_order_details")[0].warehouse, 10.0)
# cancel dn # cancel dn
dn.cancel() dn.cancel()
self.check_reserved_qty(sbom_test_records[0][1]["item_code"], self.check_reserved_qty(sbom_test_records[0][1]["item_code"],
so.doclist[1].warehouse, 50.0) so.get("sales_order_details")[0].warehouse, 50.0)
self.check_reserved_qty(sbom_test_records[0][2]["item_code"], self.check_reserved_qty(sbom_test_records[0][2]["item_code"],
so.doclist[1].warehouse, 20.0) so.get("sales_order_details")[0].warehouse, 20.0)
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 from erpnext.selling.doctype.sales_bom.test_sales_bom import test_records as sbom_test_records
@ -262,22 +262,22 @@ class TestSalesOrder(unittest.TestCase):
frappe.db.set_default("allow_negative_stock", 1) frappe.db.set_default("allow_negative_stock", 1)
# set over-delivery tolerance # set over-delivery tolerance
frappe.db.set_value('Item', so.doclist[1].item_code, 'tolerance', 50) frappe.db.set_value('Item', so.get("sales_order_details")[0].item_code, 'tolerance', 50)
# submit dn # submit dn
dn = self.create_dn_against_so(so, 15) dn = self.create_dn_against_so(so, 15)
self.check_reserved_qty(sbom_test_records[0][1]["item_code"], self.check_reserved_qty(sbom_test_records[0][1]["item_code"],
so.doclist[1].warehouse, 0.0) so.get("sales_order_details")[0].warehouse, 0.0)
self.check_reserved_qty(sbom_test_records[0][2]["item_code"], self.check_reserved_qty(sbom_test_records[0][2]["item_code"],
so.doclist[1].warehouse, 0.0) so.get("sales_order_details")[0].warehouse, 0.0)
# cancel dn # cancel dn
dn.cancel() dn.cancel()
self.check_reserved_qty(sbom_test_records[0][1]["item_code"], self.check_reserved_qty(sbom_test_records[0][1]["item_code"],
so.doclist[1].warehouse, 50.0) so.get("sales_order_details")[0].warehouse, 50.0)
self.check_reserved_qty(sbom_test_records[0][2]["item_code"], self.check_reserved_qty(sbom_test_records[0][2]["item_code"],
so.doclist[1].warehouse, 20.0) so.get("sales_order_details")[0].warehouse, 20.0)
def test_warehouse_user(self): def test_warehouse_user(self):
frappe.defaults.add_default("Warehouse", "_Test Warehouse 1 - _TC1", "test@example.com", "Restriction") frappe.defaults.add_default("Warehouse", "_Test Warehouse 1 - _TC1", "test@example.com", "Restriction")
@ -293,7 +293,7 @@ class TestSalesOrder(unittest.TestCase):
so.company = "_Test Company 1" so.company = "_Test Company 1"
so.conversion_rate = 0.02 so.conversion_rate = 0.02
so.plc_conversion_rate = 0.02 so.plc_conversion_rate = 0.02
so.doclist[1].warehouse = "_Test Warehouse 2 - _TC1" so.get("sales_order_details")[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")

View File

@ -137,8 +137,7 @@ def feature_setup():
doc.save() doc.save()
def set_single_defaults(): def set_single_defaults():
for dt in frappe.db.sql_list("""select name from `tabDocType` for dt in frappe.db.sql_list("""select name from `tabDocType` where issingle=1"""):
where issingle=1 and parent != '__default'"""):
default_values = frappe.db.sql("""select fieldname, `default` from `tabDocField` default_values = frappe.db.sql("""select fieldname, `default` from `tabDocField`
where parent=%s""", dt) where parent=%s""", dt)
if default_values: if default_values:

View File

@ -3,16 +3,11 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe.utils import add_days, cint,flt, nowdate, get_url_to_form, formatdate from frappe.utils import flt, nowdate
from frappe import msgprint, _
import frappe.defaults import frappe.defaults
from frappe.model.document import Document from frappe.model.document import Document
class Bin(Document): class Bin(Document):
def validate(self): def validate(self):
if self.get("__islocal") or not self.stock_uom: if self.get("__islocal") or not self.stock_uom:
self.stock_uom = frappe.db.get_value('Item', self.item_code, 'stock_uom') self.stock_uom = frappe.db.get_value('Item', self.item_code, 'stock_uom')
@ -25,7 +20,7 @@ class Bin(Document):
def validate_mandatory(self): def validate_mandatory(self):
qf = ['actual_qty', 'reserved_qty', 'ordered_qty', 'indented_qty'] qf = ['actual_qty', 'reserved_qty', 'ordered_qty', 'indented_qty']
for f in qf: for f in qf:
if (not self.has_key(f)) or (not self.get(f)): if (not getattr(self, f, None)) or (not self.get(f)):
self.set(f, 0.0) self.set(f, 0.0)
def update_stock(self, args): def update_stock(self, args):
@ -47,6 +42,7 @@ class Bin(Document):
def update_qty(self, args): def update_qty(self, args):
# update the stock values (for current quantities) # update the stock values (for current quantities)
self.actual_qty = flt(self.actual_qty) + flt(args.get("actual_qty")) self.actual_qty = flt(self.actual_qty) + flt(args.get("actual_qty"))
self.ordered_qty = flt(self.ordered_qty) + flt(args.get("ordered_qty")) self.ordered_qty = flt(self.ordered_qty) + flt(args.get("ordered_qty"))
self.reserved_qty = flt(self.reserved_qty) + flt(args.get("reserved_qty")) self.reserved_qty = flt(self.reserved_qty) + flt(args.get("reserved_qty"))

View File

@ -313,7 +313,7 @@ def make_sales_invoice(source_name, target_doc=None):
"serial_no": "serial_no" "serial_no": "serial_no"
}, },
"postprocess": update_item, "postprocess": update_item,
"filter": lambda d: d.qty - invoiced_qty_map.get(d.name, 0)==0 "filter": lambda d: d.qty - invoiced_qty_map.get(d.name, 0)<=0
}, },
"Sales Taxes and Charges": { "Sales Taxes and Charges": {
"doctype": "Sales Taxes and Charges", "doctype": "Sales Taxes and Charges",

View File

@ -14,7 +14,7 @@ def _insert_purchase_receipt(item_code=None):
item_code = pr_test_records[0][1]["item_code"] item_code = pr_test_records[0][1]["item_code"]
pr = frappe.copy_doc(pr_test_records[0]) pr = frappe.copy_doc(pr_test_records[0])
pr.doclist[1].item_code = item_code pr.get("purchase_receipt_details")[0].item_code = item_code
pr.insert() pr.insert()
pr.submit() pr.submit()
@ -34,7 +34,7 @@ class TestDeliveryNote(unittest.TestCase):
dn.submit() dn.submit()
si = make_sales_invoice(dn.name) si = make_sales_invoice(dn.name)
self.assertEquals(len(si), len(dn.doclist)) self.assertEquals(len(si), len(dn))
# modify amount # modify amount
si[1]["rate"] = 200 si[1]["rate"] = 200
@ -69,11 +69,11 @@ class TestDeliveryNote(unittest.TestCase):
_insert_purchase_receipt() _insert_purchase_receipt()
dn = frappe.copy_doc(test_records[0]) dn = frappe.copy_doc(test_records[0])
dn.doclist[1].expense_account = "Cost of Goods Sold - _TC" dn.get("delivery_note_details")[0].expense_account = "Cost of Goods Sold - _TC"
dn.doclist[1].cost_center = "Main - _TC" dn.get("delivery_note_details")[0].cost_center = "Main - _TC"
stock_in_hand_account = frappe.db.get_value("Account", stock_in_hand_account = frappe.db.get_value("Account",
{"master_name": dn.doclist[1].warehouse}) {"master_name": dn.get("delivery_note_details")[0].warehouse})
from erpnext.accounts.utils import get_balance_on from erpnext.accounts.utils import get_balance_on
prev_bal = get_balance_on(stock_in_hand_account, dn.posting_date) prev_bal = get_balance_on(stock_in_hand_account, dn.posting_date)
@ -97,8 +97,8 @@ class TestDeliveryNote(unittest.TestCase):
# back dated purchase receipt # back dated purchase receipt
pr = frappe.copy_doc(pr_test_records[0]) pr = frappe.copy_doc(pr_test_records[0])
pr.posting_date = "2013-01-01" pr.posting_date = "2013-01-01"
pr.doclist[1].rate = 100 pr.get("purchase_receipt_details")[0].rate = 100
pr.doclist[1].base_amount = 100 pr.get("purchase_receipt_details")[0].base_amount = 100
pr.insert() pr.insert()
pr.submit() pr.submit()
@ -124,11 +124,11 @@ class TestDeliveryNote(unittest.TestCase):
_insert_purchase_receipt("_Test Item Home Desktop 100") _insert_purchase_receipt("_Test Item Home Desktop 100")
dn = frappe.copy_doc(test_records[0]) dn = frappe.copy_doc(test_records[0])
dn.doclist[1].item_code = "_Test Sales BOM Item" dn.get("delivery_note_details")[0].item_code = "_Test Sales BOM Item"
dn.doclist[1].qty = 1 dn.get("delivery_note_details")[0].qty = 1
stock_in_hand_account = frappe.db.get_value("Account", stock_in_hand_account = frappe.db.get_value("Account",
{"master_name": dn.doclist[1].warehouse}) {"master_name": dn.get("delivery_note_details")[0].warehouse})
from erpnext.accounts.utils import get_balance_on from erpnext.accounts.utils import get_balance_on
prev_bal = get_balance_on(stock_in_hand_account, dn.posting_date) prev_bal = get_balance_on(stock_in_hand_account, dn.posting_date)
@ -160,12 +160,12 @@ class TestDeliveryNote(unittest.TestCase):
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos 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.doclist[1].serial_no) serial_nos = get_serial_nos(se.get("mtn_details")[0].serial_no)
dn = frappe.copy_doc(test_records[0]) dn = frappe.copy_doc(test_records[0])
dn.doclist[1].item_code = "_Test Serialized Item With Series" dn.get("delivery_note_details")[0].item_code = "_Test Serialized Item With Series"
dn.doclist[1].qty = 1 dn.get("delivery_note_details")[0].qty = 1
dn.doclist[1].serial_no = serial_nos[0] dn.get("delivery_note_details")[0].serial_no = serial_nos[0]
dn.insert() dn.insert()
dn.submit() dn.submit()
@ -181,7 +181,7 @@ class TestDeliveryNote(unittest.TestCase):
dn = self.test_serialized() dn = self.test_serialized()
dn.cancel() dn.cancel()
serial_nos = get_serial_nos(dn.doclist[1].serial_no) serial_nos = get_serial_nos(dn.get("delivery_note_details")[0].serial_no)
self.assertEquals(frappe.db.get_value("Serial No", serial_nos[0], "status"), "Available") self.assertEquals(frappe.db.get_value("Serial No", serial_nos[0], "status"), "Available")
self.assertEquals(frappe.db.get_value("Serial No", serial_nos[0], "warehouse"), "_Test Warehouse - _TC") self.assertEquals(frappe.db.get_value("Serial No", serial_nos[0], "warehouse"), "_Test Warehouse - _TC")
@ -193,16 +193,16 @@ class TestDeliveryNote(unittest.TestCase):
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
se = make_serialized_item() se = make_serialized_item()
serial_nos = get_serial_nos(se.doclist[1].serial_no) serial_nos = get_serial_nos(se.get("mtn_details")[0].serial_no)
sr = frappe.get_doc("Serial No", serial_nos[0]) sr = frappe.get_doc("Serial No", serial_nos[0])
sr.status = "Not Available" sr.status = "Not Available"
sr.save() sr.save()
dn = frappe.copy_doc(test_records[0]) dn = frappe.copy_doc(test_records[0])
dn.doclist[1].item_code = "_Test Serialized Item With Series" dn.get("delivery_note_details")[0].item_code = "_Test Serialized Item With Series"
dn.doclist[1].qty = 1 dn.get("delivery_note_details")[0].qty = 1
dn.doclist[1].serial_no = serial_nos[0] dn.get("delivery_note_details")[0].serial_no = serial_nos[0]
dn.insert() dn.insert()
self.assertRaises(SerialNoStatusError, dn.submit) self.assertRaises(SerialNoStatusError, dn.submit)

View File

@ -25,7 +25,7 @@ class TestMaterialRequest(unittest.TestCase):
po = make_purchase_order(mr.name) po = make_purchase_order(mr.name)
self.assertEquals(po[0]["doctype"], "Purchase Order") self.assertEquals(po[0]["doctype"], "Purchase Order")
self.assertEquals(len(po), len(mr.doclist)) self.assertEquals(len(po), len(mr))
def test_make_supplier_quotation(self): def test_make_supplier_quotation(self):
from erpnext.stock.doctype.material_request.material_request import make_supplier_quotation from erpnext.stock.doctype.material_request.material_request import make_supplier_quotation
@ -40,7 +40,7 @@ class TestMaterialRequest(unittest.TestCase):
sq = make_supplier_quotation(mr.name) sq = make_supplier_quotation(mr.name)
self.assertEquals(sq[0]["doctype"], "Supplier Quotation") self.assertEquals(sq[0]["doctype"], "Supplier Quotation")
self.assertEquals(len(sq), len(mr.doclist)) self.assertEquals(len(sq), len(mr))
def test_make_stock_entry(self): def test_make_stock_entry(self):
@ -57,12 +57,12 @@ class TestMaterialRequest(unittest.TestCase):
se = make_stock_entry(mr.name) se = make_stock_entry(mr.name)
self.assertEquals(se[0]["doctype"], "Stock Entry") self.assertEquals(se[0]["doctype"], "Stock Entry")
self.assertEquals(len(se), len(mr.doclist)) self.assertEquals(len(se), len(mr))
def _test_expected(self, doclist, expected_values): def _test_expected(self, doc, expected_values):
for i, expected in enumerate(expected_values): for i, expected in enumerate(expected_values):
for fieldname, val in expected.items(): for fieldname, val in expected.items():
self.assertEquals(val, doclist[i].get(fieldname)) self.assertEquals(val, doc[i].get(fieldname))
def _test_requested_qty(self, qty1, qty2): def _test_requested_qty(self, qty1, qty2):
self.assertEqual(flt(frappe.db.get_value("Bin", {"item_code": "_Test Item Home Desktop 100", self.assertEqual(flt(frappe.db.get_value("Bin", {"item_code": "_Test Item Home Desktop 100",
@ -104,8 +104,7 @@ class TestMaterialRequest(unittest.TestCase):
"t_warehouse": "_Test Warehouse 1 - _TC", "t_warehouse": "_Test Warehouse 1 - _TC",
} }
] ]
}, })
])
se.insert() se.insert()
se.submit() se.submit()
@ -118,42 +117,42 @@ class TestMaterialRequest(unittest.TestCase):
mr.submit() mr.submit()
# check if per complete is None # check if per complete is None
self._test_expected(mr.doclist, [{"per_ordered": None}, {"ordered_qty": None}, {"ordered_qty": None}]) self._test_expected(mr, [{"per_ordered": None}, {"ordered_qty": None}, {"ordered_qty": None}])
self._test_requested_qty(54.0, 3.0) self._test_requested_qty(54.0, 3.0)
# map a purchase order # map a purchase order
from erpnext.stock.doctype.material_request.material_request import make_purchase_order from erpnext.stock.doctype.material_request.material_request import make_purchase_order
po_doclist = make_purchase_order(mr.name) po_doc = make_purchase_order(mr.name)
po_doclist[0]["supplier"] = "_Test Supplier" po_doc["supplier"] = "_Test Supplier"
po_doclist[0]["transaction_date"] = "2013-07-07" po_doc["transaction_date"] = "2013-07-07"
po_doclist[1]["qty"] = 27.0 po_doc.get("po_details")[0]["qty"] = 27.0
po_doclist[2]["qty"] = 1.5 po_doc.get("po_details")[1]["qty"] = 1.5
po_doclist[1]["schedule_date"] = "2013-07-09" po_doc.get("po_details")[0]["schedule_date"] = "2013-07-09"
po_doclist[2]["schedule_date"] = "2013-07-09" po_doc.get("po_details")[1]["schedule_date"] = "2013-07-09"
# check for stopped status of Material Request # check for stopped status of Material Request
po = frappe.copy_doc(po_doclist) po = frappe.copy_doc(po_doc)
po.insert() po.insert()
mr.obj.update_status('Stopped') mr.obj.update_status('Stopped')
self.assertRaises(frappe.ValidationError, po.submit) self.assertRaises(frappe.ValidationError, po.submit)
self.assertRaises(frappe.ValidationError, po.cancel) self.assertRaises(frappe.ValidationError, po.cancel)
mr.obj.update_status('Submitted') mr.obj.update_status('Submitted')
po = frappe.copy_doc(po_doclist) po = frappe.copy_doc(po_doc)
po.insert() po.insert()
po.submit() po.submit()
# check if per complete is as expected # check if per complete is as expected
mr.load_from_db() mr.load_from_db()
self._test_expected(mr.doclist, [{"per_ordered": 50}, {"ordered_qty": 27.0}, {"ordered_qty": 1.5}]) self._test_expected(mr, [{"per_ordered": 50}, {"ordered_qty": 27.0}, {"ordered_qty": 1.5}])
self._test_requested_qty(27.0, 1.5) self._test_requested_qty(27.0, 1.5)
po.cancel() po.cancel()
# check if per complete is as expected # check if per complete is as expected
mr.load_from_db() mr.load_from_db()
self._test_expected(mr.doclist, [{"per_ordered": None}, {"ordered_qty": None}, {"ordered_qty": None}]) self._test_expected(mr, [{"per_ordered": None}, {"ordered_qty": None}, {"ordered_qty": None}])
self._test_requested_qty(54.0, 3.0) self._test_requested_qty(54.0, 3.0)
def test_completed_qty_for_transfer(self): def test_completed_qty_for_transfer(self):
@ -167,26 +166,26 @@ class TestMaterialRequest(unittest.TestCase):
mr.submit() mr.submit()
# check if per complete is None # check if per complete is None
self._test_expected(mr.doclist, [{"per_ordered": None}, {"ordered_qty": None}, {"ordered_qty": None}]) self._test_expected(mr, [{"per_ordered": None}, {"ordered_qty": None}, {"ordered_qty": None}])
self._test_requested_qty(54.0, 3.0) self._test_requested_qty(54.0, 3.0)
from erpnext.stock.doctype.material_request.material_request import make_stock_entry from erpnext.stock.doctype.material_request.material_request import make_stock_entry
# map a stock entry # map a stock entry
se_doclist = make_stock_entry(mr.name) se_doc = make_stock_entry(mr.name)
se_doclist[0].update({ se_doc.update({
"posting_date": "2013-03-01", "posting_date": "2013-03-01",
"posting_time": "01:00", "posting_time": "01:00",
"fiscal_year": "_Test Fiscal Year 2013", "fiscal_year": "_Test Fiscal Year 2013",
}) })
se_doclist[1].update({ se_doc.get("mtn_details")[0].update({
"qty": 27.0, "qty": 27.0,
"transfer_qty": 27.0, "transfer_qty": 27.0,
"s_warehouse": "_Test Warehouse 1 - _TC", "s_warehouse": "_Test Warehouse 1 - _TC",
"incoming_rate": 1.0 "incoming_rate": 1.0
}) })
se_doclist[2].update({ se_doc.get("mtn_details")[1].update({
"qty": 1.5, "qty": 1.5,
"transfer_qty": 1.5, "transfer_qty": 1.5,
"s_warehouse": "_Test Warehouse 1 - _TC", "s_warehouse": "_Test Warehouse 1 - _TC",
@ -197,26 +196,26 @@ class TestMaterialRequest(unittest.TestCase):
self._insert_stock_entry(27.0, 1.5) self._insert_stock_entry(27.0, 1.5)
# check for stopped status of Material Request # check for stopped status of Material Request
se = frappe.copy_doc(se_doclist) se = frappe.copy_doc(se_doc)
se.insert() se.insert()
mr.obj.update_status('Stopped') mr.obj.update_status('Stopped')
self.assertRaises(frappe.ValidationError, se.submit) self.assertRaises(frappe.ValidationError, se.submit)
self.assertRaises(frappe.ValidationError, se.cancel) self.assertRaises(frappe.ValidationError, se.cancel)
mr.obj.update_status('Submitted') mr.obj.update_status('Submitted')
se = frappe.copy_doc(se_doclist) se = frappe.copy_doc(se_doc)
se.insert() se.insert()
se.submit() se.submit()
# check if per complete is as expected # check if per complete is as expected
mr.load_from_db() mr.load_from_db()
self._test_expected(mr.doclist, [{"per_ordered": 50}, {"ordered_qty": 27.0}, {"ordered_qty": 1.5}]) self._test_expected(mr, [{"per_ordered": 50}, {"ordered_qty": 27.0}, {"ordered_qty": 1.5}])
self._test_requested_qty(27.0, 1.5) self._test_requested_qty(27.0, 1.5)
# check if per complete is as expected for Stock Entry cancelled # check if per complete is as expected for Stock Entry cancelled
se.cancel() se.cancel()
mr.load_from_db() mr.load_from_db()
self._test_expected(mr.doclist, [{"per_ordered": 0}, {"ordered_qty": 0}, {"ordered_qty": 0}]) self._test_expected(mr, [{"per_ordered": 0}, {"ordered_qty": 0}, {"ordered_qty": 0}])
self._test_requested_qty(54.0, 3.0) self._test_requested_qty(54.0, 3.0)
def test_completed_qty_for_over_transfer(self): def test_completed_qty_for_over_transfer(self):
@ -230,26 +229,26 @@ class TestMaterialRequest(unittest.TestCase):
mr.submit() mr.submit()
# check if per complete is None # check if per complete is None
self._test_expected(mr.doclist, [{"per_ordered": None}, {"ordered_qty": None}, {"ordered_qty": None}]) self._test_expected(mr, [{"per_ordered": None}, {"ordered_qty": None}, {"ordered_qty": None}])
self._test_requested_qty(54.0, 3.0) self._test_requested_qty(54.0, 3.0)
# map a stock entry # map a stock entry
from erpnext.stock.doctype.material_request.material_request import make_stock_entry from erpnext.stock.doctype.material_request.material_request import make_stock_entry
se_doclist = make_stock_entry(mr.name) se_doc = make_stock_entry(mr.name)
se_doclist[0].update({ se_doc.update({
"posting_date": "2013-03-01", "posting_date": "2013-03-01",
"posting_time": "00:00", "posting_time": "00:00",
"fiscal_year": "_Test Fiscal Year 2013", "fiscal_year": "_Test Fiscal Year 2013",
}) })
se_doclist[1].update({ se_doc.get("mtn_details")[0].update({
"qty": 60.0, "qty": 60.0,
"transfer_qty": 60.0, "transfer_qty": 60.0,
"s_warehouse": "_Test Warehouse 1 - _TC", "s_warehouse": "_Test Warehouse 1 - _TC",
"incoming_rate": 1.0 "incoming_rate": 1.0
}) })
se_doclist[2].update({ se_doc.get("mtn_details")[1].update({
"qty": 3.0, "qty": 3.0,
"transfer_qty": 3.0, "transfer_qty": 3.0,
"s_warehouse": "_Test Warehouse 1 - _TC", "s_warehouse": "_Test Warehouse 1 - _TC",
@ -260,26 +259,26 @@ class TestMaterialRequest(unittest.TestCase):
self._insert_stock_entry(60.0, 3.0) self._insert_stock_entry(60.0, 3.0)
# check for stopped status of Material Request # check for stopped status of Material Request
se = frappe.copy_doc(se_doclist) se = frappe.copy_doc(se_doc)
se.insert() se.insert()
mr.obj.update_status('Stopped') mr.obj.update_status('Stopped')
self.assertRaises(frappe.ValidationError, se.submit) self.assertRaises(frappe.ValidationError, se.submit)
self.assertRaises(frappe.ValidationError, se.cancel) self.assertRaises(frappe.ValidationError, se.cancel)
mr.obj.update_status('Submitted') mr.obj.update_status('Submitted')
se = frappe.copy_doc(se_doclist) se = frappe.copy_doc(se_doc)
se.insert() se.insert()
se.submit() se.submit()
# check if per complete is as expected # check if per complete is as expected
mr.load_from_db() mr.load_from_db()
self._test_expected(mr.doclist, [{"per_ordered": 100}, {"ordered_qty": 60.0}, {"ordered_qty": 3.0}]) self._test_expected(mr, [{"per_ordered": 100}, {"ordered_qty": 60.0}, {"ordered_qty": 3.0}])
self._test_requested_qty(0.0, 0.0) self._test_requested_qty(0.0, 0.0)
# check if per complete is as expected for Stock Entry cancelled # check if per complete is as expected for Stock Entry cancelled
se.cancel() se.cancel()
mr.load_from_db() mr.load_from_db()
self._test_expected(mr.doclist, [{"per_ordered": 0}, {"ordered_qty": 0}, {"ordered_qty": 0}]) self._test_expected(mr, [{"per_ordered": 0}, {"ordered_qty": 0}, {"ordered_qty": 0}])
self._test_requested_qty(54.0, 3.0) self._test_requested_qty(54.0, 3.0)
def test_incorrect_mapping_of_stock_entry(self): def test_incorrect_mapping_of_stock_entry(self):
@ -292,20 +291,20 @@ class TestMaterialRequest(unittest.TestCase):
# map a stock entry # map a stock entry
from erpnext.stock.doctype.material_request.material_request import make_stock_entry from erpnext.stock.doctype.material_request.material_request import make_stock_entry
se_doclist = make_stock_entry(mr.name) se_doc = make_stock_entry(mr.name)
se_doclist[0].update({ se_doc.update({
"posting_date": "2013-03-01", "posting_date": "2013-03-01",
"posting_time": "00:00", "posting_time": "00:00",
"fiscal_year": "_Test Fiscal Year 2013", "fiscal_year": "_Test Fiscal Year 2013",
}) })
se_doclist[1].update({ se_doc.get("mtn_details")[0].update({
"qty": 60.0, "qty": 60.0,
"transfer_qty": 60.0, "transfer_qty": 60.0,
"s_warehouse": "_Test Warehouse - _TC", "s_warehouse": "_Test Warehouse - _TC",
"t_warehouse": "_Test Warehouse 1 - _TC", "t_warehouse": "_Test Warehouse 1 - _TC",
"incoming_rate": 1.0 "incoming_rate": 1.0
}) })
se_doclist[2].update({ se_doc.get("mtn_details")[1].update({
"qty": 3.0, "qty": 3.0,
"transfer_qty": 3.0, "transfer_qty": 3.0,
"s_warehouse": "_Test Warehouse 1 - _TC", "s_warehouse": "_Test Warehouse 1 - _TC",
@ -313,7 +312,7 @@ class TestMaterialRequest(unittest.TestCase):
}) })
# check for stopped status of Material Request # check for stopped status of Material Request
se = frappe.copy_doc(se_doclist) se = frappe.copy_doc(se_doc)
self.assertRaises(frappe.MappingMismatchError, se.insert) self.assertRaises(frappe.MappingMismatchError, se.insert)
def test_warehouse_company_validation(self): def test_warehouse_company_validation(self):

View File

@ -53,7 +53,7 @@ def update_packing_list_item(obj, packing_item_code, qty, warehouse, line, packi
if not pi.warehouse: if not pi.warehouse:
pi.warehouse = warehouse pi.warehouse = warehouse
if not pi.batch_no: if not pi.batch_no:
pi.batch_no = cstr(line.batch_no) pi.batch_no = cstr(line.get("batch_no"))
pi.idx = packing_list_idx pi.idx = packing_list_idx
packing_list_idx += 1 packing_list_idx += 1

View File

@ -23,11 +23,11 @@ class TestPurchaseReceipt(unittest.TestCase):
pr.submit() pr.submit()
pi = make_purchase_invoice(pr.name) pi = make_purchase_invoice(pr.name)
self.assertEquals(pi[0]["doctype"], "Purchase Invoice") self.assertEquals(pi["doctype"], "Purchase Invoice")
self.assertEquals(len(pi), len(pr.doclist)) self.assertEquals(len(pi.get("entries")), len(pr.get("purchase_receipt_details")))
# modify rate # modify rate
pi[1]["rate"] = 200 pi.get("entries")[0]["rate"] = 200
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):
@ -65,9 +65,9 @@ class TestPurchaseReceipt(unittest.TestCase):
self.assertTrue(gl_entries) self.assertTrue(gl_entries)
stock_in_hand_account = frappe.db.get_value("Account", stock_in_hand_account = frappe.db.get_value("Account",
{"master_name": pr.doclist[1].warehouse}) {"master_name": pr.get("purchase_receipt_details")[0].warehouse})
fixed_asset_account = frappe.db.get_value("Account", fixed_asset_account = frappe.db.get_value("Account",
{"master_name": pr.doclist[2].warehouse}) {"master_name": pr.get("purchase_receipt_details")[1].warehouse})
expected_values = { expected_values = {
stock_in_hand_account: [375.0, 0.0], stock_in_hand_account: [375.0, 0.0],
@ -94,18 +94,18 @@ class TestPurchaseReceipt(unittest.TestCase):
pr.run_method("calculate_taxes_and_totals") pr.run_method("calculate_taxes_and_totals")
pr.insert() pr.insert()
self.assertEquals(pr.doclist[1].rm_supp_cost, 70000.0) self.assertEquals(pr.get("purchase_receipt_details")[0].rm_supp_cost, 70000.0)
self.assertEquals(len(pr.get("pr_raw_material_details")), 2) self.assertEquals(len(pr.get("pr_raw_material_details")), 2)
def test_serial_no_supplier(self): def test_serial_no_supplier(self):
pr = frappe.copy_doc(test_records[0]) pr = frappe.copy_doc(test_records[0])
pr.doclist[1].item_code = "_Test Serialized Item With Series" pr.get("purchase_receipt_details")[0].item_code = "_Test Serialized Item With Series"
pr.doclist[1].qty = 1 pr.get("purchase_receipt_details")[0].qty = 1
pr.doclist[1].received_qty = 1 pr.get("purchase_receipt_details")[0].received_qty = 1
pr.insert() pr.insert()
pr.submit() pr.submit()
self.assertEquals(frappe.db.get_value("Serial No", pr.doclist[1].serial_no, self.assertEquals(frappe.db.get_value("Serial No", pr.get("purchase_receipt_details")[0].serial_no,
"supplier"), pr.supplier) "supplier"), pr.supplier)
return pr return pr
@ -114,7 +114,7 @@ class TestPurchaseReceipt(unittest.TestCase):
pr = self.test_serial_no_supplier() pr = self.test_serial_no_supplier()
pr.cancel() pr.cancel()
self.assertFalse(frappe.db.get_value("Serial No", pr.doclist[1].serial_no, self.assertFalse(frappe.db.get_value("Serial No", pr.get("purchase_receipt_details")[0].serial_no,
"warehouse")) "warehouse"))
def get_gl_entries(voucher_type, voucher_no): def get_gl_entries(voucher_type, voucher_no):

View File

@ -284,6 +284,7 @@ def make_serial_no(serial_no, sle):
sr.serial_no = serial_no sr.serial_no = serial_no
sr.item_code = sle.item_code sr.item_code = sle.item_code
sr.warehouse = None sr.warehouse = None
sr.company = sle.company
sr.via_stock_ledger = True sr.via_stock_ledger = True
sr.insert() sr.insert()
sr.warehouse = sle.warehouse sr.warehouse = sle.warehouse

View File

@ -277,7 +277,7 @@ class StockEntry(StockController):
raise_exception=frappe.DoesNotExistError) raise_exception=frappe.DoesNotExistError)
# validate quantity <= ref item's qty - qty already returned # validate quantity <= ref item's qty - qty already returned
ref_item = ref.getone({"item_code": item.item_code}) ref_item = ref.doc.getone({"item_code": item.item_code})
returnable_qty = ref_item.qty - flt(already_returned_item_qty.get(item.item_code)) returnable_qty = ref_item.qty - flt(already_returned_item_qty.get(item.item_code))
if not returnable_qty: if not returnable_qty:
frappe.throw("{item}: {item_code} {returned}".format( frappe.throw("{item}: {item_code} {returned}".format(
@ -710,7 +710,7 @@ def get_stock_items_for_return(ref_doc, parentfields):
parentfields = [parentfields] parentfields = [parentfields]
all_items = list(set([d.item_code for d in all_items = list(set([d.item_code for d in
ref_doc.get_all_children() if d.item_code])) ref_doc.get_all_children() if d.get("item_code")]))
stock_items = frappe.db.sql_list("""select name from `tabItem` stock_items = frappe.db.sql_list("""select name from `tabItem`
where is_stock_item='Yes' and name in (%s)""" % (", ".join(["%s"] * len(all_items))), where is_stock_item='Yes' and name in (%s)""" % (", ".join(["%s"] * len(all_items))),
tuple(all_items)) tuple(all_items))
@ -720,9 +720,9 @@ def get_stock_items_for_return(ref_doc, parentfields):
def get_return_doc_and_details(args): def get_return_doc_and_details(args):
ref = frappe._dict() ref = frappe._dict()
# get ref_doc # get ref_doc
if args.get("purpose") in return_map: if args.get("purpose") in return_map:
for fieldname, val in return_map[args["purpose"]].items(): for fieldname, val in return_map[args.get("purpose")].items():
if args.get(fieldname): if args.get(fieldname):
ref.fieldname = fieldname ref.fieldname = fieldname
ref.doc = frappe.get_doc(val[0], args.get(fieldname)) ref.doc = frappe.get_doc(val[0], args.get(fieldname))

View File

@ -3,7 +3,7 @@
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, getdate
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
from erpnext.stock.doctype.stock_ledger_entry.stock_ledger_entry import StockFreezeError from erpnext.stock.doctype.stock_ledger_entry.stock_ledger_entry import StockFreezeError
@ -29,7 +29,7 @@ class TestStockEntry(unittest.TestCase):
st2 = frappe.copy_doc(test_records[1]) st2 = frappe.copy_doc(test_records[1])
st2.insert() st2.insert()
st2.submit() st2.submit()
from erpnext.stock.utils import reorder_item from erpnext.stock.utils import reorder_item
reorder_item() reorder_item()
@ -50,7 +50,7 @@ class TestStockEntry(unittest.TestCase):
mr.submit() 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",
"master_name": mr.doclist[1].t_warehouse}) "master_name": mr.get("mtn_details")[0].t_warehouse})
self.check_stock_ledger_entries("Stock Entry", mr.name, self.check_stock_ledger_entries("Stock Entry", mr.name,
[["_Test Item", "_Test Warehouse - _TC", 50.0]]) [["_Test Item", "_Test Warehouse - _TC", 50.0]])
@ -85,7 +85,7 @@ class TestStockEntry(unittest.TestCase):
[["_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",
"master_name": mi.doclist[1].s_warehouse}) "master_name": mi.get("mtn_details")[0].s_warehouse})
self.check_gl_entries("Stock Entry", mi.name, self.check_gl_entries("Stock Entry", mi.name,
sorted([ sorted([
@ -101,11 +101,11 @@ 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""", mi.name)) where voucher_type='Stock Entry' and voucher_no=%s""", mi.name))
self.assertEquals(frappe.db.get_value("Bin", {"warehouse": mi.doclist[1].s_warehouse, self.assertEquals(frappe.db.get_value("Bin", {"warehouse": mi.get("mtn_details")[0].s_warehouse,
"item_code": mi.doclist[1].item_code}, "actual_qty"), 50) "item_code": mi.get("mtn_details")[0].item_code}, "actual_qty"), 50)
self.assertEquals(frappe.db.get_value("Bin", {"warehouse": mi.doclist[1].s_warehouse, self.assertEquals(frappe.db.get_value("Bin", {"warehouse": mi.get("mtn_details")[0].s_warehouse,
"item_code": mi.doclist[1].item_code}, "stock_value"), 5000) "item_code": mi.get("mtn_details")[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() self._clear_stock_account_balance()
@ -121,10 +121,10 @@ class TestStockEntry(unittest.TestCase):
[["_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]])
stock_in_hand_account = frappe.db.get_value("Account", {"account_type": "Warehouse", stock_in_hand_account = frappe.db.get_value("Account", {"account_type": "Warehouse",
"master_name": mtn.doclist[1].s_warehouse}) "master_name": mtn.get("mtn_details")[0].s_warehouse})
fixed_asset_account = frappe.db.get_value("Account", {"account_type": "Warehouse", fixed_asset_account = frappe.db.get_value("Account", {"account_type": "Warehouse",
"master_name": mtn.doclist[1].t_warehouse}) "master_name": mtn.get("mtn_details")[0].t_warehouse})
self.check_gl_entries("Stock Entry", mtn.name, self.check_gl_entries("Stock Entry", mtn.name,
@ -171,12 +171,12 @@ class TestStockEntry(unittest.TestCase):
self._insert_material_receipt() self._insert_material_receipt()
repack = frappe.copy_doc(test_records[3]) repack = frappe.copy_doc(test_records[3])
repack.doclist[2].incoming_rate = 6000 repack.get("mtn_details")[1].incoming_rate = 6000
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",
"master_name": repack.doclist[2].t_warehouse}) "master_name": repack.get("mtn_details")[1].t_warehouse})
self.check_gl_entries("Stock Entry", repack.name, self.check_gl_entries("Stock Entry", repack.name,
sorted([ sorted([
@ -223,7 +223,7 @@ class TestStockEntry(unittest.TestCase):
se1.submit() se1.submit()
se2 = frappe.copy_doc(test_records[0]) se2 = frappe.copy_doc(test_records[0])
se2.doclist[1].item_code = "_Test Item Home Desktop 100" se2.get("mtn_details")[0].item_code = "_Test Item Home Desktop 100"
se2.insert() se2.insert()
se2.submit() se2.submit()
@ -235,7 +235,7 @@ class TestStockEntry(unittest.TestCase):
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.stock.doctype.stock_entry.stock_entry import NotUpdateStockError
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice \ from erpnext.accounts.doctype.sales_invoice.test_sales_invoice \
import test_records as sales_invoice_test_records import test_records as sales_invoice_test_records
@ -247,8 +247,8 @@ class TestStockEntry(unittest.TestCase):
se = frappe.copy_doc(test_records[0]) se = frappe.copy_doc(test_records[0])
se.purpose = "Sales Return" se.purpose = "Sales Return"
se.sales_invoice_no = si.name se.sales_invoice_no = si.name
se.doclist[1].qty = returned_qty se.get("mtn_details")[0].qty = returned_qty
se.doclist[1].transfer_qty = returned_qty se.get("mtn_details")[0].transfer_qty = returned_qty
self.assertRaises(NotUpdateStockError, se.insert) self.assertRaises(NotUpdateStockError, se.insert)
self._insert_material_receipt() self._insert_material_receipt()
@ -259,9 +259,9 @@ class TestStockEntry(unittest.TestCase):
# insert a pos invoice with update stock # insert a pos invoice with update stock
si = frappe.copy_doc(sales_invoice_test_records[1]) si = frappe.copy_doc(sales_invoice_test_records[1])
si.is_pos = si.update_stock = 1 si.is_pos = si.update_stock = 1
si.doclist[1].warehouse = "_Test Warehouse - _TC" si.get("entries")[0].warehouse = "_Test Warehouse - _TC"
si.doclist[1].item_code = item_code si.get("entries")[0].item_code = item_code
si.doclist[1].qty = 5.0 si.get("entries")[0].qty = 5.0
si.insert() si.insert()
si.submit() si.submit()
@ -276,9 +276,9 @@ class TestStockEntry(unittest.TestCase):
se.sales_invoice_no = si.name se.sales_invoice_no = si.name
se.posting_date = "2013-03-10" se.posting_date = "2013-03-10"
se.fiscal_year = "_Test Fiscal Year 2013" se.fiscal_year = "_Test Fiscal Year 2013"
se.doclist[1].item_code = "_Test Item Home Desktop 200" se.get("mtn_details")[0].item_code = "_Test Item Home Desktop 200"
se.doclist[1].qty = returned_qty se.get("mtn_details")[0].qty = returned_qty
se.doclist[1].transfer_qty = returned_qty se.get("mtn_details")[0].transfer_qty = returned_qty
# check if stock entry gets submitted # check if stock entry gets submitted
self.assertRaises(frappe.DoesNotExistError, se.insert) self.assertRaises(frappe.DoesNotExistError, se.insert)
@ -289,8 +289,8 @@ class TestStockEntry(unittest.TestCase):
se.posting_date = "2013-03-10" se.posting_date = "2013-03-10"
se.fiscal_year = "_Test Fiscal Year 2013" se.fiscal_year = "_Test Fiscal Year 2013"
se.sales_invoice_no = si.name se.sales_invoice_no = si.name
se.doclist[1].qty = returned_qty se.get("mtn_details")[0].qty = returned_qty
se.doclist[1].transfer_qty = returned_qty se.get("mtn_details")[0].transfer_qty = returned_qty
# in both cases item code remains _Test Item when returning # in both cases item code remains _Test Item when returning
se.insert() se.insert()
@ -322,7 +322,7 @@ class TestStockEntry(unittest.TestCase):
actual_qty_0 = self._get_actual_qty() actual_qty_0 = self._get_actual_qty()
# make a delivery note based on this invoice # make a delivery note based on this invoice
dn = frappe.copy_doc(delivery_note_test_records[0]) dn = frappe.copy_doc(delivery_note_test_records[0])
dn.doclist[1].item_code = item_code dn.get("delivery_note_details")[0].item_code = item_code
dn.insert() dn.insert()
dn.submit() dn.submit()
@ -330,9 +330,9 @@ class TestStockEntry(unittest.TestCase):
self.assertEquals(actual_qty_0 - delivered_qty, actual_qty_1) self.assertEquals(actual_qty_0 - delivered_qty, actual_qty_1)
si_doclist = make_sales_invoice(dn.name) si_doc = make_sales_invoice(dn.name)
si = frappe.get_doc(si_doclist) si = frappe.get_doc(si_doc)
si.posting_date = dn.posting_date si.posting_date = dn.posting_date
si.debit_to = "_Test Customer - _TC" si.debit_to = "_Test Customer - _TC"
for d in si.get("entries"): for d in si.get("entries"):
@ -347,7 +347,7 @@ class TestStockEntry(unittest.TestCase):
se.delivery_note_no = dn.name se.delivery_note_no = dn.name
se.posting_date = "2013-03-10" se.posting_date = "2013-03-10"
se.fiscal_year = "_Test Fiscal Year 2013" se.fiscal_year = "_Test Fiscal Year 2013"
se.doclist[1].qty = se.doclist[1].transfer_qty = returned_qty se.get("mtn_details")[0].qty = se.get("mtn_details")[0].transfer_qty = returned_qty
se.insert() se.insert()
se.submit() se.submit()
@ -409,28 +409,25 @@ class TestStockEntry(unittest.TestCase):
from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice, make_delivery_note from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice, make_delivery_note
actual_qty_0 = self._get_actual_qty() actual_qty_0 = self._get_actual_qty()
so = frappe.copy_doc(sales_order_test_records[0]) so = frappe.copy_doc(sales_order_test_records[0])
so.doclist[1].item_code = item_code so.get("sales_order_details")[0].item_code = item_code
so.doclist[1].qty = 5.0 so.get("sales_order_details")[0].qty = 5.0
so.insert() so.insert()
so.submit() so.submit()
dn_doc = make_delivery_note(so.name)
dn_doclist = make_delivery_note(so.name) dn = frappe.get_doc(dn_doc)
dn = frappe.get_doc(dn_doclist)
dn.status = "Draft" dn.status = "Draft"
dn.posting_date = so.delivery_date dn.posting_date = so.delivery_date
dn.insert() dn.insert()
dn.submit() dn.submit()
actual_qty_1 = self._get_actual_qty() 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_doclist = make_sales_invoice(so.name) si_doc = make_sales_invoice(so.name)
si = frappe.get_doc(si_doclist) si = frappe.get_doc(si_doc)
si.posting_date = dn.posting_date si.posting_date = dn.posting_date
si.debit_to = "_Test Customer - _TC" si.debit_to = "_Test Customer - _TC"
for d in si.get("entries"): for d in si.get("entries"):
@ -445,7 +442,7 @@ class TestStockEntry(unittest.TestCase):
se.delivery_note_no = dn.name se.delivery_note_no = dn.name
se.posting_date = "2013-03-10" se.posting_date = "2013-03-10"
se.fiscal_year = "_Test Fiscal Year 2013" se.fiscal_year = "_Test Fiscal Year 2013"
se.doclist[1].qty = se.doclist[1].transfer_qty = returned_qty se.get("mtn_details")[0].qty = se.get("mtn_details")[0].transfer_qty = returned_qty
se.insert() se.insert()
se.submit() se.submit()
@ -464,7 +461,7 @@ class TestStockEntry(unittest.TestCase):
import test_records as purchase_receipt_test_records import test_records as purchase_receipt_test_records
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchase_invoice 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 = frappe.copy_doc(purchase_receipt_test_records[0])
pr.insert() pr.insert()
@ -474,9 +471,9 @@ class TestStockEntry(unittest.TestCase):
self.assertEquals(actual_qty_0 + 5, actual_qty_1) self.assertEquals(actual_qty_0 + 5, actual_qty_1)
pi_doclist = make_purchase_invoice(pr.name) pi_doc = make_purchase_invoice(pr.name)
pi = frappe.get_doc(pi_doclist) pi = frappe.get_doc(pi_doc)
pi.posting_date = pr.posting_date pi.posting_date = pr.posting_date
pi.credit_to = "_Test Supplier - _TC" pi.credit_to = "_Test Supplier - _TC"
for d in pi.get("entries"): for d in pi.get("entries"):
@ -497,8 +494,8 @@ class TestStockEntry(unittest.TestCase):
se.purchase_receipt_no = pr.name se.purchase_receipt_no = pr.name
se.posting_date = "2013-03-01" se.posting_date = "2013-03-01"
se.fiscal_year = "_Test Fiscal Year 2013" se.fiscal_year = "_Test Fiscal Year 2013"
se.doclist[1].qty = se.doclist[1].transfer_qty = 5 se.get("mtn_details")[0].qty = se.get("mtn_details")[0].transfer_qty = 5
se.doclist[1].s_warehouse = "_Test Warehouse - _TC" se.get("mtn_details")[0].s_warehouse = "_Test Warehouse - _TC"
se.insert() se.insert()
se.submit() se.submit()
@ -523,8 +520,8 @@ class TestStockEntry(unittest.TestCase):
se.purchase_receipt_no = pr_docname se.purchase_receipt_no = pr_docname
se.posting_date = "2013-03-01" se.posting_date = "2013-03-01"
se.fiscal_year = "_Test Fiscal Year 2013" se.fiscal_year = "_Test Fiscal Year 2013"
se.doclist[1].qty = se.doclist[1].transfer_qty = 6 se.get("mtn_details")[0].qty = se.get("mtn_details")[0].transfer_qty = 6
se.doclist[1].s_warehouse = "_Test Warehouse - _TC" se.get("mtn_details")[0].s_warehouse = "_Test Warehouse - _TC"
self.assertRaises(StockOverReturnError, se.insert) self.assertRaises(StockOverReturnError, se.insert)
@ -551,24 +548,24 @@ class TestStockEntry(unittest.TestCase):
self._clear_stock_account_balance() self._clear_stock_account_balance()
actual_qty_0 = self._get_actual_qty() actual_qty_0 = self._get_actual_qty()
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
from erpnext.buying.doctype.purchase_order.purchase_order import \ from erpnext.buying.doctype.purchase_order.purchase_order import \
make_purchase_receipt, make_purchase_invoice make_purchase_receipt, make_purchase_invoice
# 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.is_subcontracted = None po.is_subcontracted = None
po.doclist[1].item_code = "_Test Item" po.get("po_details")[0].item_code = "_Test Item"
po.doclist[1].rate = 50 po.get("po_details")[0].rate = 50
po.insert() po.insert()
po.submit() po.submit()
pr_doclist = make_purchase_receipt(po.name) pr_doc = make_purchase_receipt(po.name)
pr = frappe.get_doc(pr_doclist) pr = frappe.get_doc(pr_doc)
pr.posting_date = po.transaction_date pr.posting_date = po.transaction_date
pr.insert() pr.insert()
pr.submit() pr.submit()
@ -577,9 +574,9 @@ class TestStockEntry(unittest.TestCase):
self.assertEquals(actual_qty_0 + 10, actual_qty_1) self.assertEquals(actual_qty_0 + 10, actual_qty_1)
pi_doclist = make_purchase_invoice(po.name) pi_doc = make_purchase_invoice(po.name)
pi = frappe.get_doc(pi_doclist) pi = frappe.get_doc(pi_doc)
pi.posting_date = pr.posting_date pi.posting_date = pr.posting_date
pi.credit_to = "_Test Supplier - _TC" pi.credit_to = "_Test Supplier - _TC"
for d in pi.get("entries"): for d in pi.get("entries"):
@ -599,8 +596,8 @@ class TestStockEntry(unittest.TestCase):
se.purchase_receipt_no = pr.name se.purchase_receipt_no = pr.name
se.posting_date = "2013-03-01" se.posting_date = "2013-03-01"
se.fiscal_year = "_Test Fiscal Year 2013" se.fiscal_year = "_Test Fiscal Year 2013"
se.doclist[1].qty = se.doclist[1].transfer_qty = 5 se.get("mtn_details")[0].qty = se.get("mtn_details")[0].transfer_qty = 5
se.doclist[1].s_warehouse = "_Test Warehouse - _TC" se.get("mtn_details")[0].s_warehouse = "_Test Warehouse - _TC"
se.insert() se.insert()
se.submit() se.submit()
@ -622,43 +619,43 @@ class TestStockEntry(unittest.TestCase):
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.doclist[1].serial_no = "ABCD" se.get("mtn_details")[0].serial_no = "ABCD"
se.insert() se.insert()
self.assertRaises(SerialNoNotRequiredError, se.submit) self.assertRaises(SerialNoNotRequiredError, se.submit)
def test_serial_no_reqd(self): def test_serial_no_reqd(self):
se = frappe.copy_doc(test_records[0]) se = frappe.copy_doc(test_records[0])
se.doclist[1].item_code = "_Test Serialized Item" se.get("mtn_details")[0].item_code = "_Test Serialized Item"
se.doclist[1].qty = 2 se.get("mtn_details")[0].qty = 2
se.doclist[1].transfer_qty = 2 se.get("mtn_details")[0].transfer_qty = 2
se.insert() se.insert()
self.assertRaises(SerialNoRequiredError, se.submit) self.assertRaises(SerialNoRequiredError, se.submit)
def test_serial_no_qty_more(self): def test_serial_no_qty_more(self):
se = frappe.copy_doc(test_records[0]) se = frappe.copy_doc(test_records[0])
se.doclist[1].item_code = "_Test Serialized Item" se.get("mtn_details")[0].item_code = "_Test Serialized Item"
se.doclist[1].qty = 2 se.get("mtn_details")[0].qty = 2
se.doclist[1].serial_no = "ABCD\nEFGH\nXYZ" se.get("mtn_details")[0].serial_no = "ABCD\nEFGH\nXYZ"
se.doclist[1].transfer_qty = 2 se.get("mtn_details")[0].transfer_qty = 2
se.insert() se.insert()
self.assertRaises(SerialNoQtyError, se.submit) self.assertRaises(SerialNoQtyError, se.submit)
def test_serial_no_qty_less(self): def test_serial_no_qty_less(self):
se = frappe.copy_doc(test_records[0]) se = frappe.copy_doc(test_records[0])
se.doclist[1].item_code = "_Test Serialized Item" se.get("mtn_details")[0].item_code = "_Test Serialized Item"
se.doclist[1].qty = 2 se.get("mtn_details")[0].qty = 2
se.doclist[1].serial_no = "ABCD" se.get("mtn_details")[0].serial_no = "ABCD"
se.doclist[1].transfer_qty = 2 se.get("mtn_details")[0].transfer_qty = 2
se.insert() se.insert()
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() self._clear_stock_account_balance()
se = frappe.copy_doc(test_records[0]) se = frappe.copy_doc(test_records[0])
se.doclist[1].item_code = "_Test Serialized Item" se.get("mtn_details")[0].item_code = "_Test Serialized Item"
se.doclist[1].qty = 2 se.get("mtn_details")[0].qty = 2
se.doclist[1].serial_no = "ABCD\nEFGH" se.get("mtn_details")[0].serial_no = "ABCD\nEFGH"
se.doclist[1].transfer_qty = 2 se.get("mtn_details")[0].transfer_qty = 2
se.insert() se.insert()
se.submit() se.submit()
@ -672,12 +669,12 @@ class TestStockEntry(unittest.TestCase):
self._clear_stock_account_balance() self._clear_stock_account_balance()
se = frappe.copy_doc(test_records[0]) se = frappe.copy_doc(test_records[0])
se.purpose = "Material Issue" se.purpose = "Material Issue"
se.doclist[1].item_code = "_Test Serialized Item" se.get("mtn_details")[0].item_code = "_Test Serialized Item"
se.doclist[1].qty = 2 se.get("mtn_details")[0].qty = 2
se.doclist[1].s_warehouse = "_Test Warehouse 1 - _TC" se.get("mtn_details")[0].s_warehouse = "_Test Warehouse 1 - _TC"
se.doclist[1].t_warehouse = None se.get("mtn_details")[0].t_warehouse = None
se.doclist[1].serial_no = "ABCD\nEFGH" se.get("mtn_details")[0].serial_no = "ABCD\nEFGH"
se.doclist[1].transfer_qty = 2 se.get("mtn_details")[0].transfer_qty = 2
se.insert() se.insert()
self.assertRaises(SerialNoNotExistsError, se.submit) self.assertRaises(SerialNoNotExistsError, se.submit)
@ -686,10 +683,10 @@ class TestStockEntry(unittest.TestCase):
self.test_serial_by_series() self.test_serial_by_series()
se = frappe.copy_doc(test_records[0]) se = frappe.copy_doc(test_records[0])
se.doclist[1].item_code = "_Test Serialized Item With Series" se.get("mtn_details")[0].item_code = "_Test Serialized Item With Series"
se.doclist[1].qty = 1 se.get("mtn_details")[0].qty = 1
se.doclist[1].serial_no = "ABCD00001" se.get("mtn_details")[0].serial_no = "ABCD00001"
se.doclist[1].transfer_qty = 1 se.get("mtn_details")[0].transfer_qty = 1
se.insert() se.insert()
self.assertRaises(SerialNoDuplicateError, se.submit) self.assertRaises(SerialNoDuplicateError, se.submit)
@ -697,7 +694,7 @@ class TestStockEntry(unittest.TestCase):
self._clear_stock_account_balance() self._clear_stock_account_balance()
se = make_serialized_item() se = make_serialized_item()
serial_nos = get_serial_nos(se.doclist[1].serial_no) serial_nos = get_serial_nos(se.get("mtn_details")[0].serial_no)
self.assertTrue(frappe.db.exists("Serial No", serial_nos[0])) self.assertTrue(frappe.db.exists("Serial No", serial_nos[0]))
self.assertTrue(frappe.db.exists("Serial No", serial_nos[1])) self.assertTrue(frappe.db.exists("Serial No", serial_nos[1]))
@ -710,28 +707,28 @@ class TestStockEntry(unittest.TestCase):
se = frappe.copy_doc(test_records[0]) se = frappe.copy_doc(test_records[0])
se.purpose = "Material Transfer" se.purpose = "Material Transfer"
se.doclist[1].item_code = "_Test Serialized Item" se.get("mtn_details")[0].item_code = "_Test Serialized Item"
se.doclist[1].qty = 1 se.get("mtn_details")[0].qty = 1
se.doclist[1].transfer_qty = 1 se.get("mtn_details")[0].transfer_qty = 1
se.doclist[1].serial_no = "ABCD00001" se.get("mtn_details")[0].serial_no = "ABCD00001"
se.doclist[1].s_warehouse = "_Test Warehouse - _TC" se.get("mtn_details")[0].s_warehouse = "_Test Warehouse - _TC"
se.doclist[1].t_warehouse = "_Test Warehouse 1 - _TC" se.get("mtn_details")[0].t_warehouse = "_Test Warehouse 1 - _TC"
se.insert() se.insert()
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() self._clear_stock_account_balance()
se = make_serialized_item() se = make_serialized_item()
serial_no = get_serial_nos(se.doclist[1].serial_no)[0] serial_no = get_serial_nos(se.get("mtn_details")[0].serial_no)[0]
se = frappe.copy_doc(test_records[0]) se = frappe.copy_doc(test_records[0])
se.purpose = "Material Transfer" se.purpose = "Material Transfer"
se.doclist[1].item_code = "_Test Serialized Item With Series" se.get("mtn_details")[0].item_code = "_Test Serialized Item With Series"
se.doclist[1].qty = 1 se.get("mtn_details")[0].qty = 1
se.doclist[1].transfer_qty = 1 se.get("mtn_details")[0].transfer_qty = 1
se.doclist[1].serial_no = serial_no se.get("mtn_details")[0].serial_no = serial_no
se.doclist[1].s_warehouse = "_Test Warehouse - _TC" se.get("mtn_details")[0].s_warehouse = "_Test Warehouse - _TC"
se.doclist[1].t_warehouse = "_Test Warehouse 1 - _TC" se.get("mtn_details")[0].t_warehouse = "_Test Warehouse 1 - _TC"
se.insert() se.insert()
se.submit() se.submit()
self.assertTrue(frappe.db.get_value("Serial No", serial_no, "warehouse"), "_Test Warehouse 1 - _TC") self.assertTrue(frappe.db.get_value("Serial No", serial_no, "warehouse"), "_Test Warehouse 1 - _TC")
@ -745,12 +742,12 @@ class TestStockEntry(unittest.TestCase):
se = frappe.copy_doc(test_records[0]) se = frappe.copy_doc(test_records[0])
se.purpose = "Material Transfer" se.purpose = "Material Transfer"
se.doclist[1].item_code = "_Test Serialized Item With Series" se.get("mtn_details")[0].item_code = "_Test Serialized Item With Series"
se.doclist[1].qty = 1 se.get("mtn_details")[0].qty = 1
se.doclist[1].transfer_qty = 1 se.get("mtn_details")[0].transfer_qty = 1
se.doclist[1].serial_no = "ABCD00001" se.get("mtn_details")[0].serial_no = "ABCD00001"
se.doclist[1].s_warehouse = "_Test Warehouse 1 - _TC" se.get("mtn_details")[0].s_warehouse = "_Test Warehouse 1 - _TC"
se.doclist[1].t_warehouse = "_Test Warehouse - _TC" se.get("mtn_details")[0].t_warehouse = "_Test Warehouse - _TC"
se.insert() se.insert()
self.assertRaises(SerialNoWarehouseError, se.submit) self.assertRaises(SerialNoWarehouseError, se.submit)
@ -759,9 +756,9 @@ class TestStockEntry(unittest.TestCase):
se = self.test_serial_by_series() se = self.test_serial_by_series()
se.cancel() se.cancel()
serial_no = get_serial_nos(se.doclist[1].serial_no)[0] serial_no = get_serial_nos(se.get("mtn_details")[0].serial_no)[0]
self.assertFalse(frappe.db.get_value("Serial No", serial_no, "warehouse")) self.assertFalse(frappe.db.get_value("Serial No", serial_no, "warehouse"))
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() self._clear_stock_account_balance()
@ -771,15 +768,15 @@ class TestStockEntry(unittest.TestCase):
from erpnext.stock.utils import InvalidWarehouseCompany from erpnext.stock.utils import InvalidWarehouseCompany
st1 = frappe.copy_doc(test_records[0]) st1 = frappe.copy_doc(test_records[0])
st1.doclist[1].t_warehouse="_Test Warehouse 2 - _TC1" st1.get("mtn_details")[0].t_warehouse="_Test Warehouse 2 - _TC1"
st1.insert() st1.insert()
self.assertRaises(InvalidWarehouseCompany, st1.submit) self.assertRaises(InvalidWarehouseCompany, st1.submit)
# permission tests # permission tests
def test_warehouse_user(self): def test_warehouse_user(self):
import frappe.defaults import frappe.defaults
set_perpetual_inventory(0) set_perpetual_inventory(0)
frappe.defaults.add_default("Warehouse", "_Test Warehouse 1 - _TC1", "test@example.com", "Restriction") frappe.defaults.add_default("Warehouse", "_Test Warehouse 1 - _TC1", "test@example.com", "Restriction")
frappe.defaults.add_default("Warehouse", "_Test Warehouse 2 - _TC1", "test2@example.com", "Restriction") frappe.defaults.add_default("Warehouse", "_Test Warehouse 2 - _TC1", "test2@example.com", "Restriction")
frappe.get_doc("User", "test@example.com")\ frappe.get_doc("User", "test@example.com")\
@ -790,19 +787,19 @@ class TestStockEntry(unittest.TestCase):
frappe.set_user("test@example.com") frappe.set_user("test@example.com")
st1 = frappe.copy_doc(test_records[0]) st1 = frappe.copy_doc(test_records[0])
st1.company = "_Test Company 1" st1.company = "_Test Company 1"
st1.doclist[1].t_warehouse="_Test Warehouse 2 - _TC1" st1.get("mtn_details")[0].t_warehouse="_Test Warehouse 2 - _TC1"
self.assertRaises(frappe.PermissionErrorp, st1.insert) self.assertRaises(frappe.PermissionError, st1.insert)
frappe.set_user("test2@example.com") frappe.set_user("test2@example.com")
st1 = frappe.copy_doc(test_records[0]) st1 = frappe.copy_doc(test_records[0])
st1.company = "_Test Company 1" st1.company = "_Test Company 1"
st1.doclist[1].t_warehouse="_Test Warehouse 2 - _TC1" st1.get("mtn_details")[0].t_warehouse="_Test Warehouse 2 - _TC1"
st1.insert() st1.insert()
st1.submit() st1.submit()
frappe.defaults.clear_default("Warehouse", "_Test Warehouse 1 - _TC1", "test@example.com", parenttype="Restriction") frappe.defaults.clear_default("Warehouse", "_Test Warehouse 1 - _TC1", "test@example.com", parenttype="Restriction")
frappe.defaults.clear_default("Warehouse", "_Test Warehouse 2 - _TC1", "test2@example.com", parenttype="Restriction") frappe.defaults.clear_default("Warehouse", "_Test Warehouse 2 - _TC1", "test2@example.com", parenttype="Restriction")
def test_freeze_stocks (self): def test_freeze_stocks (self):
self._clear_stock_account_balance() 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', '')
@ -822,11 +819,11 @@ class TestStockEntry(unittest.TestCase):
def make_serialized_item(): def make_serialized_item():
se = frappe.copy_doc(test_records[0]) se = frappe.copy_doc(test_records[0])
se.doclist[1].item_code = "_Test Serialized Item With Series" se.get("mtn_details")[0].item_code = "_Test Serialized Item With Series"
se.doclist[1].qty = 2 se.get("mtn_details")[0].qty = 2
se.doclist[1].transfer_qty = 2 se.get("mtn_details")[0].transfer_qty = 2
se.insert() se.insert()
se.submit() se.submit()
return se return se
test_records = frappe.get_test_records('Stock Entry') test_records = frappe.get_test_records('Stock Entry')

View File

@ -228,9 +228,9 @@ class TestStockReconciliation(unittest.TestCase):
pr1 = frappe.copy_doc(stock_entry) pr1 = frappe.copy_doc(stock_entry)
pr1.posting_date = "2012-12-15" pr1.posting_date = "2012-12-15"
pr1.posting_time = "02:00" pr1.posting_time = "02:00"
pr1.doclist[1].qty = 10 pr1.get("mtn_details")[0].qty = 10
pr1.doclist[1].transfer_qty = 10 pr1.get("mtn_details")[0].transfer_qty = 10
pr1.doclist[1].incoming_rate = 700 pr1.get("mtn_details")[0].incoming_rate = 700
pr1.insert() pr1.insert()
pr1.submit() pr1.submit()
@ -238,11 +238,11 @@ class TestStockReconciliation(unittest.TestCase):
pr2.posting_date = "2012-12-25" pr2.posting_date = "2012-12-25"
pr2.posting_time = "03:00" pr2.posting_time = "03:00"
pr2.purpose = "Material Issue" pr2.purpose = "Material Issue"
pr2.doclist[1].s_warehouse = "_Test Warehouse - _TC" pr2.get("mtn_details")[0].s_warehouse = "_Test Warehouse - _TC"
pr2.doclist[1].t_warehouse = None pr2.get("mtn_details")[0].t_warehouse = None
pr2.doclist[1].qty = 15 pr2.get("mtn_details")[0].qty = 15
pr2.doclist[1].transfer_qty = 15 pr2.get("mtn_details")[0].transfer_qty = 15
pr2.doclist[1].incoming_rate = 0 pr2.get("mtn_details")[0].incoming_rate = 0
pr2.insert() pr2.insert()
pr2.submit() pr2.submit()
@ -250,11 +250,11 @@ class TestStockReconciliation(unittest.TestCase):
pr3.posting_date = "2012-12-31" pr3.posting_date = "2012-12-31"
pr3.posting_time = "08:00" pr3.posting_time = "08:00"
pr3.purpose = "Material Issue" pr3.purpose = "Material Issue"
pr3.doclist[1].s_warehouse = "_Test Warehouse - _TC" pr3.get("mtn_details")[0].s_warehouse = "_Test Warehouse - _TC"
pr3.doclist[1].t_warehouse = None pr3.get("mtn_details")[0].t_warehouse = None
pr3.doclist[1].qty = 20 pr3.get("mtn_details")[0].qty = 20
pr3.doclist[1].transfer_qty = 20 pr3.get("mtn_details")[0].transfer_qty = 20
pr3.doclist[1].incoming_rate = 0 pr3.get("mtn_details")[0].incoming_rate = 0
pr3.insert() pr3.insert()
pr3.submit() pr3.submit()
@ -263,9 +263,9 @@ class TestStockReconciliation(unittest.TestCase):
pr4.posting_date = "2013-01-05" pr4.posting_date = "2013-01-05"
pr4.fiscal_year = "_Test Fiscal Year 2013" pr4.fiscal_year = "_Test Fiscal Year 2013"
pr4.posting_time = "07:00" pr4.posting_time = "07:00"
pr4.doclist[1].qty = 15 pr4.get("mtn_details")[0].qty = 15
pr4.doclist[1].transfer_qty = 15 pr4.get("mtn_details")[0].transfer_qty = 15
pr4.doclist[1].incoming_rate = 1200 pr4.get("mtn_details")[0].incoming_rate = 1200
pr4.insert() pr4.insert()
pr4.submit() pr4.submit()

View File

@ -17,36 +17,35 @@ _exceptions = frappe.local('stockledger_exceptions')
def make_sl_entries(sl_entries, is_amended=None): def make_sl_entries(sl_entries, is_amended=None):
if sl_entries: if sl_entries:
from erpnext.stock.utils import update_bin from erpnext.stock.utils import update_bin
cancel = True if sl_entries[0].get("is_cancelled") == "Yes" else False cancel = True if sl_entries[0].get("is_cancelled") == "Yes" else False
if cancel: if cancel:
set_as_cancel(sl_entries[0].get('voucher_no'), sl_entries[0].get('voucher_type')) set_as_cancel(sl_entries[0].get('voucher_no'), sl_entries[0].get('voucher_type'))
for sle in sl_entries: for sle in sl_entries:
sle_id = None sle_id = None
if sle.get('is_cancelled') == 'Yes': if sle.get('is_cancelled') == 'Yes':
sle['actual_qty'] = -flt(sle['actual_qty']) sle['actual_qty'] = -flt(sle['actual_qty'])
if sle.get("actual_qty"): if sle.get("actual_qty"):
sle_id = make_entry(sle) sle_id = make_entry(sle)
args = sle.copy() args = sle.copy()
args.update({ args.update({
"sle_id": sle_id, "sle_id": sle_id,
"is_amended": is_amended "is_amended": is_amended
}) })
update_bin(args) update_bin(args)
if cancel: if cancel:
delete_cancelled_entry(sl_entries[0].get('voucher_type'), delete_cancelled_entry(sl_entries[0].get('voucher_type'),
sl_entries[0].get('voucher_no')) sl_entries[0].get('voucher_no'))
def set_as_cancel(voucher_type, voucher_no): def set_as_cancel(voucher_type, voucher_no):
frappe.db.sql("""update `tabStock Ledger Entry` set is_cancelled='Yes', frappe.db.sql("""update `tabStock Ledger Entry` set is_cancelled='Yes',
modified=%s, modified_by=%s modified=%s, modified_by=%s
where voucher_no=%s and voucher_type=%s""", where voucher_no=%s and voucher_type=%s""",
(now(), frappe.session.user, voucher_type, voucher_no)) (now(), frappe.session.user, voucher_type, voucher_no))
def make_entry(args): def make_entry(args):
args.update({"doctype": "Stock Ledger Entry"}) args.update({"doctype": "Stock Ledger Entry"})
sle = frappe.get_doc(args) sle = frappe.get_doc(args)
@ -54,16 +53,16 @@ def make_entry(args):
sle.insert() sle.insert()
sle.submit() sle.submit()
return sle.name return sle.name
def delete_cancelled_entry(voucher_type, voucher_no): def delete_cancelled_entry(voucher_type, voucher_no):
frappe.db.sql("""delete from `tabStock Ledger Entry` frappe.db.sql("""delete from `tabStock Ledger Entry`
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no)) where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
def update_entries_after(args, verbose=1): def update_entries_after(args, verbose=1):
""" """
update valution rate and qty after transaction update valution rate and qty after transaction
from the current time-bucket onwards from the current time-bucket onwards
args = { args = {
"item_code": "ABC", "item_code": "ABC",
"warehouse": "XYZ", "warehouse": "XYZ",
@ -73,15 +72,15 @@ def update_entries_after(args, verbose=1):
""" """
if not _exceptions: if not _exceptions:
frappe.local.stockledger_exceptions = [] frappe.local.stockledger_exceptions = []
previous_sle = get_sle_before_datetime(args) previous_sle = get_sle_before_datetime(args)
qty_after_transaction = flt(previous_sle.get("qty_after_transaction")) qty_after_transaction = flt(previous_sle.get("qty_after_transaction"))
valuation_rate = flt(previous_sle.get("valuation_rate")) valuation_rate = flt(previous_sle.get("valuation_rate"))
stock_queue = json.loads(previous_sle.get("stock_queue") or "[]") stock_queue = json.loads(previous_sle.get("stock_queue") or "[]")
stock_value = flt(previous_sle.get("stock_value")) stock_value = flt(previous_sle.get("stock_value"))
prev_stock_value = flt(previous_sle.get("stock_value")) prev_stock_value = flt(previous_sle.get("stock_value"))
entries_to_fix = get_sle_after_datetime(previous_sle or \ entries_to_fix = get_sle_after_datetime(previous_sle or \
{"item_code": args["item_code"], "warehouse": args["warehouse"]}, for_update=True) {"item_code": args["item_code"], "warehouse": args["warehouse"]}, for_update=True)
@ -90,7 +89,7 @@ def update_entries_after(args, verbose=1):
for sle in entries_to_fix: for sle in entries_to_fix:
if sle.serial_no or not cint(frappe.db.get_default("allow_negative_stock")): if sle.serial_no or not cint(frappe.db.get_default("allow_negative_stock")):
# validate negative stock for serialized items, fifo valuation # validate negative stock for serialized items, fifo valuation
# or when negative stock is not allowed for moving average # or when negative stock is not allowed for moving average
if not validate_negative_stock(qty_after_transaction, sle): if not validate_negative_stock(qty_after_transaction, sle):
qty_after_transaction += flt(sle.actual_qty) qty_after_transaction += flt(sle.actual_qty)
@ -102,9 +101,9 @@ def update_entries_after(args, verbose=1):
valuation_rate = get_moving_average_values(qty_after_transaction, sle, valuation_rate) valuation_rate = get_moving_average_values(qty_after_transaction, sle, valuation_rate)
else: else:
valuation_rate = get_fifo_values(qty_after_transaction, sle, stock_queue) valuation_rate = get_fifo_values(qty_after_transaction, sle, stock_queue)
qty_after_transaction += flt(sle.actual_qty) qty_after_transaction += flt(sle.actual_qty)
# get stock value # get stock value
if sle.serial_no: if sle.serial_no:
stock_value = qty_after_transaction * valuation_rate stock_value = qty_after_transaction * valuation_rate
@ -113,29 +112,29 @@ def update_entries_after(args, verbose=1):
(qty_after_transaction * valuation_rate) or 0 (qty_after_transaction * valuation_rate) or 0
else: else:
stock_value = sum((flt(batch[0]) * flt(batch[1]) for batch in stock_queue)) stock_value = sum((flt(batch[0]) * flt(batch[1]) for batch in stock_queue))
# rounding as per precision # rounding as per precision
from frappe.model.meta import get_field_precision from frappe.model.meta import get_field_precision
meta = frappe.get_meta("Stock Ledger Entry") meta = frappe.get_meta("Stock Ledger Entry")
stock_value = flt(stock_value, get_field_precision(meta.get_field("stock_value"), stock_value = flt(stock_value, get_field_precision(meta.get_field("stock_value"),
frappe._dict({"fields": sle}))) frappe._dict({"fields": sle})))
stock_value_difference = stock_value - prev_stock_value stock_value_difference = stock_value - prev_stock_value
prev_stock_value = stock_value prev_stock_value = stock_value
# update current sle # update current sle
frappe.db.sql("""update `tabStock Ledger Entry` frappe.db.sql("""update `tabStock Ledger Entry`
set qty_after_transaction=%s, valuation_rate=%s, stock_queue=%s, set qty_after_transaction=%s, valuation_rate=%s, stock_queue=%s,
stock_value=%s, stock_value_difference=%s where name=%s""", stock_value=%s, stock_value_difference=%s where name=%s""",
(qty_after_transaction, valuation_rate, (qty_after_transaction, valuation_rate,
json.dumps(stock_queue), stock_value, stock_value_difference, sle.name)) json.dumps(stock_queue), stock_value, stock_value_difference, sle.name))
if _exceptions: if _exceptions:
_raise_exceptions(args, verbose) _raise_exceptions(args, verbose)
# update bin # update bin
if not frappe.db.exists({"doctype": "Bin", "item_code": args["item_code"], if not frappe.db.exists({"doctype": "Bin", "item_code": args["item_code"],
"warehouse": args["warehouse"]}): "warehouse": args["warehouse"]}):
bin_wrapper = frappe.get_doc({ bin_wrapper = frappe.get_doc({
"doctype": "Bin", "doctype": "Bin",
@ -144,13 +143,13 @@ def update_entries_after(args, verbose=1):
}) })
bin_wrapper.ignore_permissions = 1 bin_wrapper.ignore_permissions = 1
bin_wrapper.insert() bin_wrapper.insert()
frappe.db.sql("""update `tabBin` set valuation_rate=%s, actual_qty=%s, frappe.db.sql("""update `tabBin` set valuation_rate=%s, actual_qty=%s,
stock_value=%s, stock_value=%s,
projected_qty = (actual_qty + indented_qty + ordered_qty + planned_qty - reserved_qty) projected_qty = (actual_qty + indented_qty + ordered_qty + planned_qty - reserved_qty)
where item_code=%s and warehouse=%s""", (valuation_rate, qty_after_transaction, where item_code=%s and warehouse=%s""", (valuation_rate, qty_after_transaction,
stock_value, args["item_code"], args["warehouse"])) stock_value, args["item_code"], args["warehouse"]))
def get_sle_before_datetime(args, for_update=False): def get_sle_before_datetime(args, for_update=False):
""" """
get previous stock ledger entry before current time-bucket get previous stock ledger entry before current time-bucket
@ -164,23 +163,23 @@ def get_sle_before_datetime(args, for_update=False):
sle = get_stock_ledger_entries(args, sle = get_stock_ledger_entries(args,
["timestamp(posting_date, posting_time) < timestamp(%(posting_date)s, %(posting_time)s)"], ["timestamp(posting_date, posting_time) < timestamp(%(posting_date)s, %(posting_time)s)"],
"desc", "limit 1", for_update=for_update) "desc", "limit 1", for_update=for_update)
return sle and sle[0] or frappe._dict() return sle and sle[0] or frappe._dict()
def get_sle_after_datetime(args, for_update=False): def get_sle_after_datetime(args, for_update=False):
"""get Stock Ledger Entries after a particular datetime, for reposting""" """get Stock Ledger Entries after a particular datetime, for reposting"""
# NOTE: using for update of # NOTE: using for update of
return get_stock_ledger_entries(args, return get_stock_ledger_entries(args,
["timestamp(posting_date, posting_time) > timestamp(%(posting_date)s, %(posting_time)s)"], ["timestamp(posting_date, posting_time) > timestamp(%(posting_date)s, %(posting_time)s)"],
"asc", for_update=for_update) "asc", for_update=for_update)
def get_stock_ledger_entries(args, conditions=None, order="desc", limit=None, for_update=False): def get_stock_ledger_entries(args, conditions=None, order="desc", limit=None, for_update=False):
"""get stock ledger entries filtered by specific posting datetime conditions""" """get stock ledger entries filtered by specific posting datetime conditions"""
if not args.get("posting_date"): if not args.get("posting_date"):
args["posting_date"] = "1900-01-01" args["posting_date"] = "1900-01-01"
if not args.get("posting_time"): if not args.get("posting_time"):
args["posting_time"] = "00:00" args["posting_time"] = "00:00"
return frappe.db.sql("""select * from `tabStock Ledger Entry` return frappe.db.sql("""select * from `tabStock Ledger Entry`
where item_code = %%(item_code)s where item_code = %%(item_code)s
and warehouse = %%(warehouse)s and warehouse = %%(warehouse)s
@ -193,7 +192,7 @@ def get_stock_ledger_entries(args, conditions=None, order="desc", limit=None, fo
"for_update": for_update and "for update" or "", "for_update": for_update and "for update" or "",
"order": order "order": order
}, args, as_dict=1) }, args, as_dict=1)
def validate_negative_stock(qty_after_transaction, sle): def validate_negative_stock(qty_after_transaction, sle):
""" """
validate negative stock for entries current datetime onwards validate negative stock for entries current datetime onwards
@ -203,7 +202,7 @@ def validate_negative_stock(qty_after_transaction, sle):
if not _exceptions: if not _exceptions:
frappe.local.stockledger_exceptions = [] frappe.local.stockledger_exceptions = []
if diff < 0 and abs(diff) > 0.0001: if diff < 0 and abs(diff) > 0.0001:
# negative stock! # negative stock!
exc = sle.copy().update({"diff": diff}) exc = sle.copy().update({"diff": diff})
@ -211,12 +210,12 @@ def validate_negative_stock(qty_after_transaction, sle):
return False return False
else: else:
return True return True
def get_serialized_values(qty_after_transaction, sle, valuation_rate): def get_serialized_values(qty_after_transaction, sle, valuation_rate):
incoming_rate = flt(sle.incoming_rate) incoming_rate = flt(sle.incoming_rate)
actual_qty = flt(sle.actual_qty) actual_qty = flt(sle.actual_qty)
serial_no = cstr(sle.serial_no).split("\n") serial_no = cstr(sle.serial_no).split("\n")
if incoming_rate < 0: if incoming_rate < 0:
# wrong incoming rate # wrong incoming rate
incoming_rate = valuation_rate incoming_rate = valuation_rate
@ -226,7 +225,7 @@ def get_serialized_values(qty_after_transaction, sle, valuation_rate):
incoming_rate = flt(frappe.db.sql("""select avg(ifnull(purchase_rate, 0)) incoming_rate = flt(frappe.db.sql("""select avg(ifnull(purchase_rate, 0))
from `tabSerial No` where name in (%s)""" % (", ".join(["%s"]*len(serial_no))), from `tabSerial No` where name in (%s)""" % (", ".join(["%s"]*len(serial_no))),
tuple(serial_no))[0][0]) tuple(serial_no))[0][0])
if incoming_rate and not valuation_rate: if incoming_rate and not valuation_rate:
valuation_rate = incoming_rate valuation_rate = incoming_rate
else: else:
@ -237,33 +236,33 @@ def get_serialized_values(qty_after_transaction, sle, valuation_rate):
# calculate new valuation rate only if stock value is positive # calculate new valuation rate only if stock value is positive
# else it remains the same as that of previous entry # else it remains the same as that of previous entry
valuation_rate = new_stock_value / new_stock_qty valuation_rate = new_stock_value / new_stock_qty
return valuation_rate return valuation_rate
def get_moving_average_values(qty_after_transaction, sle, valuation_rate): def get_moving_average_values(qty_after_transaction, sle, valuation_rate):
incoming_rate = flt(sle.incoming_rate) incoming_rate = flt(sle.incoming_rate)
actual_qty = flt(sle.actual_qty) actual_qty = flt(sle.actual_qty)
if not incoming_rate: if not incoming_rate:
# In case of delivery/stock issue in_rate = 0 or wrong incoming rate # In case of delivery/stock issue in_rate = 0 or wrong incoming rate
incoming_rate = valuation_rate incoming_rate = valuation_rate
elif qty_after_transaction < 0: elif qty_after_transaction < 0:
# if negative stock, take current valuation rate as incoming rate # if negative stock, take current valuation rate as incoming rate
valuation_rate = incoming_rate valuation_rate = incoming_rate
new_stock_qty = qty_after_transaction + actual_qty new_stock_qty = qty_after_transaction + actual_qty
new_stock_value = qty_after_transaction * valuation_rate + actual_qty * incoming_rate new_stock_value = qty_after_transaction * valuation_rate + actual_qty * incoming_rate
if new_stock_qty > 0 and new_stock_value > 0: if new_stock_qty > 0 and new_stock_value > 0:
valuation_rate = new_stock_value / flt(new_stock_qty) valuation_rate = new_stock_value / flt(new_stock_qty)
elif new_stock_qty <= 0: elif new_stock_qty <= 0:
valuation_rate = 0.0 valuation_rate = 0.0
# NOTE: val_rate is same as previous entry if new stock value is negative # NOTE: val_rate is same as previous entry if new stock value is negative
return valuation_rate return valuation_rate
def get_fifo_values(qty_after_transaction, sle, stock_queue): def get_fifo_values(qty_after_transaction, sle, stock_queue):
incoming_rate = flt(sle.incoming_rate) incoming_rate = flt(sle.incoming_rate)
actual_qty = flt(sle.actual_qty) actual_qty = flt(sle.actual_qty)
@ -282,9 +281,9 @@ def get_fifo_values(qty_after_transaction, sle, stock_queue):
while qty_to_pop: while qty_to_pop:
if not stock_queue: if not stock_queue:
stock_queue.append([0, 0]) stock_queue.append([0, 0])
batch = stock_queue[0] batch = stock_queue[0]
if 0 < batch[0] <= qty_to_pop: if 0 < batch[0] <= qty_to_pop:
# if batch qty > 0 # if batch qty > 0
# not enough or exactly same qty in current batch, clear batch # not enough or exactly same qty in current batch, clear batch
@ -296,7 +295,7 @@ def get_fifo_values(qty_after_transaction, sle, stock_queue):
incoming_cost += flt(qty_to_pop) * flt(batch[1]) incoming_cost += flt(qty_to_pop) * flt(batch[1])
batch[0] -= qty_to_pop batch[0] -= qty_to_pop
qty_to_pop = 0 qty_to_pop = 0
stock_value = sum((flt(batch[0]) * flt(batch[1]) for batch in stock_queue)) stock_value = sum((flt(batch[0]) * flt(batch[1]) for batch in stock_queue))
stock_qty = sum((flt(batch[0]) for batch in stock_queue)) stock_qty = sum((flt(batch[0]) for batch in stock_queue))
@ -306,9 +305,9 @@ def get_fifo_values(qty_after_transaction, sle, stock_queue):
def _raise_exceptions(args, verbose=1): def _raise_exceptions(args, verbose=1):
deficiency = min(e["diff"] for e in _exceptions) deficiency = min(e["diff"] for e in _exceptions)
msg = """Negative stock error: msg = """Negative stock error:
Cannot complete this transaction because stock will start Cannot complete this transaction because stock will start
becoming negative (%s) for Item <b>%s</b> in Warehouse becoming negative (%s) for Item <b>%s</b> in Warehouse
<b>%s</b> on <b>%s %s</b> in Transaction %s %s. <b>%s</b> on <b>%s %s</b> in Transaction %s %s.
Total Quantity Deficiency: <b>%s</b>""" % \ Total Quantity Deficiency: <b>%s</b>""" % \
(_exceptions[0]["diff"], args.get("item_code"), args.get("warehouse"), (_exceptions[0]["diff"], args.get("item_code"), args.get("warehouse"),
@ -319,13 +318,13 @@ def _raise_exceptions(args, verbose=1):
msgprint(msg, raise_exception=NegativeStockError) msgprint(msg, raise_exception=NegativeStockError)
else: else:
raise NegativeStockError, msg raise NegativeStockError, msg
def get_previous_sle(args, for_update=False): def get_previous_sle(args, for_update=False):
""" """
get the last sle on or before the current time-bucket, get the last sle on or before the current time-bucket,
to get actual qty before transaction, this function to get actual qty before transaction, this function
is called from various transaction like stock entry, reco etc is called from various transaction like stock entry, reco etc
args = { args = {
"item_code": "ABC", "item_code": "ABC",
"warehouse": "XYZ", "warehouse": "XYZ",
@ -335,7 +334,7 @@ def get_previous_sle(args, for_update=False):
} }
""" """
if not args.get("sle"): args["sle"] = "" if not args.get("sle"): args["sle"] = ""
sle = get_stock_ledger_entries(args, ["name != %(sle)s", sle = get_stock_ledger_entries(args, ["name != %(sle)s",
"timestamp(posting_date, posting_time) <= timestamp(%(posting_date)s, %(posting_time)s)"], "timestamp(posting_date, posting_time) <= timestamp(%(posting_date)s, %(posting_time)s)"],
"desc", "limit 1", for_update=for_update) "desc", "limit 1", for_update=for_update)