def test_alternative_item_for_production_rm(self): create_stock_reconciliation(item_code='Alternate Item For A RW 1', warehouse='_Test Warehouse - _TC', qty=5, rate=2000) create_stock_reconciliation(item_code='Test FG A RW 2', warehouse='_Test Warehouse - _TC', qty=5, rate=2000) pro_order = make_wo_order_test_record( production_item='Test Finished Goods - A', qty=5, source_warehouse='_Test Warehouse - _TC', wip_warehouse='Test Supplier Warehouse - _TC') reserved_qty_for_production = frappe.db.get_value( 'Bin', { 'item_code': 'Test FG A RW 1', 'warehouse': '_Test Warehouse - _TC' }, 'reserved_qty_for_production') ste = frappe.get_doc( make_stock_entry(pro_order.name, "Material Transfer for Manufacture", 5)) ste.insert() for item in ste.items: if item.item_code == 'Test FG A RW 1': item.item_code = 'Alternate Item For A RW 1' item.item_name = 'Alternate Item For A RW 1' item.description = 'Alternate Item For A RW 1' item.original_item = 'Test FG A RW 1' ste.submit() reserved_qty_for_production_after_transfer = frappe.db.get_value( 'Bin', { 'item_code': 'Test FG A RW 1', 'warehouse': '_Test Warehouse - _TC' }, 'reserved_qty_for_production') self.assertEqual(reserved_qty_for_production_after_transfer, flt(reserved_qty_for_production - 5)) ste1 = frappe.get_doc( make_stock_entry(pro_order.name, "Manufacture", 5)) status = False for d in ste1.items: if d.item_code == 'Alternate Item For A RW 1': status = True self.assertEqual(status, True) ste1.submit()
def test_fifo(self): frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1) item_code = "_Test Item 2" warehouse = "_Test Warehouse - _TC" create_stock_reconciliation(item_code="_Test Item 2", warehouse="_Test Warehouse - _TC", qty=0, rate=100) make_stock_entry(item_code=item_code, target=warehouse, qty=1, basic_rate=10) sle = get_sle(item_code=item_code, warehouse=warehouse)[0] self.assertEqual([[1, 10]], frappe.safe_eval(sle.stock_queue)) # negative qty make_stock_entry(item_code=item_code, source=warehouse, qty=2, basic_rate=10) sle = get_sle(item_code=item_code, warehouse=warehouse)[0] self.assertEqual([[-1, 10]], frappe.safe_eval(sle.stock_queue)) # further negative make_stock_entry(item_code=item_code, source=warehouse, qty=1) sle = get_sle(item_code=item_code, warehouse=warehouse)[0] self.assertEqual([[-2, 10]], frappe.safe_eval(sle.stock_queue)) # move stock to positive make_stock_entry(item_code=item_code, target=warehouse, qty=3, basic_rate=20) sle = get_sle(item_code=item_code, warehouse=warehouse)[0] self.assertEqual([[1, 20]], frappe.safe_eval(sle.stock_queue)) # incoming entry with diff rate make_stock_entry(item_code=item_code, target=warehouse, qty=1, basic_rate=30) sle = get_sle(item_code=item_code, warehouse=warehouse)[0] self.assertEqual([[1, 20], [1, 30]], frappe.safe_eval(sle.stock_queue)) frappe.db.set_default("allow_negative_stock", 0)
def test_production_plan_for_existing_ordered_qty(self): sr1 = create_stock_reconciliation(item_code="Raw Material Item 1", target="_Test Warehouse - _TC", qty=1, rate=110) sr2 = create_stock_reconciliation(item_code="Raw Material Item 2", target="_Test Warehouse - _TC", qty=1, rate=120) pln = create_production_plan(item_code='Test Production Item 1', ignore_existing_ordered_qty=0) self.assertTrue(len(pln.mr_items), 1) self.assertTrue(flt(pln.mr_items[0].quantity), 1.0) sr1.cancel() sr2.cancel() pln.cancel()
def test_production_plan_without_multi_level_for_existing_ordered_qty( self): sr1 = create_stock_reconciliation(item_code="Raw Material Item 1", target="_Test Warehouse - _TC", qty=1, rate=130) sr2 = create_stock_reconciliation(item_code="Subassembly Item 1", target="_Test Warehouse - _TC", qty=1, rate=140) pln = create_production_plan(item_code='Test Production Item 1', use_multi_level_bom=0, ignore_existing_ordered_qty=0) self.assertTrue(len(pln.mr_items), 0) sr1.cancel() sr2.cancel() pln.cancel()
def _test_auto_material_request(self, item_code, material_request_type="Purchase", warehouse="_Test Warehouse - _TC"): variant = frappe.get_doc("Item", item_code) projected_qty, actual_qty = frappe.db.get_value( "Bin", { "item_code": item_code, "warehouse": warehouse }, ["projected_qty", "actual_qty"]) or [0, 0] # stock entry reqd for auto-reorder create_stock_reconciliation(item_code=item_code, warehouse=warehouse, qty=actual_qty + abs(projected_qty) + 10, rate=100) projected_qty = frappe.db.get_value("Bin", { "item_code": item_code, "warehouse": warehouse }, "projected_qty") or 0 frappe.db.set_value("Stock Settings", None, "auto_indent", 1) # update re-level qty so that it is more than projected_qty if projected_qty >= variant.reorder_levels[0].warehouse_reorder_level: variant.reorder_levels[0].warehouse_reorder_level += projected_qty variant.reorder_levels[ 0].material_request_type = material_request_type variant.save() from erpbee.stock.reorder_item import reorder_item mr_list = reorder_item() frappe.db.set_value("Stock Settings", None, "auto_indent", 0) items = [] for mr in mr_list: for d in mr.items: items.append(d.item_code) self.assertTrue(item_code in items)
def reset_item_valuation_rate(item_code, warehouse_list=None, qty=None, rate=None): if warehouse_list and isinstance(warehouse_list, string_types): warehouse_list = [warehouse_list] if not warehouse_list: warehouse_list = frappe.db.sql_list( """ select warehouse from `tabBin` where item_code=%s and actual_qty > 0 """, item_code) if not warehouse_list: warehouse_list.append("_Test Warehouse - _TC") for warehouse in warehouse_list: create_stock_reconciliation(item_code=item_code, warehouse=warehouse, qty=qty, rate=rate)
def make_items(): items = [ 'Test Finished Goods - A', 'Test FG A RW 1', 'Test FG A RW 2', 'Alternate Item For A RW 1' ] for item_code in items: if not frappe.db.exists('Item', item_code): create_item(item_code) create_stock_reconciliation(item_code="Test FG A RW 1", warehouse='_Test Warehouse - _TC', qty=10, rate=2000) if frappe.db.exists('Item', 'Test FG A RW 1'): doc = frappe.get_doc('Item', 'Test FG A RW 1') doc.allow_alternative_item = 1 doc.save() if frappe.db.exists('Item', 'Test Finished Goods - A'): doc = frappe.get_doc('Item', 'Test Finished Goods - A') doc.is_sub_contracted_item = 1 doc.save() if not frappe.db.get_value('BOM', { 'item': 'Test Finished Goods - A', 'docstatus': 1 }): make_bom(item='Test Finished Goods - A', raw_materials=['Test FG A RW 1', 'Test FG A RW 2']) if not frappe.db.get_value('Warehouse', {'warehouse_name': 'Test Supplier Warehouse'}): frappe.get_doc({ 'doctype': 'Warehouse', 'warehouse_name': 'Test Supplier Warehouse', 'company': '_Test Company' }).insert(ignore_permissions=True)
def test_item_cost_reposting(self): company = "_Test Company" # _Test Item for Reposting at Stores warehouse on 10-04-2020: Qty = 50, Rate = 100 create_stock_reconciliation(item_code="_Test Item for Reposting", warehouse="Stores - _TC", qty=50, rate=100, company=company, expense_account="Stock Adjustment - _TC", posting_date='2020-04-10', posting_time='14:00') # _Test Item for Reposting at FG warehouse on 20-04-2020: Qty = 10, Rate = 200 create_stock_reconciliation(item_code="_Test Item for Reposting", warehouse="Finished Goods - _TC", qty=10, rate=200, company=company, expense_account="Stock Adjustment - _TC", posting_date='2020-04-20', posting_time='14:00') # _Test Item for Reposting transferred from Stores to FG warehouse on 30-04-2020 make_stock_entry(item_code="_Test Item for Reposting", source="Stores - _TC", target="Finished Goods - _TC", company=company, qty=10, expense_account="Stock Adjustment - _TC", posting_date='2020-04-30', posting_time='14:00') target_wh_sle = get_previous_sle({ "item_code": "_Test Item for Reposting", "warehouse": "Finished Goods - _TC", "posting_date": '2020-04-30', "posting_time": '14:00' }) self.assertEqual(target_wh_sle.get("valuation_rate"), 150) # Repack entry on 5-5-2020 repack = create_repack_entry(company=company, posting_date='2020-05-05', posting_time='14:00') finished_item_sle = get_previous_sle({ "item_code": "_Test Finished Item for Reposting", "warehouse": "Finished Goods - _TC", "posting_date": '2020-05-05', "posting_time": '14:00' }) self.assertEqual(finished_item_sle.get("incoming_rate"), 540) self.assertEqual(finished_item_sle.get("valuation_rate"), 540) # Reconciliation for _Test Item for Reposting at Stores on 12-04-2020: Qty = 50, Rate = 150 create_stock_reconciliation(item_code="_Test Item for Reposting", warehouse="Stores - _TC", qty=50, rate=150, company=company, expense_account="Stock Adjustment - _TC", posting_date='2020-04-12', posting_time='14:00') # Check valuation rate of finished goods warehouse after back-dated entry at Stores target_wh_sle = get_previous_sle({ "item_code": "_Test Item for Reposting", "warehouse": "Finished Goods - _TC", "posting_date": '2020-04-30', "posting_time": '14:00' }) self.assertEqual(target_wh_sle.get("incoming_rate"), 150) self.assertEqual(target_wh_sle.get("valuation_rate"), 175) # Check valuation rate of repacked item after back-dated entry at Stores finished_item_sle = get_previous_sle({ "item_code": "_Test Finished Item for Reposting", "warehouse": "Finished Goods - _TC", "posting_date": '2020-05-05', "posting_time": '14:00' }) self.assertEqual(finished_item_sle.get("incoming_rate"), 790) self.assertEqual(finished_item_sle.get("valuation_rate"), 790) # Check updated rate in Repack entry repack.reload() self.assertEqual(repack.items[0].get("basic_rate"), 150) self.assertEqual(repack.items[1].get("basic_rate"), 750)
def test_delivery_of_bundled_items_to_target_warehouse(self): company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company') set_valuation_method("_Test Item", "FIFO") set_valuation_method("_Test Item Home Desktop 100", "FIFO") target_warehouse = get_warehouse( company=company, abbr="TCP1", warehouse_name="_Test Customer Warehouse").name for warehouse in ("Stores - TCP1", target_warehouse): create_stock_reconciliation( item_code="_Test Item", warehouse=warehouse, company=company, expense_account="Stock Adjustment - TCP1", qty=500, rate=100) create_stock_reconciliation( item_code="_Test Item Home Desktop 100", company=company, expense_account="Stock Adjustment - TCP1", warehouse=warehouse, qty=500, rate=100) dn = create_delivery_note( item_code="_Test Product Bundle Item", company='_Test Company with perpetual inventory', cost_center='Main - TCP1', expense_account="Cost of Goods Sold - TCP1", do_not_submit=True, qty=5, rate=500, warehouse="Stores - TCP1", target_warehouse=target_warehouse) dn.submit() # qty after delivery actual_qty_at_source = get_qty_after_transaction( warehouse="Stores - TCP1") self.assertEqual(actual_qty_at_source, 475) actual_qty_at_target = get_qty_after_transaction( warehouse=target_warehouse) self.assertEqual(actual_qty_at_target, 525) # stock value diff for source warehouse for "_Test Item" stock_value_difference = frappe.db.get_value( "Stock Ledger Entry", { "voucher_type": "Delivery Note", "voucher_no": dn.name, "item_code": "_Test Item", "warehouse": "Stores - TCP1" }, "stock_value_difference") # stock value diff for target warehouse stock_value_difference1 = frappe.db.get_value( "Stock Ledger Entry", { "voucher_type": "Delivery Note", "voucher_no": dn.name, "item_code": "_Test Item", "warehouse": target_warehouse }, "stock_value_difference") self.assertEqual(abs(stock_value_difference), stock_value_difference1) # Check gl entries gl_entries = get_gl_entries("Delivery Note", dn.name) self.assertTrue(gl_entries) stock_value_difference = abs( frappe.db.sql( """select sum(stock_value_difference) from `tabStock Ledger Entry` where voucher_type='Delivery Note' and voucher_no=%s and warehouse='Stores - TCP1'""", dn.name)[0][0]) expected_values = { "Stock In Hand - TCP1": [0.0, stock_value_difference], target_warehouse: [stock_value_difference, 0.0] } for i, gle in enumerate(gl_entries): self.assertEqual([gle.debit, gle.credit], expected_values.get(gle.account))
def test_return_entire_bundled_items(self): company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company') create_stock_reconciliation(item_code="_Test Item", warehouse="Stores - TCP1", qty=50, rate=100, company=company, expense_account="Stock Adjustment - TCP1") create_stock_reconciliation(item_code="_Test Item Home Desktop 100", warehouse="Stores - TCP1", qty=50, rate=100, company=company, expense_account="Stock Adjustment - TCP1") actual_qty = get_qty_after_transaction(warehouse="Stores - TCP1") self.assertEqual(actual_qty, 50) dn = create_delivery_note(item_code="_Test Product Bundle Item", qty=5, rate=500, company=company, warehouse="Stores - TCP1", expense_account="Cost of Goods Sold - TCP1", cost_center="Main - TCP1") # qty after return actual_qty = get_qty_after_transaction(warehouse="Stores - TCP1") self.assertEqual(actual_qty, 25) # return bundled item dn1 = create_delivery_note(item_code='_Test Product Bundle Item', is_return=1, return_against=dn.name, qty=-2, rate=500, company=company, warehouse="Stores - TCP1", expense_account="Cost of Goods Sold - TCP1", cost_center="Main - TCP1") # qty after return actual_qty = get_qty_after_transaction(warehouse="Stores - TCP1") self.assertEqual(actual_qty, 35) # Check incoming rate for return entry incoming_rate, stock_value_difference = frappe.db.get_value( "Stock Ledger Entry", { "voucher_type": "Delivery Note", "voucher_no": dn1.name }, ["incoming_rate", "stock_value_difference"]) self.assertEqual(incoming_rate, 100) stock_in_hand_account = get_inventory_account('_Test Company', dn1.items[0].warehouse) # Check gl entry for warehouse gle_warehouse_amount = frappe.db.get_value( "GL Entry", { "voucher_type": "Delivery Note", "voucher_no": dn1.name, "account": stock_in_hand_account }, "debit") self.assertEqual(gle_warehouse_amount, 1400)
def test_return_single_item_from_bundled_items(self): company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company') create_stock_reconciliation(item_code="_Test Item", warehouse="Stores - TCP1", qty=50, rate=100, company=company, expense_account="Stock Adjustment - TCP1") create_stock_reconciliation(item_code="_Test Item Home Desktop 100", warehouse="Stores - TCP1", qty=50, rate=100, company=company, expense_account="Stock Adjustment - TCP1") dn = create_delivery_note(item_code="_Test Product Bundle Item", qty=5, rate=500, company=company, warehouse="Stores - TCP1", expense_account="Cost of Goods Sold - TCP1", cost_center="Main - TCP1") # Qty after delivery actual_qty_1 = get_qty_after_transaction(warehouse="Stores - TCP1") self.assertEqual(actual_qty_1, 25) # outgoing_rate outgoing_rate = frappe.db.get_value( "Stock Ledger Entry", { "voucher_type": "Delivery Note", "voucher_no": dn.name, "item_code": "_Test Item" }, "stock_value_difference") / 25 # return 'test item' from packed items dn1 = create_delivery_note(is_return=1, return_against=dn.name, qty=-10, rate=500, company=company, warehouse="Stores - TCP1", expense_account="Cost of Goods Sold - TCP1", cost_center="Main - TCP1") # qty after return actual_qty_2 = get_qty_after_transaction(warehouse="Stores - TCP1") self.assertEqual(actual_qty_2, 35) # Check incoming rate for return entry incoming_rate, stock_value_difference = frappe.db.get_value( "Stock Ledger Entry", { "voucher_type": "Delivery Note", "voucher_no": dn1.name }, ["incoming_rate", "stock_value_difference"]) self.assertEqual(flt(incoming_rate, 3), abs(flt(outgoing_rate, 3))) stock_in_hand_account = get_inventory_account(company, dn1.items[0].warehouse) # Check gl entry for warehouse gle_warehouse_amount = frappe.db.get_value( "GL Entry", { "voucher_type": "Delivery Note", "voucher_no": dn1.name, "account": stock_in_hand_account }, "debit") self.assertEqual(gle_warehouse_amount, stock_value_difference)
def test_alternative_item_for_subcontract_rm(self): create_stock_reconciliation(item_code='Alternate Item For A RW 1', warehouse='_Test Warehouse - _TC', qty=5, rate=2000) create_stock_reconciliation(item_code='Test FG A RW 2', warehouse='_Test Warehouse - _TC', qty=5, rate=2000) supplier_warehouse = "Test Supplier Warehouse - _TC" po = create_purchase_order(item="Test Finished Goods - A", is_subcontracted='Yes', qty=5, rate=3000, supplier_warehouse=supplier_warehouse) rm_item = [{ "item_code": "Test Finished Goods - A", "rm_item_code": "Test FG A RW 1", "item_name": "Test FG A RW 1", "qty": 5, "warehouse": "_Test Warehouse - _TC", "rate": 2000, "amount": 10000, "stock_uom": "Nos" }, { "item_code": "Test Finished Goods - A", "rm_item_code": "Test FG A RW 2", "item_name": "Test FG A RW 2", "qty": 5, "warehouse": "_Test Warehouse - _TC", "rate": 2000, "amount": 10000, "stock_uom": "Nos" }] rm_item_string = json.dumps(rm_item) reserved_qty_for_sub_contract = frappe.db.get_value( 'Bin', { 'item_code': 'Test FG A RW 1', 'warehouse': '_Test Warehouse - _TC' }, 'reserved_qty_for_sub_contract') se = frappe.get_doc(make_rm_stock_entry(po.name, rm_item_string)) se.to_warehouse = supplier_warehouse se.insert() doc = frappe.get_doc('Stock Entry', se.name) for item in doc.items: if item.item_code == 'Test FG A RW 1': item.item_code = 'Alternate Item For A RW 1' item.item_name = 'Alternate Item For A RW 1' item.description = 'Alternate Item For A RW 1' item.original_item = 'Test FG A RW 1' doc.save() doc.submit() after_transfer_reserved_qty_for_sub_contract = frappe.db.get_value( 'Bin', { 'item_code': 'Test FG A RW 1', 'warehouse': '_Test Warehouse - _TC' }, 'reserved_qty_for_sub_contract') self.assertEqual(after_transfer_reserved_qty_for_sub_contract, flt(reserved_qty_for_sub_contract - 5)) pr = make_purchase_receipt(po.name) pr.save() pr = frappe.get_doc('Purchase Receipt', pr.name) status = False for d in pr.supplied_items: if d.rm_item_code == 'Alternate Item For A RW 1': status = True self.assertEqual(status, True)