import json import frappe from frappe.tests.utils import FrappeTestCase from erpnext.stock.utils import scan_barcode class StockTestMixin: """Mixin to simplfy stock ledger tests, useful for all stock transactions.""" def make_item(self, item_code=None, properties=None, *args, **kwargs): from erpnext.stock.doctype.item.test_item import make_item return make_item(item_code, properties, *args, **kwargs) def assertSLEs(self, doc, expected_sles, sle_filters=None): """Compare sorted SLEs, useful for vouchers that create multiple SLEs for same line""" filters = {"voucher_no": doc.name, "voucher_type": doc.doctype, "is_cancelled": 0} if sle_filters: filters.update(sle_filters) sles = frappe.get_all( "Stock Ledger Entry", fields=["*"], filters=filters, order_by="timestamp(posting_date, posting_time), creation", ) self.assertGreaterEqual(len(sles), len(expected_sles)) for exp_sle, act_sle in zip(expected_sles, sles): for k, v in exp_sle.items(): act_value = act_sle[k] if k == "stock_queue": act_value = json.loads(act_value) if act_value and act_value[0][0] == 0: # ignore empty fifo bins continue self.assertEqual(v, act_value, msg=f"{k} doesn't match \n{exp_sle}\n{act_sle}") def assertGLEs(self, doc, expected_gles, gle_filters=None, order_by=None): filters = {"voucher_no": doc.name, "voucher_type": doc.doctype, "is_cancelled": 0} if gle_filters: filters.update(gle_filters) actual_gles = frappe.get_all( "GL Entry", fields=["*"], filters=filters, order_by=order_by or "posting_date, creation", ) self.assertGreaterEqual(len(actual_gles), len(expected_gles)) for exp_gle, act_gle in zip(expected_gles, actual_gles): for k, exp_value in exp_gle.items(): act_value = act_gle[k] self.assertEqual(exp_value, act_value, msg=f"{k} doesn't match \n{exp_gle}\n{act_gle}") class TestStockUtilities(FrappeTestCase, StockTestMixin): def test_barcode_scanning(self): simple_item = self.make_item(properties={"barcodes": [{"barcode": "12399"}]}) self.assertEqual(scan_barcode("12399")["item_code"], simple_item.name) batch_item = self.make_item(properties={"has_batch_no": 1, "create_new_batch": 1}) batch = frappe.get_doc(doctype="Batch", item=batch_item.name).insert() batch_scan = scan_barcode(batch.name) self.assertEqual(batch_scan["item_code"], batch_item.name) self.assertEqual(batch_scan["batch_no"], batch.name) self.assertEqual(batch_scan["has_batch_no"], 1) self.assertEqual(batch_scan["has_serial_no"], 0) serial_item = self.make_item(properties={"has_serial_no": 1}) serial = frappe.get_doc( doctype="Serial No", item_code=serial_item.name, serial_no=frappe.generate_hash() ).insert() serial_scan = scan_barcode(serial.name) self.assertEqual(serial_scan["item_code"], serial_item.name) self.assertEqual(serial_scan["serial_no"], serial.name) self.assertEqual(serial_scan["has_batch_no"], 0) self.assertEqual(serial_scan["has_serial_no"], 1)