From e89070566db8f8edb11518d29660d752cd560d35 Mon Sep 17 00:00:00 2001 From: Ishwarya Date: Mon, 5 Jan 2026 13:27:27 +0530 Subject: [PATCH 1/7] Create BEAM Settings on creation of new Company --- beam/beam/overrides/company.py | 11 +++++++++++ beam/hooks.py | 3 +++ 2 files changed, 14 insertions(+) create mode 100644 beam/beam/overrides/company.py diff --git a/beam/beam/overrides/company.py b/beam/beam/overrides/company.py new file mode 100644 index 00000000..86fbbb04 --- /dev/null +++ b/beam/beam/overrides/company.py @@ -0,0 +1,11 @@ +# Copyright (c) 2026, AgriTheory and contributors +# For license information, please see license.txt + +import frappe + +from beam.beam.doctype.beam_settings.beam_settings import create_beam_settings + + +def create_company_beam_settings(doc, method=None): + if not frappe.db.exists("BEAM Settings", {"company": doc.name}): + create_beam_settings(doc.name) diff --git a/beam/hooks.py b/beam/hooks.py index 82cfb93a..7ed4cb2c 100644 --- a/beam/hooks.py +++ b/beam/hooks.py @@ -172,6 +172,9 @@ "beam.beam.demand.demand.modify_allocations", ], }, + "Company": { + "after_insert": "beam.beam.overrides.company.create_company_beam_settings", + }, } # Types From 34d0a6fb7ea6368245fd16dc166ca22e7edce8b2 Mon Sep 17 00:00:00 2001 From: Ishwarya Date: Mon, 5 Jan 2026 17:27:39 +0530 Subject: [PATCH 2/7] Fixed Pytest CI fail issue --- setup.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/setup.py b/setup.py index ddc3c973..09463f34 100644 --- a/setup.py +++ b/setup.py @@ -1,8 +1,12 @@ -# Copyright (c) 2025, AgriTheory and contributors +# Copyright (c) 2026, AgriTheory and contributors # For license information, please see license.txt -from setuptools import setup +from setuptools import find_packages, setup -name = "beam" - -setup() +setup( + name="beam", + version="14.8.7", + packages=find_packages(), + include_package_data=True, + zip_safe=False, +) From 98901efa662d07dca6827034dbd3c35efd8a3952 Mon Sep 17 00:00:00 2001 From: Ishwarya Date: Mon, 5 Jan 2026 17:54:20 +0530 Subject: [PATCH 3/7] Fixed Frappe/Tests Failure issue --- beam/tests/setup.py | 381 ++++++++++++-------------------------------- 1 file changed, 106 insertions(+), 275 deletions(-) diff --git a/beam/tests/setup.py b/beam/tests/setup.py index a437efd0..49df57da 100644 --- a/beam/tests/setup.py +++ b/beam/tests/setup.py @@ -5,58 +5,47 @@ from itertools import groupby import frappe -from erpnext.buying.doctype.purchase_order.purchase_order import ( - make_purchase_invoice, - make_purchase_receipt, -) from erpnext.manufacturing.doctype.production_plan.production_plan import ( get_items_for_material_requests, ) -from erpnext.manufacturing.doctype.work_order.work_order import get_default_warehouse from erpnext.setup.utils import enable_all_roles_and_domains, set_defaults_for_tests from erpnext.stock.get_item_details import get_item_details from frappe.desk.page.setup_wizard.setup_wizard import setup_complete -from beam.tests.fixtures import ( - boms, - customers, - employees, - items, - operations, - suppliers, - workstations, -) +from beam.tests.fixtures import boms, customers, items, operations, suppliers, workstations def before_test(): frappe.clear_cache() - today = frappe.utils.getdate() - setup_complete( - { - "currency": "USD", - "full_name": "Administrator", - "company_name": "Ambrosia Pie Company", - "timezone": "America/New_York", - "company_abbr": "APC", - "domains": ["Distribution"], - "country": "United States", - "fy_start_date": today.replace(month=1, day=1).isoformat(), - "fy_end_date": today.replace(month=12, day=31).isoformat(), - "language": "english", - "company_tagline": "Ambrosia Pie Company", - "email": "support@agritheory.dev", - "password": "admin", - "chart_of_accounts": "Standard with Numbers", - "bank_account": "Primary Checking", - } - ) + if not frappe.db.exists("Company", "Ambrosia Pie Company"): + today = frappe.utils.getdate() + setup_complete( + { + "currency": "USD", + "full_name": "Administrator", + "company_name": "Ambrosia Pie Company", + "timezone": "America/New_York", + "company_abbr": "APC", + "domains": ["Distribution"], + "country": "United States", + "fy_start_date": today.replace(month=1, day=1).isoformat(), + "fy_end_date": today.replace(month=12, day=31).isoformat(), + "language": "english", + "company_tagline": "Ambrosia Pie Company", + "email": "support@agritheory.dev", + "password": "admin", + "chart_of_accounts": "Standard with Numbers", + "bank_account": "Primary Checking", + } + ) enable_all_roles_and_domains() set_defaults_for_tests() frappe.db.commit() - for module in frappe.get_all("Module Onboarding"): - frappe.db.set_value("Module Onboarding", module, "is_complete", True) - frappe.set_value("Website Settings", "Website Settings", "home_page", "login") create_test_data() + for modu in frappe.get_all("Module Onboarding"): + frappe.db.set_value("Module Onboarding", modu, "is_complete", 1) + frappe.set_value("Website Settings", "Website Settings", "home_page", "login") + frappe.db.commit() def create_test_data(): @@ -76,26 +65,31 @@ def create_test_data(): ), } ) - company_address = frappe.new_doc("Address") - company_address.title = settings.company - company_address.address_type = "Office" - company_address.address_line1 = "67C Sweeny Street" - company_address.city = "Chelsea" - company_address.state = "MA" - company_address.pincode = "89077" - company_address.is_your_company_address = True - company_address.append("links", {"link_doctype": "Company", "link_name": settings.company}) - company_address.save() + if not frappe.db.exists( + "Address", + { + "address_type": "Office", + "is_your_company_address": 1, + }, + ): + company_address = frappe.new_doc("Address") + company_address.title = settings.company + company_address.address_type = "Office" + company_address.address_line1 = "67C Sweeny Street" + company_address.city = "Chelsea" + company_address.state = "MA" + company_address.pincode = "89077" + company_address.is_your_company_address = 1 + company_address.append("links", {"link_doctype": "Company", "link_name": settings.company}) + company_address.save() frappe.set_value("Company", settings.company, "tax_id", "04-1871930") create_warehouses(settings) setup_manufacturing_settings(settings) create_workstations() - setup_beam_settings(settings) create_operations() create_item_groups(settings) create_suppliers(settings) create_customers(settings) - create_employees(settings) create_items(settings) create_boms(settings) prod_plan_from_doc = "Sales Order" @@ -117,6 +111,8 @@ def create_suppliers(settings): addresses = frappe._dict({}) for supplier in suppliers: + if frappe.db.exists("Supplier", supplier[0]): + continue biz = frappe.new_doc("Supplier") biz.supplier_name = supplier[0] biz.supplier_group = "Bakery" @@ -147,6 +143,8 @@ def create_suppliers(settings): def create_customers(settings): for customer_name in customers: + if frappe.db.exists("Customer", customer_name): + continue customer = frappe.new_doc("Customer") customer.customer_name = customer_name customer.customer_group = "Commercial" @@ -157,11 +155,11 @@ def create_customers(settings): def setup_manufacturing_settings(settings): mfg_settings = frappe.get_doc("Manufacturing Settings", "Manufacturing Settings") - mfg_settings.material_consumption = True + mfg_settings.material_consumption = 1 mfg_settings.default_wip_warehouse = "Kitchen - APC" mfg_settings.default_fg_warehouse = "Baked Goods - APC" mfg_settings.overproduction_percentage_for_work_order = 5.00 - mfg_settings.job_card_excess_transfer = True + mfg_settings.job_Card_excess_transfer = 1 mfg_settings.save() if frappe.db.exists("Account", {"account_name": "Work In Progress", "company": settings.company}): @@ -191,33 +189,6 @@ def setup_manufacturing_settings(settings): frappe.set_value("Warehouse", "Kitchen - APC", "account", wip.name) -def setup_beam_settings(settings): - beams = frappe.new_doc("BEAM Settings") - beams.company = settings.company - beams.enable_demand = True - beams.enable_handling_units = True - beams.receiving_workstation = "Receiving" - beams.shipping_workstation = "Shipping" - beams.set("warehouse_types", [{"warehouse_type": "Quarantine"}]) - beams.set( - "routes", - [ - { - "label": "Manufacture", - "route": "#/manufacture", - "dt": "Stock Entry", - "component": "Manufacture", - }, - {"label": "Demand", "route": "#/demand", "dt": "Stock Entry", "component": "Demand"}, - {"label": "Move", "route": "#/move", "dt": "Stock Entry", "component": "Demand"}, - {"label": "Receive", "route": "#/receive", "dt": "Purchase Receipt", "component": "Receive"}, - {"label": "Ship", "route": "#/ship", "dt": "Delivery Note", "component": "Ship"}, - {"label": "Repack", "route": "#/repack", "dt": "Stock Entry", "component": "Repack"}, - ], - ) - beams.save() - - def create_workstations(): for ws in workstations: if frappe.db.exists("Workstation", ws[0]): @@ -260,21 +231,21 @@ def create_items(settings): if not frappe.db.exists("Price List", "Bakery Buying"): pl = frappe.new_doc("Price List") pl.price_list_name = "Bakery Buying" - pl.buying = True + pl.buying = 1 pl.append("countries", {"country": "United States"}) pl.save() if not frappe.db.exists("Price List", "Bakery Wholesale"): pl = frappe.new_doc("Price List") pl.price_list_name = "Bakery Wholesale" - pl.selling = True + pl.selling = 1 pl.append("countries", {"country": "United States"}) pl.save() if not frappe.db.exists("Pricing Rule", "Bakery Retail"): pr = frappe.new_doc("Pricing Rule") pr.title = "Bakery Retail" - pr.selling = True + pr.selling = 1 pr.apply_on = "Item Group" pr.company = settings.company pr.margin_type = "Percentage" @@ -292,16 +263,23 @@ def create_items(settings): i.item_group = item.get("item_group") i.stock_uom = item.get("uom") i.description = item.get("description") - i.maintain_stock = True - i.enable_handling_unit = i.item_code not in ("Water", "Ice Water") - i.include_item_in_manufacturing = True + i.maintain_stock = 1 + i.enable_handling_unit = 0 if i.item_code in ("Water", "Ice Water") else 1 + i.include_item_in_manufacturing = 1 i.default_warehouse = settings.get("warehouse") i.default_material_request_type = ( "Purchase" if item.get("item_group") in ("Bakery Supplies", "Ingredients") else "Manufacture" ) i.valuation_method = "FIFO" - i.is_purchase_item = item.get("item_group") in ("Bakery Supplies", "Ingredients") - i.is_sales_item = item.get("item_group") == "Baked Goods" + i.is_purchase_item = ( + 1 + if item.get("item_group") in ("Bakery Supplies", "Ingredients") + or item.get("is_purchase_item", 0) + else 0 + ) + i.is_sales_item = ( + 1 if item.get("item_group") == "Baked Goods" or item.get("is_sales_item", 0) else 0 + ) i.append( "item_defaults", {"company": settings.company, "default_warehouse": item.get("default_warehouse")}, @@ -311,17 +289,16 @@ def create_items(settings): if i.item_code == "Parchment Paper": i.append("uoms", {"uom": "Box", "conversion_factor": 100}) i.purchase_uom = "Box" - if i.item_code in ("Water", "Ice Water"): - i.append("uoms", {"uom": "Gallon Liquid (US)", "conversion_factor": 15.142}) - i.purchase_uom = "Gallon Liquid (US)" - i.valuation_rate = 0.01 if i.item_code == "Water" else 0.02 + + i.has_serial_no = item.get("has_serial_no", 0) or 0 + i.serial_no_series = item.get("serial_no_series", "") or "" i.save() if item.get("item_price"): ip = frappe.new_doc("Item Price") ip.item_code = i.item_code ip.uom = i.stock_uom ip.price_list = "Bakery Wholesale" if i.is_sales_item else "Bakery Buying" - ip.buying = True + ip.buying = 1 ip.valid_from = "2018-1-1" ip.price_list_rate = item.get("item_price") ip.save() @@ -332,22 +309,20 @@ def create_items(settings): "items", { "item_code": "Water", - "qty": 9, # intentionally to help with demand tests + "qty": 10000000, "t_warehouse": "Refrigerator - APC", - "uom": "Cup", - "basic_rate": 0.15, - "expense_account": "5111 - Cost of Goods Sold - APC", + "basic_rate": 0.0, + "allow_zero_valuation_rate": 1, }, ) water.append( "items", { "item_code": "Ice Water", - "qty": 11, # intentionally to help with demand tests - "uom": "Cup", + "qty": 10000000, "t_warehouse": "Refrigerator - APC", - "basic_rate": 0.30, - "expense_account": "5111 - Cost of Goods Sold - APC", + "basic_rate": 0.0, + "allow_zero_valuation_rate": 1, }, ) water.save() @@ -370,90 +345,6 @@ def create_warehouses(settings): wh.parent_warehouse = root_wh wh.company = settings.company wh.save() - create_quarantine_warehouse(settings, parent_wh=root_wh) - - -# TODO: replace with test utils functionality -def create_quarantine_warehouse( - settings, - wh_name="Quarantined, Scrap and Rejected Items", - account_name=None, - parent_account=None, - account_number="1430", - parent_wh=None, - is_default_scrap_wh=True, -): - if not account_name: - if not parent_account: - # If one possible parent account in system, use it, if zero or 2+, account is standalone - parent_accts = frappe.get_all( - "Account", - { - "company": settings.company, - "root_type": "Asset", - "account_type": "Stock", - "is_group": 1, - }, - "name", - pluck="name", - ) - parent_account = parent_accts[0] if len(parent_accts) == 1 else "" - - if not frappe.db.exists( - "Account", - { - "name": wh_name, - "company": settings.company, - "root_type": "Asset", - "account_type": "Stock", - }, - ): - a = frappe.new_doc("Account") - a.name = a.account_name = wh_name - a.account_number = account_number - a.is_group = 0 - a.company = settings.company - a.root_type = "Asset" - a.report_type = "Balance Sheet" - a.account_currency = frappe.get_value("Company", settings.company, "default_currency") - a.parent_account = parent_account - a.account_type = "Stock" - a.save() - account_name = a.name - - if not parent_wh: - parent_wh = frappe.get_value("Warehouse", {"company": settings.company, "is_group": 1}) - - wh_type = "Quarantine" - if not frappe.db.exists("Warehouse Type", wh_type): - wht = frappe.new_doc("Warehouse Type") - wht.name = wh_type - wht.save() - - if not frappe.db.exists( - "Warehouse", - { - "warehouse_name": wh_name, - "company": settings.company, - "is_rejected_warehouse": 1, - "account": account_name, - }, - ): - wh = frappe.new_doc("Warehouse") - wh.warehouse_name = wh_name - wh.company = settings.company - wh.is_group = 0 - wh.parent_warehouse = parent_wh - wh.is_rejected_warehouse = 1 - wh.account = account_name - wh.warehouse_type = wh_type - wh.save() - wh_name = wh.name - - if is_default_scrap_wh: - ms = frappe.get_doc("Manufacturing Settings") - ms.default_scrap_warehouse = wh_name - ms.save() def create_boms(settings): @@ -468,7 +359,7 @@ def create_boms(settings): b.rm_cost_as_per = "Price List" b.buying_price_list = "Bakery Buying" b.currency = "USD" - b.with_operations = True + b.with_operations = 1 for item in bom.get("items"): b.append("items", {**item, "stock_uom": item.get("uom")}) b.items[-1].bom_no = frappe.get_value("BOM", {"item": item.get("item_code")}) @@ -501,7 +392,7 @@ def create_sales_order(settings): "items", { "item_code": "Double Plum Pie", - "delivery_date": so.transaction_date + datetime.timedelta(days=1), + "delivery_date": so.transaction_date, "qty": 40, "warehouse": "Baked Goods - APC", }, @@ -510,7 +401,7 @@ def create_sales_order(settings): "items", { "item_code": "Gooseberry Pie", - "delivery_date": so.transaction_date + datetime.timedelta(days=2), + "delivery_date": so.transaction_date, "qty": 10, "warehouse": "Baked Goods - APC", }, @@ -519,7 +410,7 @@ def create_sales_order(settings): "items", { "item_code": "Kaduka Key Lime Pie", - "delivery_date": so.transaction_date + datetime.timedelta(days=3), + "delivery_date": so.transaction_date, "qty": 10, "warehouse": "Baked Goods - APC", }, @@ -546,7 +437,7 @@ def create_material_request(settings): "items", { "item_code": "Double Plum Pie", - "schedule_date": mr.schedule_date + datetime.timedelta(days=1), + "schedule_date": mr.schedule_date, "qty": 40, "warehouse": "Baked Goods - APC", }, @@ -555,7 +446,7 @@ def create_material_request(settings): "items", { "item_code": "Gooseberry Pie", - "schedule_date": mr.schedule_date + datetime.timedelta(days=2), + "schedule_date": mr.schedule_date, "qty": 10, "warehouse": "Baked Goods - APC", }, @@ -564,7 +455,7 @@ def create_material_request(settings): "items", { "item_code": "Kaduka Key Lime Pie", - "schedule_date": mr.schedule_date + datetime.timedelta(days=3), + "schedule_date": mr.schedule_date, "qty": 10, "warehouse": "Baked Goods - APC", }, @@ -577,7 +468,7 @@ def create_production_plan(settings, prod_plan_from_doc): pp = frappe.new_doc("Production Plan") pp.posting_date = settings.day pp.company = settings.company - pp.combine_sub_items = True + pp.combine_sub_items = 1 if prod_plan_from_doc == "Sales Order": pp.get_items_from = "Sales Order" pp.append( @@ -596,20 +487,12 @@ def create_production_plan(settings, prod_plan_from_doc): }, ) pp.get_mr_items() - - pp.po_items = sorted(pp.po_items, key=lambda x: x.get("item_code")) - - for idx, item in enumerate(pp.po_items): - item.planned_start_date = settings.day + datetime.timedelta(days=idx) - + for item in pp.po_items: + item.planned_start_date = settings.day pp.get_sub_assembly_items() - start_time = datetime.datetime(settings.day.year, settings.day.month, settings.day.day, 0, 0) for item in pp.sub_assembly_items: - item.schedule_date = start_time - time = frappe.get_value("BOM Operation", {"parent": item.bom_no}, "sum(time_in_mins) AS time") - start_time += datetime.timedelta(minutes=time + 2) + item.schedule_date = settings.day pp.for_warehouse = "Storeroom - APC" - pp.sub_assembly_items = sorted(pp.sub_assembly_items, key=lambda x: x.get("production_item")) raw_materials = get_items_for_material_requests( pp.as_dict(), warehouses=None, get_parent_warehouse_data=None ) @@ -640,47 +523,38 @@ def create_production_plan(settings, prod_plan_from_doc): sorted((m for m in mr.items if m.supplier), key=lambda d: d.supplier), lambda x: x.get("supplier"), ): + items = list(_items) if supplier == "No Supplier": + # make a stock entry here? continue - items = list(_items) - po = frappe.new_doc("Purchase Order") - po.company = settings.company - po.supplier = supplier - po.transaction_date = po.schedule_date = settings.day - po.buying_price_list = "Bakery Buying" + if supplier == "Freedom Provisions": + pr = frappe.new_doc("Purchase Invoice") + pr.update_stock = 1 + else: + pr = frappe.new_doc("Purchase Receipt") + pr.company = settings.company + pr.supplier = supplier + pr.posting_date = settings.day + pr.set_posting_time = 1 + pr.buying_price_list = "Bakery Buying" for item in items: item_details = get_item_details( { "item_code": item.item_code, "qty": item.qty, - "supplier": po.supplier, - "company": po.company, - "doctype": po.doctype, - "currency": po.currency, - "buying_price_list": po.buying_price_list, + "supplier": pr.supplier, + "company": pr.company, + "doctype": pr.doctype, + "currency": pr.currency, + "buying_price_list": pr.buying_price_list, } ) - po.append("items", {**item_details}) - po.save() - po.submit() - - if supplier == "Freedom Provisions": - pr = make_purchase_invoice(po.name) - pr.update_stock = True - else: - pr = make_purchase_receipt(po.name) - - pr.set_posting_time = True - pr.posting_date = settings.day + pr.append("items", {**item_details}) pr.save() # pr.submit() # don't submit - needed to test handling unit generation - wo_list, po_list = [], [] - subcontracted_po = {} - default_warehouses = get_default_warehouse() - pp.make_work_order_for_subassembly_items(wo_list, subcontracted_po, default_warehouses) - pp.make_work_order_for_finished_goods(wo_list, default_warehouses) - wos = frappe.get_all("Work Order", {"production_plan": pp.name}, order_by="name ASC") + pp.make_work_order() + wos = frappe.get_all("Work Order", {"production_plan": pp.name}) start_time = datetime.datetime(settings.day.year, settings.day.month, settings.day.day, 0, 0) for wo in wos: wo = frappe.get_doc("Work Order", wo) @@ -702,7 +576,6 @@ def create_production_plan(settings, prod_plan_from_doc): job_card.append( "time_logs", { - # "completed_qty": wo.qty, "from_time": start_time, "to_time": start_time + datetime.timedelta(minutes=time_in_mins), "time_in_mins": time_in_mins, @@ -711,7 +584,6 @@ def create_production_plan(settings, prod_plan_from_doc): ) job_card.save() start_time = job_card.time_logs[0].to_time + datetime.timedelta(minutes=2) - # job_card.submit() # TODO: don't submit for demand tests def create_purchase_receipt_for_received_qty_test(settings): @@ -719,7 +591,7 @@ def create_purchase_receipt_for_received_qty_test(settings): pr.company = settings.company pr.supplier = "Freedom Provisions" pr.posting_date = settings.day - pr.set_posting_time = True + pr.set_posting_time = 1 pr.buying_price_list = "Bakery Buying" item = frappe.get_doc("Item", "Gooseberry") pr.append( @@ -755,44 +627,3 @@ def create_network_printer_settings(settings): nps.port = ps["port"] nps.printer_name = ps["name"] nps.save() - - -def create_employees(settings, only_create=None): - for employee in employees: - if only_create and employee.get("employee_name") not in only_create: - continue - - if frappe.db.exists("Employee", {"employee_name": employee.get("employee_name")}): - continue - - if not frappe.db.exists("Designation", employee.get("designation")): - desg = frappe.new_doc("Designation") - desg.designation_name = employee.get("designation") - desg.save() - - empl = frappe.new_doc("Employee") - name = employee.pop("name") - empl.first_name = name.split(" ")[0] - empl.last_name = name.split(" ")[1] - empl.update(employee) - empl.reports_to = None - if settings.company: - empl.company = settings.company - empl.save() - - user = frappe.new_doc("User") - user.email = f"{empl.first_name[0].lower()}{empl.last_name.lower()}@cfc.co" - user.first_name = empl.first_name - user.last_name = empl.last_name - user.send_welcome_email = 0 - user.enabled = 1 - user.language = settings.language - user.time_zone = settings.time_zone - for r in employee.get("roles", []): - user.append("roles", {"role": r}) - - user.save() - empl.user_id = user.email - if employee.get("reports_to"): - empl.reports_to = frappe.get_value("Employee", {"employee_name": employee.get("reports_to")}) - empl.save() From b53f6fa69312b67d9c661cc1504ef31e41f324e4 Mon Sep 17 00:00:00 2001 From: Ishwarya Date: Mon, 5 Jan 2026 18:00:00 +0530 Subject: [PATCH 4/7] Fixed Tests failure --- beam/tests/setup.py | 311 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 246 insertions(+), 65 deletions(-) diff --git a/beam/tests/setup.py b/beam/tests/setup.py index 49df57da..64acba22 100644 --- a/beam/tests/setup.py +++ b/beam/tests/setup.py @@ -5,14 +5,27 @@ from itertools import groupby import frappe +from erpnext.buying.doctype.purchase_order.purchase_order import ( + make_purchase_invoice, + make_purchase_receipt, +) from erpnext.manufacturing.doctype.production_plan.production_plan import ( get_items_for_material_requests, ) +from erpnext.manufacturing.doctype.work_order.work_order import get_default_warehouse from erpnext.setup.utils import enable_all_roles_and_domains, set_defaults_for_tests from erpnext.stock.get_item_details import get_item_details from frappe.desk.page.setup_wizard.setup_wizard import setup_complete -from beam.tests.fixtures import boms, customers, items, operations, suppliers, workstations +from beam.tests.fixtures import ( + boms, + customers, + employees, + items, + operations, + suppliers, + workstations, +) def before_test(): @@ -41,11 +54,10 @@ def before_test(): enable_all_roles_and_domains() set_defaults_for_tests() frappe.db.commit() - create_test_data() - for modu in frappe.get_all("Module Onboarding"): - frappe.db.set_value("Module Onboarding", modu, "is_complete", 1) + for module in frappe.get_all("Module Onboarding"): + frappe.db.set_value("Module Onboarding", module, "is_complete", True) frappe.set_value("Website Settings", "Website Settings", "home_page", "login") - frappe.db.commit() + create_test_data() def create_test_data(): @@ -79,17 +91,19 @@ def create_test_data(): company_address.city = "Chelsea" company_address.state = "MA" company_address.pincode = "89077" - company_address.is_your_company_address = 1 + company_address.is_your_company_address = True company_address.append("links", {"link_doctype": "Company", "link_name": settings.company}) company_address.save() frappe.set_value("Company", settings.company, "tax_id", "04-1871930") create_warehouses(settings) setup_manufacturing_settings(settings) create_workstations() + setup_beam_settings(settings) create_operations() create_item_groups(settings) create_suppliers(settings) create_customers(settings) + create_employees(settings) create_items(settings) create_boms(settings) prod_plan_from_doc = "Sales Order" @@ -155,11 +169,11 @@ def create_customers(settings): def setup_manufacturing_settings(settings): mfg_settings = frappe.get_doc("Manufacturing Settings", "Manufacturing Settings") - mfg_settings.material_consumption = 1 + mfg_settings.material_consumption = True mfg_settings.default_wip_warehouse = "Kitchen - APC" mfg_settings.default_fg_warehouse = "Baked Goods - APC" mfg_settings.overproduction_percentage_for_work_order = 5.00 - mfg_settings.job_Card_excess_transfer = 1 + mfg_settings.job_card_excess_transfer = True mfg_settings.save() if frappe.db.exists("Account", {"account_name": "Work In Progress", "company": settings.company}): @@ -189,6 +203,33 @@ def setup_manufacturing_settings(settings): frappe.set_value("Warehouse", "Kitchen - APC", "account", wip.name) +def setup_beam_settings(settings): + beams = frappe.new_doc("BEAM Settings") + beams.company = settings.company + beams.enable_demand = True + beams.enable_handling_units = True + beams.receiving_workstation = "Receiving" + beams.shipping_workstation = "Shipping" + beams.set("warehouse_types", [{"warehouse_type": "Quarantine"}]) + beams.set( + "routes", + [ + { + "label": "Manufacture", + "route": "#/manufacture", + "dt": "Stock Entry", + "component": "Manufacture", + }, + {"label": "Demand", "route": "#/demand", "dt": "Stock Entry", "component": "Demand"}, + {"label": "Move", "route": "#/move", "dt": "Stock Entry", "component": "Demand"}, + {"label": "Receive", "route": "#/receive", "dt": "Purchase Receipt", "component": "Receive"}, + {"label": "Ship", "route": "#/ship", "dt": "Delivery Note", "component": "Ship"}, + {"label": "Repack", "route": "#/repack", "dt": "Stock Entry", "component": "Repack"}, + ], + ) + beams.save() + + def create_workstations(): for ws in workstations: if frappe.db.exists("Workstation", ws[0]): @@ -231,21 +272,21 @@ def create_items(settings): if not frappe.db.exists("Price List", "Bakery Buying"): pl = frappe.new_doc("Price List") pl.price_list_name = "Bakery Buying" - pl.buying = 1 + pl.buying = True pl.append("countries", {"country": "United States"}) pl.save() if not frappe.db.exists("Price List", "Bakery Wholesale"): pl = frappe.new_doc("Price List") pl.price_list_name = "Bakery Wholesale" - pl.selling = 1 + pl.selling = True pl.append("countries", {"country": "United States"}) pl.save() if not frappe.db.exists("Pricing Rule", "Bakery Retail"): pr = frappe.new_doc("Pricing Rule") pr.title = "Bakery Retail" - pr.selling = 1 + pr.selling = True pr.apply_on = "Item Group" pr.company = settings.company pr.margin_type = "Percentage" @@ -263,23 +304,16 @@ def create_items(settings): i.item_group = item.get("item_group") i.stock_uom = item.get("uom") i.description = item.get("description") - i.maintain_stock = 1 - i.enable_handling_unit = 0 if i.item_code in ("Water", "Ice Water") else 1 - i.include_item_in_manufacturing = 1 + i.maintain_stock = True + i.enable_handling_unit = i.item_code not in ("Water", "Ice Water") + i.include_item_in_manufacturing = True i.default_warehouse = settings.get("warehouse") i.default_material_request_type = ( "Purchase" if item.get("item_group") in ("Bakery Supplies", "Ingredients") else "Manufacture" ) i.valuation_method = "FIFO" - i.is_purchase_item = ( - 1 - if item.get("item_group") in ("Bakery Supplies", "Ingredients") - or item.get("is_purchase_item", 0) - else 0 - ) - i.is_sales_item = ( - 1 if item.get("item_group") == "Baked Goods" or item.get("is_sales_item", 0) else 0 - ) + i.is_purchase_item = item.get("item_group") in ("Bakery Supplies", "Ingredients") + i.is_sales_item = item.get("item_group") == "Baked Goods" i.append( "item_defaults", {"company": settings.company, "default_warehouse": item.get("default_warehouse")}, @@ -289,16 +323,17 @@ def create_items(settings): if i.item_code == "Parchment Paper": i.append("uoms", {"uom": "Box", "conversion_factor": 100}) i.purchase_uom = "Box" - - i.has_serial_no = item.get("has_serial_no", 0) or 0 - i.serial_no_series = item.get("serial_no_series", "") or "" + if i.item_code in ("Water", "Ice Water"): + i.append("uoms", {"uom": "Gallon Liquid (US)", "conversion_factor": 15.142}) + i.purchase_uom = "Gallon Liquid (US)" + i.valuation_rate = 0.01 if i.item_code == "Water" else 0.02 i.save() if item.get("item_price"): ip = frappe.new_doc("Item Price") ip.item_code = i.item_code ip.uom = i.stock_uom ip.price_list = "Bakery Wholesale" if i.is_sales_item else "Bakery Buying" - ip.buying = 1 + ip.buying = True ip.valid_from = "2018-1-1" ip.price_list_rate = item.get("item_price") ip.save() @@ -309,20 +344,22 @@ def create_items(settings): "items", { "item_code": "Water", - "qty": 10000000, + "qty": 9, # intentionally to help with demand tests "t_warehouse": "Refrigerator - APC", - "basic_rate": 0.0, - "allow_zero_valuation_rate": 1, + "uom": "Cup", + "basic_rate": 0.15, + "expense_account": "5111 - Cost of Goods Sold - APC", }, ) water.append( "items", { "item_code": "Ice Water", - "qty": 10000000, + "qty": 11, # intentionally to help with demand tests + "uom": "Cup", "t_warehouse": "Refrigerator - APC", - "basic_rate": 0.0, - "allow_zero_valuation_rate": 1, + "basic_rate": 0.30, + "expense_account": "5111 - Cost of Goods Sold - APC", }, ) water.save() @@ -345,6 +382,90 @@ def create_warehouses(settings): wh.parent_warehouse = root_wh wh.company = settings.company wh.save() + create_quarantine_warehouse(settings, parent_wh=root_wh) + + +# TODO: replace with test utils functionality +def create_quarantine_warehouse( + settings, + wh_name="Quarantined, Scrap and Rejected Items", + account_name=None, + parent_account=None, + account_number="1430", + parent_wh=None, + is_default_scrap_wh=True, +): + if not account_name: + if not parent_account: + # If one possible parent account in system, use it, if zero or 2+, account is standalone + parent_accts = frappe.get_all( + "Account", + { + "company": settings.company, + "root_type": "Asset", + "account_type": "Stock", + "is_group": 1, + }, + "name", + pluck="name", + ) + parent_account = parent_accts[0] if len(parent_accts) == 1 else "" + + if not frappe.db.exists( + "Account", + { + "name": wh_name, + "company": settings.company, + "root_type": "Asset", + "account_type": "Stock", + }, + ): + a = frappe.new_doc("Account") + a.name = a.account_name = wh_name + a.account_number = account_number + a.is_group = 0 + a.company = settings.company + a.root_type = "Asset" + a.report_type = "Balance Sheet" + a.account_currency = frappe.get_value("Company", settings.company, "default_currency") + a.parent_account = parent_account + a.account_type = "Stock" + a.save() + account_name = a.name + + if not parent_wh: + parent_wh = frappe.get_value("Warehouse", {"company": settings.company, "is_group": 1}) + + wh_type = "Quarantine" + if not frappe.db.exists("Warehouse Type", wh_type): + wht = frappe.new_doc("Warehouse Type") + wht.name = wh_type + wht.save() + + if not frappe.db.exists( + "Warehouse", + { + "warehouse_name": wh_name, + "company": settings.company, + "is_rejected_warehouse": 1, + "account": account_name, + }, + ): + wh = frappe.new_doc("Warehouse") + wh.warehouse_name = wh_name + wh.company = settings.company + wh.is_group = 0 + wh.parent_warehouse = parent_wh + wh.is_rejected_warehouse = 1 + wh.account = account_name + wh.warehouse_type = wh_type + wh.save() + wh_name = wh.name + + if is_default_scrap_wh: + ms = frappe.get_doc("Manufacturing Settings") + ms.default_scrap_warehouse = wh_name + ms.save() def create_boms(settings): @@ -359,7 +480,7 @@ def create_boms(settings): b.rm_cost_as_per = "Price List" b.buying_price_list = "Bakery Buying" b.currency = "USD" - b.with_operations = 1 + b.with_operations = True for item in bom.get("items"): b.append("items", {**item, "stock_uom": item.get("uom")}) b.items[-1].bom_no = frappe.get_value("BOM", {"item": item.get("item_code")}) @@ -392,7 +513,7 @@ def create_sales_order(settings): "items", { "item_code": "Double Plum Pie", - "delivery_date": so.transaction_date, + "delivery_date": so.transaction_date + datetime.timedelta(days=1), "qty": 40, "warehouse": "Baked Goods - APC", }, @@ -401,7 +522,7 @@ def create_sales_order(settings): "items", { "item_code": "Gooseberry Pie", - "delivery_date": so.transaction_date, + "delivery_date": so.transaction_date + datetime.timedelta(days=2), "qty": 10, "warehouse": "Baked Goods - APC", }, @@ -410,7 +531,7 @@ def create_sales_order(settings): "items", { "item_code": "Kaduka Key Lime Pie", - "delivery_date": so.transaction_date, + "delivery_date": so.transaction_date + datetime.timedelta(days=3), "qty": 10, "warehouse": "Baked Goods - APC", }, @@ -437,7 +558,7 @@ def create_material_request(settings): "items", { "item_code": "Double Plum Pie", - "schedule_date": mr.schedule_date, + "schedule_date": mr.schedule_date + datetime.timedelta(days=1), "qty": 40, "warehouse": "Baked Goods - APC", }, @@ -446,7 +567,7 @@ def create_material_request(settings): "items", { "item_code": "Gooseberry Pie", - "schedule_date": mr.schedule_date, + "schedule_date": mr.schedule_date + datetime.timedelta(days=2), "qty": 10, "warehouse": "Baked Goods - APC", }, @@ -455,7 +576,7 @@ def create_material_request(settings): "items", { "item_code": "Kaduka Key Lime Pie", - "schedule_date": mr.schedule_date, + "schedule_date": mr.schedule_date + datetime.timedelta(days=3), "qty": 10, "warehouse": "Baked Goods - APC", }, @@ -468,7 +589,7 @@ def create_production_plan(settings, prod_plan_from_doc): pp = frappe.new_doc("Production Plan") pp.posting_date = settings.day pp.company = settings.company - pp.combine_sub_items = 1 + pp.combine_sub_items = True if prod_plan_from_doc == "Sales Order": pp.get_items_from = "Sales Order" pp.append( @@ -487,12 +608,20 @@ def create_production_plan(settings, prod_plan_from_doc): }, ) pp.get_mr_items() - for item in pp.po_items: - item.planned_start_date = settings.day + + pp.po_items = sorted(pp.po_items, key=lambda x: x.get("item_code")) + + for idx, item in enumerate(pp.po_items): + item.planned_start_date = settings.day + datetime.timedelta(days=idx) + pp.get_sub_assembly_items() + start_time = datetime.datetime(settings.day.year, settings.day.month, settings.day.day, 0, 0) for item in pp.sub_assembly_items: - item.schedule_date = settings.day + item.schedule_date = start_time + time = frappe.get_value("BOM Operation", {"parent": item.bom_no}, "sum(time_in_mins) AS time") + start_time += datetime.timedelta(minutes=time + 2) pp.for_warehouse = "Storeroom - APC" + pp.sub_assembly_items = sorted(pp.sub_assembly_items, key=lambda x: x.get("production_item")) raw_materials = get_items_for_material_requests( pp.as_dict(), warehouses=None, get_parent_warehouse_data=None ) @@ -523,38 +652,47 @@ def create_production_plan(settings, prod_plan_from_doc): sorted((m for m in mr.items if m.supplier), key=lambda d: d.supplier), lambda x: x.get("supplier"), ): - items = list(_items) if supplier == "No Supplier": - # make a stock entry here? continue - if supplier == "Freedom Provisions": - pr = frappe.new_doc("Purchase Invoice") - pr.update_stock = 1 - else: - pr = frappe.new_doc("Purchase Receipt") - pr.company = settings.company - pr.supplier = supplier - pr.posting_date = settings.day - pr.set_posting_time = 1 - pr.buying_price_list = "Bakery Buying" + items = list(_items) + po = frappe.new_doc("Purchase Order") + po.company = settings.company + po.supplier = supplier + po.transaction_date = po.schedule_date = settings.day + po.buying_price_list = "Bakery Buying" for item in items: item_details = get_item_details( { "item_code": item.item_code, "qty": item.qty, - "supplier": pr.supplier, - "company": pr.company, - "doctype": pr.doctype, - "currency": pr.currency, - "buying_price_list": pr.buying_price_list, + "supplier": po.supplier, + "company": po.company, + "doctype": po.doctype, + "currency": po.currency, + "buying_price_list": po.buying_price_list, } ) - pr.append("items", {**item_details}) + po.append("items", {**item_details}) + po.save() + po.submit() + + if supplier == "Freedom Provisions": + pr = make_purchase_invoice(po.name) + pr.update_stock = True + else: + pr = make_purchase_receipt(po.name) + + pr.set_posting_time = True + pr.posting_date = settings.day pr.save() # pr.submit() # don't submit - needed to test handling unit generation - pp.make_work_order() - wos = frappe.get_all("Work Order", {"production_plan": pp.name}) + wo_list, po_list = [], [] + subcontracted_po = {} + default_warehouses = get_default_warehouse() + pp.make_work_order_for_subassembly_items(wo_list, subcontracted_po, default_warehouses) + pp.make_work_order_for_finished_goods(wo_list, default_warehouses) + wos = frappe.get_all("Work Order", {"production_plan": pp.name}, order_by="name ASC") start_time = datetime.datetime(settings.day.year, settings.day.month, settings.day.day, 0, 0) for wo in wos: wo = frappe.get_doc("Work Order", wo) @@ -576,6 +714,7 @@ def create_production_plan(settings, prod_plan_from_doc): job_card.append( "time_logs", { + # "completed_qty": wo.qty, "from_time": start_time, "to_time": start_time + datetime.timedelta(minutes=time_in_mins), "time_in_mins": time_in_mins, @@ -584,6 +723,7 @@ def create_production_plan(settings, prod_plan_from_doc): ) job_card.save() start_time = job_card.time_logs[0].to_time + datetime.timedelta(minutes=2) + # job_card.submit() # TODO: don't submit for demand tests def create_purchase_receipt_for_received_qty_test(settings): @@ -591,7 +731,7 @@ def create_purchase_receipt_for_received_qty_test(settings): pr.company = settings.company pr.supplier = "Freedom Provisions" pr.posting_date = settings.day - pr.set_posting_time = 1 + pr.set_posting_time = True pr.buying_price_list = "Bakery Buying" item = frappe.get_doc("Item", "Gooseberry") pr.append( @@ -627,3 +767,44 @@ def create_network_printer_settings(settings): nps.port = ps["port"] nps.printer_name = ps["name"] nps.save() + + +def create_employees(settings, only_create=None): + for employee in employees: + if only_create and employee.get("employee_name") not in only_create: + continue + + if frappe.db.exists("Employee", {"employee_name": employee.get("employee_name")}): + continue + + if not frappe.db.exists("Designation", employee.get("designation")): + desg = frappe.new_doc("Designation") + desg.designation_name = employee.get("designation") + desg.save() + + empl = frappe.new_doc("Employee") + name = employee.pop("name") + empl.first_name = name.split(" ")[0] + empl.last_name = name.split(" ")[1] + empl.update(employee) + empl.reports_to = None + if settings.company: + empl.company = settings.company + empl.save() + + user = frappe.new_doc("User") + user.email = f"{empl.first_name[0].lower()}{empl.last_name.lower()}@cfc.co" + user.first_name = empl.first_name + user.last_name = empl.last_name + user.send_welcome_email = 0 + user.enabled = 1 + user.language = settings.language + user.time_zone = settings.time_zone + for r in employee.get("roles", []): + user.append("roles", {"role": r}) + + user.save() + empl.user_id = user.email + if employee.get("reports_to"): + empl.reports_to = frappe.get_value("Employee", {"employee_name": employee.get("reports_to")}) + empl.save() From 90037bceb2380a5325729c4268cbcc46516f77d1 Mon Sep 17 00:00:00 2001 From: Ishwarya Date: Mon, 5 Jan 2026 18:15:46 +0530 Subject: [PATCH 5/7] Fixed Beam settings duplication Tests failure issue --- beam/tests/setup.py | 51 ++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/beam/tests/setup.py b/beam/tests/setup.py index 64acba22..a6e87b94 100644 --- a/beam/tests/setup.py +++ b/beam/tests/setup.py @@ -204,30 +204,33 @@ def setup_manufacturing_settings(settings): def setup_beam_settings(settings): - beams = frappe.new_doc("BEAM Settings") - beams.company = settings.company - beams.enable_demand = True - beams.enable_handling_units = True - beams.receiving_workstation = "Receiving" - beams.shipping_workstation = "Shipping" - beams.set("warehouse_types", [{"warehouse_type": "Quarantine"}]) - beams.set( - "routes", - [ - { - "label": "Manufacture", - "route": "#/manufacture", - "dt": "Stock Entry", - "component": "Manufacture", - }, - {"label": "Demand", "route": "#/demand", "dt": "Stock Entry", "component": "Demand"}, - {"label": "Move", "route": "#/move", "dt": "Stock Entry", "component": "Demand"}, - {"label": "Receive", "route": "#/receive", "dt": "Purchase Receipt", "component": "Receive"}, - {"label": "Ship", "route": "#/ship", "dt": "Delivery Note", "component": "Ship"}, - {"label": "Repack", "route": "#/repack", "dt": "Stock Entry", "component": "Repack"}, - ], - ) - beams.save() + if frappe.db.exists("BEAM Settings", settings.company): + beams = frappe.get_doc("BEAM Settings", settings.company) + else: + beams = frappe.new_doc("BEAM Settings") + beams.company = settings.company + beams.enable_demand = True + beams.enable_handling_units = True + beams.receiving_workstation = "Receiving" + beams.shipping_workstation = "Shipping" + beams.set("warehouse_types", [{"warehouse_type": "Quarantine"}]) + beams.set( + "routes", + [ + { + "label": "Manufacture", + "route": "#/manufacture", + "dt": "Stock Entry", + "component": "Manufacture", + }, + {"label": "Demand", "route": "#/demand", "dt": "Stock Entry", "component": "Demand"}, + {"label": "Move", "route": "#/move", "dt": "Stock Entry", "component": "Demand"}, + {"label": "Receive", "route": "#/receive", "dt": "Purchase Receipt", "component": "Receive"}, + {"label": "Ship", "route": "#/ship", "dt": "Delivery Note", "component": "Ship"}, + {"label": "Repack", "route": "#/repack", "dt": "Stock Entry", "component": "Repack"}, + ], + ) + beams.save() def create_workstations(): From 3e8b501706f420a22f8cdd5e405eae25cb636309 Mon Sep 17 00:00:00 2001 From: Tyler Matteson Date: Tue, 13 Jan 2026 10:05:57 -0500 Subject: [PATCH 6/7] chore: update pyproject --- .pre-commit-config.yaml | 2 +- beam/beam/custom/bom_scrap_item.json | 8 -------- beam/beam/custom/item.json | 8 -------- beam/beam/custom/item_barcode.json | 6 ------ beam/beam/custom/stock_entry_detail.json | 9 --------- beam/beam/custom/user.json | 14 -------------- beam/beam/custom/warehouse.json | 14 -------------- poetry.lock | 4 ++-- pyproject.toml | 14 +++++++------- setup.py | 15 ++++++--------- 10 files changed, 16 insertions(+), 78 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index de282cf5..73e8c017 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -55,7 +55,7 @@ repos: - tomli - repo: https://github.com/agritheory/test_utils - rev: v1.0.0 + rev: v1.7.1 hooks: - id: update_pre_commit_config - id: validate_copyright diff --git a/beam/beam/custom/bom_scrap_item.json b/beam/beam/custom/bom_scrap_item.json index 95230daf..4037dd3e 100644 --- a/beam/beam/custom/bom_scrap_item.json +++ b/beam/beam/custom/bom_scrap_item.json @@ -6,9 +6,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "creation": "2023-08-22 15:23:16.272692", "default": null, - "docstatus": 0, "dt": "BOM Scrap Item", "fetch_if_empty": 0, "fieldname": "create_handling_unit", @@ -29,15 +27,11 @@ "is_virtual": 0, "label": "Create Handling Unit", "length": 0, - "modified": "2023-08-22 15:23:52.267428", - "modified_by": "Administrator", "module": "BEAM", "name": "BOM Scrap Item-create_handling_unit", "no_copy": 0, "non_negative": 0, - "owner": "Administrator", "permlevel": 0, - "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, @@ -49,9 +43,7 @@ "unique": 0 } ], - "custom_perms": [], "doctype": "BOM Scrap Item", - "links": [], "property_setters": [], "sync_on_migrate": 1 } diff --git a/beam/beam/custom/item.json b/beam/beam/custom/item.json index ee256d60..03099d33 100644 --- a/beam/beam/custom/item.json +++ b/beam/beam/custom/item.json @@ -6,9 +6,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "creation": "2024-02-26 23:52:53.051024", "default": "1", - "docstatus": 0, "dt": "Item", "fetch_if_empty": 0, "fieldname": "enable_handling_unit", @@ -29,15 +27,11 @@ "is_virtual": 0, "label": "Enable Handling Unit", "length": 0, - "modified": "2024-02-26 23:52:53.051024", - "modified_by": "Administrator", "module": "BEAM", "name": "Item-enable_handling_unit", "no_copy": 0, "non_negative": 0, - "owner": "Administrator", "permlevel": 0, - "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, @@ -49,9 +43,7 @@ "unique": 0 } ], - "custom_perms": [], "doctype": "Item", - "links": [], "property_setters": [], "sync_on_migrate": 1 } diff --git a/beam/beam/custom/item_barcode.json b/beam/beam/custom/item_barcode.json index 2e6bb577..55b70641 100644 --- a/beam/beam/custom/item_barcode.json +++ b/beam/beam/custom/item_barcode.json @@ -1,20 +1,14 @@ { "custom_fields": [], - "custom_perms": [], "doctype": "Item Barcode", "property_setters": [ { - "creation": "2022-06-16 09:40:22.875922", "doc_type": "Item Barcode", - "docstatus": 0, "doctype_or_field": "DocField", "field_name": "barcode_type", "idx": 0, - "modified": "2022-06-16 09:40:22.875922", - "modified_by": "Administrator", "module": "BEAM", "name": "Item Barcode-barcode_type-options", - "owner": "Administrator", "property": "options", "property_type": "Text", "value": "\nEAN\nUPC-A\nCode128" diff --git a/beam/beam/custom/stock_entry_detail.json b/beam/beam/custom/stock_entry_detail.json index 6fc6385b..1728d497 100644 --- a/beam/beam/custom/stock_entry_detail.json +++ b/beam/beam/custom/stock_entry_detail.json @@ -6,10 +6,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "creation": "2023-09-13 12:51:04.950175", "default": null, - "depends_on": "", - "docstatus": 0, "dt": "Stock Entry Detail", "fetch_if_empty": 0, "fieldname": "recombine_on_cancel", @@ -30,15 +27,11 @@ "is_virtual": 0, "label": "Recombine On Cancel", "length": 0, - "modified": "2023-09-13 12:51:04.950175", - "modified_by": "Administrator", "module": "BEAM", "name": "Stock Entry Detail-recombine_on_cancel", "no_copy": 1, "non_negative": 0, - "owner": "Administrator", "permlevel": 0, - "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 1, @@ -50,9 +43,7 @@ "unique": 0 } ], - "custom_perms": [], "doctype": "Stock Entry Detail", - "links": [], "property_setters": [], "sync_on_migrate": 1 } diff --git a/beam/beam/custom/user.json b/beam/beam/custom/user.json index e1d92164..9075ecb1 100644 --- a/beam/beam/custom/user.json +++ b/beam/beam/custom/user.json @@ -6,9 +6,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "creation": "2022-06-16 09:48:36.521275", "default": null, - "docstatus": 0, "dt": "User", "fetch_if_empty": 0, "fieldname": "barcode_section", @@ -27,15 +25,11 @@ "insert_after": "mobile_no", "label": "Barcodes", "length": 0, - "modified": "2022-06-16 09:48:36.521275", - "modified_by": "Administrator", "module": "BEAM", "name": "User-barcode_section", "no_copy": 0, "non_negative": 0, - "owner": "Administrator", "permlevel": 0, - "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, @@ -51,9 +45,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "creation": "2022-06-16 09:48:36.701251", "default": null, - "docstatus": 0, "dt": "User", "fetch_if_empty": 0, "fieldname": "barcodes", @@ -70,18 +62,13 @@ "in_preview": 0, "in_standard_filter": 0, "insert_after": "barcode_section", - "label": "", "length": 0, - "modified": "2022-06-16 09:48:36.701251", - "modified_by": "Administrator", "module": "BEAM", "name": "User-barcodes", "no_copy": 0, "non_negative": 0, "options": "Item Barcode", - "owner": "Administrator", "permlevel": 0, - "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, @@ -92,7 +79,6 @@ "unique": 0 } ], - "custom_perms": [], "doctype": "User", "property_setters": [], "sync_on_migrate": 1 diff --git a/beam/beam/custom/warehouse.json b/beam/beam/custom/warehouse.json index 8861a08d..79dafeae 100644 --- a/beam/beam/custom/warehouse.json +++ b/beam/beam/custom/warehouse.json @@ -6,9 +6,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "creation": "2022-06-16 09:48:36.521275", "default": null, - "docstatus": 0, "dt": "Warehouse", "fetch_if_empty": 0, "fieldname": "barcode_section", @@ -27,15 +25,11 @@ "insert_after": "pin", "label": "Barcodes", "length": 0, - "modified": "2022-06-16 09:48:36.521275", - "modified_by": "Administrator", "module": "BEAM", "name": "Warehouse-barcode_section", "no_copy": 0, "non_negative": 0, - "owner": "Administrator", "permlevel": 0, - "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, @@ -51,9 +45,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "creation": "2022-06-16 09:48:36.701251", "default": null, - "docstatus": 0, "dt": "Warehouse", "fetch_if_empty": 0, "fieldname": "barcodes", @@ -70,18 +62,13 @@ "in_preview": 0, "in_standard_filter": 0, "insert_after": "barcode_section", - "label": "", "length": 0, - "modified": "2022-06-16 09:48:36.701251", - "modified_by": "Administrator", "module": "BEAM", "name": "Warehouse-barcodes", "no_copy": 0, "non_negative": 0, "options": "Item Barcode", - "owner": "Administrator", "permlevel": 0, - "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, @@ -92,7 +79,6 @@ "unique": 0 } ], - "custom_perms": [], "doctype": "Warehouse", "property_setters": [], "sync_on_migrate": 1 diff --git a/poetry.lock b/poetry.lock index c2d72381..09ac8da7 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.1.4 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand. [[package]] name = "certifi" @@ -655,4 +655,4 @@ resolved_reference = "45ffc60638814df575d9fe11c7504b1a533e4ecb" [metadata] lock-version = "2.1" python-versions = ">=3.10,<3.14" -content-hash = "f125f1cb02654c1352139afe242a3336876573fdc1e9222a99eb04648802cc17" +content-hash = "943528828f8114492fa2ba8112b91b96557d0182e2507a3c8627db881cb22e8e" diff --git a/pyproject.toml b/pyproject.toml index 61fbe324..0b0b5de4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,13 +1,13 @@ [project] name = "beam" +version = "15.5.0" +authors = [ + { name = "AgriTheory", email = "support@agritheory.dev" } +] description = "Barcode Scanning for ERPNext" -authors = [{name = "AgriTheory", email = "support@agritheory.dev"}] +requires-python = ">=3.10" readme = "README.md" -license = { file = "LICENSE" } -dynamic = [ "version", "dependencies", "requires-python" ] - -[tool.poetry] -version = "15.4.0" +dynamic = ["dependencies"] [tool.poetry.dependencies] python = ">=3.10,<3.14" @@ -69,7 +69,7 @@ exclude_also = [ ] [tool.semantic_release] -version_toml = ["pyproject.toml:tool.poetry.version"] +version_toml = ["pyproject.toml:project.version"] version_variable = [ "beam/__init__.py:__version__" ] diff --git a/setup.py b/setup.py index 09463f34..e438b6c0 100644 --- a/setup.py +++ b/setup.py @@ -1,12 +1,9 @@ -# Copyright (c) 2026, AgriTheory and contributors +# Copyright (c) 2024, AgriTheory and contributors # For license information, please see license.txt -from setuptools import find_packages, setup +from setuptools import setup -setup( - name="beam", - version="14.8.7", - packages=find_packages(), - include_package_data=True, - zip_safe=False, -) +# TODO: Remove this file when bench >=v5.11.0 is adopted / v15.0.0 is released +name = "beam" + +setup() From 7742149581dc5984b2c0d0d41d25d5e44673cfeb Mon Sep 17 00:00:00 2001 From: Tyler Matteson Date: Tue, 13 Jan 2026 10:27:24 -0500 Subject: [PATCH 7/7] chore: handle modified key --- beam/customize.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/beam/customize.py b/beam/customize.py index 45b0a066..06bbc6c3 100644 --- a/beam/customize.py +++ b/beam/customize.py @@ -21,7 +21,8 @@ def load_customizations(): if existing_field else frappe.new_doc("Custom Field") ) - field.pop("modified") + if "modified" in field: + field.pop("modified") {custom_field.set(key, value) for key, value in field.items()} custom_field.flags.ignore_permissions = True custom_field.flags.ignore_version = True