def test_not_accept_duplicate_serial_no(self): from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note item_code = frappe.db.get_value('Item', { 'has_serial_no': 1, 'is_fixed_asset': 0 }) if not item_code: item = make_item("Test Serial Item 1", dict(has_serial_no=1)) item_code = item.name serial_no = random_string(5) make_purchase_receipt(item_code=item_code, qty=1, serial_no=serial_no) create_delivery_note(item_code=item_code, qty=1, serial_no=serial_no) pr = make_purchase_receipt(item_code=item_code, qty=1, serial_no=serial_no, do_not_submit=True) self.assertRaises(SerialNoDuplicateError, pr.submit) se = make_stock_entry(item_code=item_code, target="_Test Warehouse - _TC", qty=1, serial_no=serial_no, basic_rate=100, do_not_submit=True) self.assertRaises(SerialNoDuplicateError, se.submit)
def test_inter_company_transfer(self): se = make_serialized_item(target_warehouse="_Test Warehouse - _TC") serial_nos = get_serial_nos(se.get("items")[0].serial_no) create_delivery_note(item_code="_Test Serialized Item With Series", qty=1, serial_no=serial_nos[0]) wh = create_warehouse("_Test Warehouse", company="_Test Company 1") make_purchase_receipt(item_code="_Test Serialized Item With Series", qty=1, serial_no=serial_nos[0], company="_Test Company 1", warehouse=wh) serial_no = frappe.db.get_value("Serial No", serial_nos[0], ["warehouse", "company"], as_dict=1) self.assertEqual(serial_no.warehouse, wh) self.assertEqual(serial_no.company, "_Test Company 1")
def _test_delivery_note_return(self, item_code, delivered_qty, returned_qty): from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, incoming_rate=100) actual_qty_0 = get_qty_after_transaction() # make a delivery note based on this invoice dn = create_delivery_note(item_code="_Test Item", warehouse="_Test Warehouse - _TC", qty=delivered_qty) actual_qty_1 = get_qty_after_transaction() self.assertEquals(actual_qty_0 - delivered_qty, actual_qty_1) si = make_sales_invoice(dn.name) si.insert() si.submit() # insert and submit stock entry for sales return se = make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=returned_qty, purpose="Sales Return", delivery_note_no=dn.name) actual_qty_2 = get_qty_after_transaction() self.assertEquals(actual_qty_1 + returned_qty, actual_qty_2) return se
def test_qa_for_delivery(self): make_stock_entry(item_code="_Test Item with QA", target="_Test Warehouse - _TC", qty=1, basic_rate=100) dn = create_delivery_note(item_code="_Test Item with QA", do_not_submit=True) self.assertRaises(QualityInspectionRequiredError, dn.submit) qa = create_quality_inspection(reference_type="Delivery Note", reference_name=dn.name, status="Rejected") dn.reload() self.assertRaises(QualityInspectionRejectedError, dn.submit) frappe.db.set_value("Quality Inspection", qa.name, "status", "Accepted") dn.reload() dn.submit() qa.reload() qa.cancel() dn.reload() dn.cancel()
def test_value_based_qi_readings(self): # Test QI based on acceptance values (Non formula) dn = create_delivery_note(item_code="_Test Item with QA", do_not_submit=True) readings = [ { "specification": "Iron Content", # numeric reading "min_value": 0.1, "max_value": 0.9, "reading_1": "0.4", }, { "specification": "Particle Inspection Needed", # non-numeric reading "numeric": 0, "value": "Yes", "reading_value": "Yes", }, ] qa = create_quality_inspection( reference_type="Delivery Note", reference_name=dn.name, readings=readings, do_not_save=True ) qa.save() # status must be auto set as per formula self.assertEqual(qa.readings[0].status, "Accepted") self.assertEqual(qa.readings[1].status, "Accepted") qa.delete() dn.delete()
def test_formula_based_qi_readings(self): dn = create_delivery_note(item_code="_Test Item with QA", do_not_submit=True) readings = [{ "specification": "Iron Content", "acceptance_formula": "reading_1 > 0.35 and reading_1 < 0.50", "reading_1": 0.4 }, { "specification": "Calcium Content", "acceptance_formula": "reading_1 > 0.20 and reading_1 < 0.50", "reading_1": 0.7 }, { "specification": "Mg Content", "acceptance_formula": "(reading_1 + reading_2 + reading_3) / 3 < 0.9", "reading_1": 0.5, "reading_2": 0.7, "reading_3": "random text" # check if random string input causes issues }] qa = create_quality_inspection(reference_type="Delivery Note", reference_name=dn.name, readings=readings, do_not_save=True) qa.save() # status must be auto set as per formula self.assertEqual(qa.readings[0].status, "Accepted") self.assertEqual(qa.readings[1].status, "Rejected") self.assertEqual(qa.readings[2].status, "Accepted") qa.delete() dn.delete()
def test_delivered_serial_no_case(self): from erpnext.accounts.doctype.pos_invoice_merge_log.test_pos_invoice_merge_log import ( init_user_and_profile, ) from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note from erpnext.stock.doctype.serial_no.test_serial_no import get_serial_nos from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item frappe.db.savepoint("before_test_delivered_serial_no_case") try: se = make_serialized_item() serial_no = get_serial_nos(se.get("items")[0].serial_no)[0] dn = create_delivery_note(item_code="_Test Serialized Item With Series", serial_no=serial_no) delivery_document_no = frappe.db.get_value("Serial No", serial_no, "delivery_document_no") self.assertEquals(delivery_document_no, dn.name) init_user_and_profile() pos_inv = create_pos_invoice( item_code="_Test Serialized Item With Series", serial_no=serial_no, qty=1, rate=100, do_not_submit=True, ) self.assertRaises(frappe.ValidationError, pos_inv.submit) finally: frappe.db.rollback(save_point="before_test_delivered_serial_no_case") frappe.set_user("Administrator")
def test_item_type_field_change(self): """Check if critical fields like `is_stock_item`, `has_batch_no` are not changed if transactions exist.""" from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry transaction_creators = [ lambda i: make_purchase_receipt(item_code=i), lambda i: make_purchase_invoice(item_code=i, update_stock=1), lambda i: make_stock_entry( item_code=i, qty=1, target="_Test Warehouse - _TC"), lambda i: create_delivery_note(item_code=i), ] properties = { "has_batch_no": 0, "allow_negative_stock": 1, "valuation_rate": 10 } for transaction_creator in transaction_creators: item = make_item(properties=properties) transaction = transaction_creator(item.name) item.has_batch_no = 1 self.assertRaises(frappe.ValidationError, item.save) transaction.cancel() # should be allowed now item.reload() item.has_batch_no = 1 item.save()
def test_inter_company_transfer(self): se = make_serialized_item(target_warehouse="_Test Warehouse - _TC") serial_nos = get_serial_nos(se.get("items")[0].serial_no) create_delivery_note( item_code="_Test Serialized Item With Series", qty=1, serial_no=serial_nos[0]) wh = create_warehouse("_Test Warehouse", company="_Test Company 1") make_purchase_receipt(item_code="_Test Serialized Item With Series", qty=1, serial_no=serial_nos[0], company="_Test Company 1", warehouse=wh) serial_no = frappe.db.get_value("Serial No", serial_nos[0], [ "warehouse", "company"], as_dict=1) self.assertEqual(serial_no.warehouse, wh) self.assertEqual(serial_no.company, "_Test Company 1")
def test_inter_company_transfer(self): se = make_serialized_item(target_warehouse="_Test Warehouse - _TC") serial_nos = get_serial_nos(se.get("items")[0].serial_no) dn = create_delivery_note( item_code="_Test Serialized Item With Series", qty=1, serial_no=serial_nos[0]) serial_no = frappe.get_doc("Serial No", serial_nos[0]) # check Serial No details after delivery self.assertEqual(serial_no.status, "Delivered") self.assertEqual(serial_no.warehouse, None) self.assertEqual(serial_no.company, "_Test Company") self.assertEqual(serial_no.delivery_document_type, "Delivery Note") self.assertEqual(serial_no.delivery_document_no, dn.name) wh = create_warehouse("_Test Warehouse", company="_Test Company 1") pr = make_purchase_receipt( item_code="_Test Serialized Item With Series", qty=1, serial_no=serial_nos[0], company="_Test Company 1", warehouse=wh) serial_no.reload() # check Serial No details after purchase in second company self.assertEqual(serial_no.status, "Active") self.assertEqual(serial_no.warehouse, wh) self.assertEqual(serial_no.company, "_Test Company 1") self.assertEqual(serial_no.purchase_document_type, "Purchase Receipt") self.assertEqual(serial_no.purchase_document_no, pr.name)
def test_qa_not_submit(self): dn = create_delivery_note(item_code="_Test Item with QA", do_not_submit=True) qa = create_quality_inspection(reference_type="Delivery Note", reference_name=dn.name, submit=False) dn.items[0].quality_inspection = qa.name self.assertRaises(QualityInspectionNotSubmittedError, dn.submit)
def test_not_accept_duplicate_serial_no(self): from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note item_code = frappe.db.get_value('Item', {'has_serial_no': 1}) if not item_code: item = make_item("Test Serial Item 1", dict(has_serial_no=1)) item_code = item.name serial_no = random_string(5) make_purchase_receipt(item_code=item_code, qty=1, serial_no=serial_no) create_delivery_note(item_code=item_code, qty=1, serial_no=serial_no) pr = make_purchase_receipt(item_code=item_code, qty=1, serial_no=serial_no, do_not_submit=True) self.assertRaises(SerialNoDuplicateError, pr.submit) se = make_stock_entry(item_code=item_code, target="_Test Warehouse - _TC", qty=1, serial_no=serial_no, basic_rate=100, do_not_submit=True) self.assertRaises(SerialNoDuplicateError, se.submit)
def test_qa_for_delivery(self): dn = create_delivery_note(item_code="_Test Item with QA", do_not_submit=True) self.assertRaises(QualityInspectionRequiredError, dn.submit) qa = create_quality_inspection(reference_type="Delivery Note", reference_name=dn.name, status="Rejected", submit=True) dn.reload() self.assertRaises(QualityInspectionRejectedError, dn.submit) frappe.db.set_value("Quality Inspection Reading", {"parent": qa.name}, "status", "Accepted") dn.reload() dn.submit()
def test_make_quality_inspections_from_linked_document(self): dn = create_delivery_note(item_code="_Test Item with QA", do_not_submit=True) for item in dn.items: item.sample_size = item.qty quality_inspections = make_quality_inspections(dn.doctype, dn.name, dn.items) self.assertEqual(len(dn.items), len(quality_inspections)) # cleanup for qi in quality_inspections: frappe.delete_doc("Quality Inspection", qi) dn.delete()
def test_qa_for_delivery(self): dn = create_delivery_note(item_code="_Test Item with QA", do_not_submit=True, allow_zero_valuation=True) self.assertRaises(QualityInspectionRequiredError, dn.submit) qa = create_quality_inspection(reference_type="Delivery Note", reference_name=dn.name, status="Rejected", submit=True) dn.reload() self.assertRaises(QualityInspectionRejectedError, dn.submit) frappe.db.set_value("Quality Inspection Reading", {"parent": qa.name}, "status", "Accepted") dn.reload() dn.submit()
def test_backdated_stock_reco_future_negative_stock(self): """ Test if a backdated stock reco causes future negative stock and is blocked. ------------------------------------------- Var | Doc | Qty | Balance ------------------------------------------- PR1 | PR | 10 | 10 (posting date: today-2) SR3 | Reco | 0 | 1 (posting date: today-1) [backdated & blocked] DN2 | DN | -2 | 8(-1) (posting date: today) """ from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note from erpnext.stock.stock_ledger import NegativeStockError item_code = make_item().name warehouse = "_Test Warehouse - _TC" pr1 = make_purchase_receipt(item_code=item_code, warehouse=warehouse, qty=10, rate=100, posting_date=add_days(nowdate(), -2)) dn2 = create_delivery_note(item_code=item_code, warehouse=warehouse, qty=2, rate=120, posting_date=nowdate()) pr1_balance = frappe.db.get_value("Stock Ledger Entry", { "voucher_no": pr1.name, "is_cancelled": 0 }, "qty_after_transaction") dn2_balance = frappe.db.get_value("Stock Ledger Entry", { "voucher_no": dn2.name, "is_cancelled": 0 }, "qty_after_transaction") self.assertEqual(pr1_balance, 10) self.assertEqual(dn2_balance, 8) # check if stock reco is blocked sr3 = create_stock_reconciliation( item_code=item_code, warehouse=warehouse, qty=1, rate=100, posting_date=add_days(nowdate(), -1), do_not_submit=True, ) self.assertRaises(NegativeStockError, sr3.submit) # teardown sr3.cancel() dn2.cancel() pr1.cancel()
def consume_item_code_with_differet_stock_transactions( self, item_code, warehouse="_Test Warehouse - _TC"): from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry typical_args = {"item_code": item_code, "warehouse": warehouse} create_delivery_note(**typical_args) create_sales_invoice(update_stock=1, **typical_args) make_stock_entry(item_code=item_code, source=warehouse, qty=1, purpose="Material Issue") make_stock_entry(item_code=item_code, source=warehouse, target="Stores - _TC", qty=1) # standalone return make_purchase_receipt(is_return=True, qty=-1, **typical_args)
def test_formula_based_qi_readings(self): dn = create_delivery_note(item_code="_Test Item with QA", do_not_submit=True) readings = [ { "specification": "Iron Content", # numeric reading "formula_based_criteria": 1, "acceptance_formula": "reading_1 > 0.35 and reading_1 < 0.50", "reading_1": "0.4" }, { "specification": "Calcium Content", # numeric reading "formula_based_criteria": 1, "acceptance_formula": "reading_1 > 0.20 and reading_1 < 0.50", "reading_1": "0.7" }, { "specification": "Mg Content", # numeric reading "formula_based_criteria": 1, "acceptance_formula": "mean < 0.9", "reading_1": "0.5", "reading_2": "0.7", "reading_3": "random text" # check if random string input causes issues }, { "specification": "Calcium Content", # non-numeric reading "formula_based_criteria": 1, "numeric": 0, "acceptance_formula": "reading_value in ('Grade A', 'Grade B', 'Grade C')", "reading_value": "Grade B" } ] qa = create_quality_inspection(reference_type="Delivery Note", reference_name=dn.name, readings=readings, do_not_save=True) qa.save() # status must be auto set as per formula self.assertEqual(qa.readings[0].status, "Accepted") self.assertEqual(qa.readings[1].status, "Rejected") self.assertEqual(qa.readings[2].status, "Accepted") self.assertEqual(qa.readings[3].status, "Accepted") qa.delete() dn.delete()
def test_serial_balance(self): item_code = "_Test Stock Report Serial Item" # Checks serials which were added through stock in entry. columns, data = execute(self.filters) self.assertEqual(data[0].in_qty, 2) serials_added = get_serial_nos(data[0].serial_no) self.assertEqual(len(serials_added), 2) # Stock out entry for one of the serials. dn = create_delivery_note(item=item_code, serial_no=serials_added[1]) self.filters.voucher_no = dn.name columns, data = execute(self.filters) self.assertEqual(data[0].out_qty, -1) self.assertEqual(data[0].serial_no, serials_added[1]) self.assertEqual(data[0].balance_serial_no, serials_added[0])
def test_intermediate_sr_bin_update(self): """Bin should show correct qty even for backdated entries. ------------------------------------------- | creation | Var | Doc | Qty | balance qty ------------------------------------------- | 1 | SR | Reco | 10 | 10 (posting date: today+10) | 3 | SR2 | Reco | 11 | 11 (posting date: today+11) | 2 | DN | DN | 5 | 6 <-- assert in BIN (posting date: today+12) """ from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note frappe.db.rollback() # repost will make this test useless, qty should update in realtime without reposts frappe.flags.dont_execute_stock_reposts = True item_code = make_item().name warehouse = "_Test Warehouse - _TC" sr = create_stock_reconciliation(item_code=item_code, warehouse=warehouse, qty=10, rate=100, posting_date=add_days(nowdate(), 10)) dn = create_delivery_note(item_code=item_code, warehouse=warehouse, qty=5, rate=120, posting_date=add_days(nowdate(), 12)) old_bin_qty = frappe.db.get_value("Bin", { "item_code": item_code, "warehouse": warehouse }, "actual_qty") sr2 = create_stock_reconciliation(item_code=item_code, warehouse=warehouse, qty=11, rate=100, posting_date=add_days(nowdate(), 11)) new_bin_qty = frappe.db.get_value("Bin", { "item_code": item_code, "warehouse": warehouse }, "actual_qty") self.assertEqual(old_bin_qty + 1, new_bin_qty) frappe.db.rollback()
def test_backdated_stock_reco_cancellation_future_negative_stock(self): """ Test if a backdated stock reco cancellation that causes future negative stock is blocked. ------------------------------------------- Var | Doc | Qty | Balance ------------------------------------------- SR | Reco | 100 | 100 (posting date: today-1) (shouldn't be cancelled after DN) DN | DN | 100 | 0 (posting date: today) """ from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note from erpnext.stock.stock_ledger import NegativeStockError item_code = make_item().name warehouse = "_Test Warehouse - _TC" sr = create_stock_reconciliation( item_code=item_code, warehouse=warehouse, qty=100, rate=100, posting_date=add_days(nowdate(), -1), ) dn = create_delivery_note(item_code=item_code, warehouse=warehouse, qty=100, rate=120, posting_date=nowdate()) dn_balance = frappe.db.get_value("Stock Ledger Entry", { "voucher_no": dn.name, "is_cancelled": 0 }, "qty_after_transaction") self.assertEqual(dn_balance, 0) # check if cancellation of stock reco is blocked self.assertRaises(NegativeStockError, sr.cancel) repost_exists = bool( frappe.db.exists("Repost Item Valuation", {"voucher_no": sr.name})) self.assertFalse( repost_exists, msg="Negative stock validation not working on reco cancellation")
def test_return_against_sales_order(self): so = make_sales_order() dn = create_dn_against_so(so.name, 6) so.load_from_db() self.assertEqual(so.get("items")[0].delivered_qty, 6) # Check delivered_qty after make_sales_invoice with update_stock checked si2 = make_sales_invoice(so.name) si2.set("update_stock", 1) si2.get("items")[0].qty = 3 si2.insert() si2.submit() so.load_from_db() self.assertEqual(so.get("items")[0].delivered_qty, 9) # Make return deliver note, sales invoice and check quantity from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice dn1 = create_delivery_note(is_return=1, return_against=dn.name, qty=-3, do_not_submit=True) dn1.items[0].against_sales_order = so.name dn1.items[0].so_detail = so.items[0].name dn1.submit() si1 = create_sales_invoice(is_return=1, return_against=si2.name, qty=-1, update_stock=1, do_not_submit=True) si1.items[0].sales_order = so.name si1.items[0].so_detail = so.items[0].name si1.submit() so.load_from_db() self.assertEqual(so.get("items")[0].delivered_qty, 5)
def test_serial_numbers_against_delivery_note(self): """ check if the sales invoice item serial numbers and the delivery note items serial numbers are same """ from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos se = make_serialized_item() serial_nos = get_serial_nos(se.get("items")[0].serial_no) dn = create_delivery_note(item=se.get("items")[0].item_code, serial_no=serial_nos[0]) dn.submit() si = make_sales_invoice(dn.name) si.save() self.assertEquals(si.get("items")[0].serial_no, dn.get("items")[0].serial_no)
def test_customer_credit_limit(self): from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice outstanding_amt = self.get_customer_outstanding_amount() credit_limit = get_credit_limit('_Test Customer', '_Test Company') if outstanding_amt <= 0.0: item_qty = int((abs(outstanding_amt) + 200) / 100) make_sales_order(qty=item_qty) if credit_limit == 0.0: frappe.db.set_value("Customer", '_Test Customer', 'credit_limit', outstanding_amt - 50.0) # Sales Order so = make_sales_order(do_not_submit=True) self.assertRaises(frappe.ValidationError, so.submit) # Delivery Note dn = create_delivery_note(do_not_submit=True) self.assertRaises(frappe.ValidationError, dn.submit) # Sales Invoice si = create_sales_invoice(do_not_submit=True) self.assertRaises(frappe.ValidationError, si.submit) if credit_limit > outstanding_amt: frappe.db.set_value("Customer", '_Test Customer', 'credit_limit', credit_limit) # Makes Sales invoice from Sales Order so.save(ignore_permissions=True) si = make_sales_invoice(so.name) si.save(ignore_permissions=True) self.assertRaises(frappe.ValidationError, make_sales_order)
def test_correct_serial_no_incoming_rate(self): """Check correct consumption rate based on serial no record.""" item_code = "_Test Serialized Item" warehouse = "_Test Warehouse - _TC" serial_nos = ["LOWVALUATION", "HIGHVALUATION"] in1 = make_stock_entry(item_code=item_code, to_warehouse=warehouse, qty=1, rate=42, serial_no=serial_nos[0]) in2 = make_stock_entry(item_code=item_code, to_warehouse=warehouse, qty=1, rate=113, serial_no=serial_nos[1]) out = create_delivery_note(item_code=item_code, qty=1, serial_no=serial_nos[0], do_not_submit=True) # change serial no out.items[0].serial_no = serial_nos[1] out.save() out.submit() value_diff = frappe.db.get_value( "Stock Ledger Entry", { "voucher_no": out.name, "voucher_type": "Delivery Note" }, "stock_value_difference", ) self.assertEqual(value_diff, -113)
def test_customer_credit_limit(self): from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice outstanding_amt = self.get_customer_outstanding_amount() credit_limit = get_credit_limit('_Test Customer', '_Test Company') if outstanding_amt <= 0.0: item_qty = int((abs(outstanding_amt) + 200)/100) make_sales_order(qty=item_qty) if credit_limit == 0.0: frappe.db.set_value("Customer", '_Test Customer', 'credit_limit', outstanding_amt - 50.0) # Sales Order so = make_sales_order(do_not_submit=True) self.assertRaises(frappe.ValidationError, so.submit) # Delivery Note dn = create_delivery_note(do_not_submit=True) self.assertRaises(frappe.ValidationError, dn.submit) # Sales Invoice si = create_sales_invoice(do_not_submit=True) self.assertRaises(frappe.ValidationError, si.submit) if credit_limit > outstanding_amt: frappe.db.set_value("Customer", '_Test Customer', 'credit_limit', credit_limit) # Makes Sales invoice from Sales Order so.save(ignore_permissions=True) si = make_sales_invoice(so.name) si.save(ignore_permissions=True) self.assertRaises(frappe.ValidationError, make_sales_order)
def test_serialized_lcv_delivered(self): """In some cases you'd want to deliver before you can know all the landed costs, this should be allowed for serial nos too. Case: - receipt a serial no @ X rate - delivery the serial no @ X rate - add LCV to receipt X + Y - LCV should be successful - delivery should reflect X+Y valuation. """ serial_no = "LCV_TEST_SR_NO" item_code = "_Test Serialized Item" warehouse = "Stores - TCP1" pr = make_purchase_receipt( company="_Test Company with perpetual inventory", warehouse=warehouse, qty=1, rate=200, item_code=item_code, serial_no=serial_no, ) serial_no_rate = frappe.db.get_value("Serial No", serial_no, "purchase_rate") # deliver it before creating LCV dn = create_delivery_note( item_code=item_code, company="_Test Company with perpetual inventory", warehouse="Stores - TCP1", serial_no=serial_no, qty=1, rate=500, cost_center="Main - TCP1", expense_account="Cost of Goods Sold - TCP1", ) charges = 10 create_landed_cost_voucher("Purchase Receipt", pr.name, pr.company, charges=charges) new_purchase_rate = serial_no_rate + charges serial_no = frappe.db.get_value("Serial No", serial_no, ["warehouse", "purchase_rate"], as_dict=1) self.assertEqual(serial_no.purchase_rate, new_purchase_rate) stock_value_difference = frappe.db.get_value( "Stock Ledger Entry", filters={ "voucher_no": dn.name, "voucher_type": dn.doctype, "is_cancelled": 0, # LCV cancels with same name. }, fieldname="stock_value_difference", ) # reposting should update the purchase rate in future delivery self.assertEqual(stock_value_difference, -new_purchase_rate)
def test_inter_company_transfer_intermediate_cancellation(self): """ Receive into and Deliver Serial No from one company. Then Receive into and Deliver from second company. Try to cancel intermediate receipts/deliveries to test if it is blocked. """ se = make_serialized_item(target_warehouse="_Test Warehouse - _TC") serial_nos = get_serial_nos(se.get("items")[0].serial_no) sn_doc = frappe.get_doc("Serial No", serial_nos[0]) # check Serial No details after purchase in first company self.assertEqual(sn_doc.status, "Active") self.assertEqual(sn_doc.company, "_Test Company") self.assertEqual(sn_doc.warehouse, "_Test Warehouse - _TC") self.assertEqual(sn_doc.purchase_document_no, se.name) dn = create_delivery_note( item_code="_Test Serialized Item With Series", qty=1, serial_no=serial_nos[0]) sn_doc.reload() # check Serial No details after delivery from **first** company self.assertEqual(sn_doc.status, "Delivered") self.assertEqual(sn_doc.company, "_Test Company") self.assertEqual(sn_doc.warehouse, None) self.assertEqual(sn_doc.delivery_document_no, dn.name) # try cancelling the first Serial No Receipt, even though it is delivered # block cancellation is Serial No is out of the warehouse self.assertRaises(frappe.ValidationError, se.cancel) # receive serial no in second company wh = create_warehouse("_Test Warehouse", company="_Test Company 1") pr = make_purchase_receipt( item_code="_Test Serialized Item With Series", qty=1, serial_no=serial_nos[0], company="_Test Company 1", warehouse=wh) sn_doc.reload() self.assertEqual(sn_doc.warehouse, wh) # try cancelling the delivery from the first company # block cancellation as Serial No belongs to different company self.assertRaises(frappe.ValidationError, dn.cancel) # deliver from second company dn_2 = create_delivery_note( item_code="_Test Serialized Item With Series", qty=1, serial_no=serial_nos[0], company="_Test Company 1", warehouse=wh) sn_doc.reload() # check Serial No details after delivery from **second** company self.assertEqual(sn_doc.status, "Delivered") self.assertEqual(sn_doc.company, "_Test Company 1") self.assertEqual(sn_doc.warehouse, None) self.assertEqual(sn_doc.delivery_document_no, dn_2.name) # cannot cancel any intermediate document before last Delivery Note self.assertRaises(frappe.ValidationError, se.cancel) self.assertRaises(frappe.ValidationError, dn.cancel) self.assertRaises(frappe.ValidationError, pr.cancel)
def test_inter_company_transfer_fallback_on_cancel(self): """ Test Serial No state changes on cancellation. If Delivery cancelled, it should fall back on last Receipt in the same company. If Receipt is cancelled, it should be Inactive in the same company. """ # Receipt in **first** company se = make_serialized_item(target_warehouse="_Test Warehouse - _TC") serial_nos = get_serial_nos(se.get("items")[0].serial_no) sn_doc = frappe.get_doc("Serial No", serial_nos[0]) # Delivery from first company dn = create_delivery_note( item_code="_Test Serialized Item With Series", qty=1, serial_no=serial_nos[0]) # Receipt in **second** company wh = create_warehouse("_Test Warehouse", company="_Test Company 1") pr = make_purchase_receipt( item_code="_Test Serialized Item With Series", qty=1, serial_no=serial_nos[0], company="_Test Company 1", warehouse=wh) # Delivery from second company dn_2 = create_delivery_note( item_code="_Test Serialized Item With Series", qty=1, serial_no=serial_nos[0], company="_Test Company 1", warehouse=wh) sn_doc.reload() self.assertEqual(sn_doc.status, "Delivered") self.assertEqual(sn_doc.company, "_Test Company 1") self.assertEqual(sn_doc.delivery_document_no, dn_2.name) dn_2.cancel() sn_doc.reload() # Fallback on Purchase Receipt if Delivery is cancelled self.assertEqual(sn_doc.status, "Active") self.assertEqual(sn_doc.company, "_Test Company 1") self.assertEqual(sn_doc.warehouse, wh) self.assertEqual(sn_doc.purchase_document_no, pr.name) pr.cancel() sn_doc.reload() # Inactive in same company if Receipt cancelled self.assertEqual(sn_doc.status, "Inactive") self.assertEqual(sn_doc.company, "_Test Company 1") self.assertEqual(sn_doc.warehouse, None) dn.cancel() sn_doc.reload() # Fallback on Purchase Receipt in FIRST company if # Delivery from FIRST company is cancelled self.assertEqual(sn_doc.status, "Active") self.assertEqual(sn_doc.company, "_Test Company") self.assertEqual(sn_doc.warehouse, "_Test Warehouse - _TC") self.assertEqual(sn_doc.purchase_document_no, se.name)
def test_reposting_of_sales_return_for_packed_item(self): company = "_Test Company" packed_item_code = "_Test Item for Reposting" bundled_item = "_Test Bundled Item for Reposting" create_product_bundle_item(bundled_item, [[packed_item_code, 4]]) # Purchase Return: Qty = 50, Rate = 100 pr = make_purchase_receipt(company=company, posting_date='2020-04-10', warehouse="Stores - _TC", item_code=packed_item_code, qty=50, rate=100) #Delivery Note: Qty = 5, Rate = 150 dn = create_delivery_note(item_code=bundled_item, qty=5, rate=150, warehouse="Stores - _TC", company=company, expense_account="Cost of Goods Sold - _TC", cost_center="Main - _TC") # check outgoing_rate for DN outgoing_rate = abs( frappe.db.get_value("Stock Ledger Entry", { "voucher_type": "Delivery Note", "voucher_no": dn.name }, "stock_value_difference") / 20) self.assertEqual(dn.packed_items[0].incoming_rate, 100) self.assertEqual(outgoing_rate, 100) # Return Entry: Qty = -2, Rate = 150 return_dn = create_delivery_note( is_return=1, return_against=dn.name, item_code=bundled_item, qty=-2, rate=150, company=company, warehouse="Stores - _TC", expense_account="Cost of Goods Sold - _TC", cost_center="Main - _TC") # check incoming rate for Return entry incoming_rate, stock_value_difference = frappe.db.get_value( "Stock Ledger Entry", { "voucher_type": "Delivery Note", "voucher_no": return_dn.name }, ["incoming_rate", "stock_value_difference"]) self.assertEqual(return_dn.packed_items[0].incoming_rate, 100) self.assertEqual(incoming_rate, 100) self.assertEqual(stock_value_difference, 800) #------------------------------- # Landed Cost Voucher to update the rate of incoming Purchase Return: Additional cost = 50 lcv = create_landed_cost_voucher("Purchase Receipt", pr.name, pr.company) # check outgoing_rate for DN after reposting outgoing_rate = abs( frappe.db.get_value("Stock Ledger Entry", { "voucher_type": "Delivery Note", "voucher_no": dn.name }, "stock_value_difference") / 20) self.assertEqual(outgoing_rate, 101) dn.reload() self.assertEqual(dn.packed_items[0].incoming_rate, 101) # check incoming rate for Return entry after reposting incoming_rate, stock_value_difference = frappe.db.get_value( "Stock Ledger Entry", { "voucher_type": "Delivery Note", "voucher_no": return_dn.name }, ["incoming_rate", "stock_value_difference"]) self.assertEqual(incoming_rate, 101) self.assertEqual(stock_value_difference, 808) return_dn.reload() self.assertEqual(return_dn.packed_items[0].incoming_rate, 101) # Cleanup data return_dn.cancel() dn.cancel() lcv.cancel() pr.cancel()
def test_qa_not_submit(self): dn = create_delivery_note(item_code="_Test Item with QA", do_not_submit=True) qa = create_quality_inspection(reference_type="Delivery Note", reference_name=dn.name, submit = False) dn.items[0].quality_inspection = qa.name self.assertRaises(QualityInspectionNotSubmittedError, dn.submit)