diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 1fb45004e6f..4518c3f2872 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -179,7 +179,12 @@ def normalize_ctx_input(T: type) -> callable: def decorator(func: callable): # conserve annotations for frappe.utils.typing_validations - @functools.wraps(func, assigned=(a for a in functools.WRAPPER_ASSIGNMENTS if a != "__annotations__")) + @functools.wraps( + func, + assigned=( + a for a in functools.WRAPPER_ASSIGNMENTS if a not in ("__annotations__", "__annotate__") + ), + ) def wrapper(ctx: T | Document | dict | str, *args, **kwargs): if isinstance(ctx, Document): ctx = T(**ctx.as_dict()) diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py index 1574d048a7b..b08ac4df980 100644 --- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py +++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py @@ -663,7 +663,6 @@ class POSInvoice(SalesInvoice): def set_pos_fields(self, for_validate=False): """Set retail related fields from POS Profiles""" from erpnext.stock.get_item_details import ( - ItemDetailsCtx, get_pos_profile, get_pos_profile_item_details_, ) @@ -736,7 +735,7 @@ class POSInvoice(SalesInvoice): for item in self.get("items"): if item.get("item_code"): profile_details = get_pos_profile_item_details_( - ItemDetailsCtx(item.as_dict()), profile.get("company"), profile + frappe._dict(item.as_dict()), profile.get("company"), profile ) for fname, val in profile_details.items(): if (not for_validate) or (for_validate and not item.get(fname)): diff --git a/erpnext/accounts/doctype/sales_invoice/services/pos.py b/erpnext/accounts/doctype/sales_invoice/services/pos.py index 04709ae76b6..9c7a7c2654c 100644 --- a/erpnext/accounts/doctype/sales_invoice/services/pos.py +++ b/erpnext/accounts/doctype/sales_invoice/services/pos.py @@ -126,13 +126,13 @@ class POSService: doc.update_stock = 0 if dn_flag else cint(pos.get("update_stock")) def _apply_pos_item_defaults(self, pos, for_validate: bool) -> None: - from erpnext.stock.get_item_details import ItemDetailsCtx, get_pos_profile_item_details_ + from erpnext.stock.get_item_details import get_pos_profile_item_details_ for item in self.doc.get("items"): if not item.get("item_code"): continue profile_details = get_pos_profile_item_details_( - ItemDetailsCtx(item.as_dict()), pos, pos, update_data=True + frappe._dict(item.as_dict()), pos, pos, update_data=True ) for fname, val in profile_details.items(): if (not for_validate) or (for_validate and not item.get(fname)): diff --git a/erpnext/accounts/services/taxes.py b/erpnext/accounts/services/taxes.py index 8f77ba4eb14..4762b520885 100644 --- a/erpnext/accounts/services/taxes.py +++ b/erpnext/accounts/services/taxes.py @@ -12,7 +12,6 @@ from frappe.utils import cint, flt, parse_json import erpnext from erpnext.stock.get_item_details import ( NOT_APPLICABLE_TAX, - ItemDetailsCtx, _get_item_tax_template, _get_item_tax_template_from_item_group, get_item_tax_map, @@ -350,7 +349,7 @@ def set_balance_in_account_currency( def set_child_tax_template_and_map(item, child_item, parent_doc) -> None: - ctx = ItemDetailsCtx( + ctx = frappe._dict( { "item_code": item.item_code, "posting_date": parent_doc.transaction_date, diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py index 973f4de833b..5ffaa6dc74e 100644 --- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py +++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py @@ -500,7 +500,7 @@ def get_target_item_details(item_code: str | None = None, company: str | None = item_group_defaults = get_item_group_defaults(item.name, company) brand_defaults = get_brand_defaults(item.name, company) out.cost_center = get_default_cost_center( - ItemDetailsCtx({"item_code": item.name, "company": company}), + frappe._dict({"item_code": item.name, "company": company}), item_defaults, item_group_defaults, brand_defaults, diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py index 39c618e975e..37ccf275cdc 100644 --- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py @@ -1531,11 +1531,11 @@ class TestPurchaseOrder(ERPNextTestSuite): (via the standard item lookup the form uses) without going through the Sales Order → Purchase Order mapping pipeline. """ - from erpnext.stock.get_item_details import ItemDetailsCtx, get_item_details + from erpnext.stock.get_item_details import get_item_details item = make_item("_Test Drop Ship From Master", {"is_stock_item": 1, "delivered_by_supplier": 1}) - ctx = ItemDetailsCtx( + ctx = frappe._dict( { "item_code": item.item_code, "doctype": "Purchase Order", diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index ef62313da75..e03ab72a7e1 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -47,7 +47,6 @@ from erpnext.controllers.sales_and_purchase_return import validate_return from erpnext.setup.utils import get_exchange_rate from erpnext.stock.doctype.item.item import get_uom_conv_factor from erpnext.stock.get_item_details import ( - ItemDetailsCtx, get_item_details, ) from erpnext.utilities.regional import temporary_flag @@ -782,7 +781,7 @@ class AccountsController(TransactionBase): for item in self.get("items"): if item.get("item_code"): - ctx: ItemDetailsCtx = ItemDetailsCtx(parent_dict.copy()) + ctx: frappe._dict = frappe._dict(parent_dict.copy()) ctx.update(item.as_dict()) ctx.update( diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py index 74b8b8af761..68b1607d68a 100644 --- a/erpnext/controllers/queries.py +++ b/erpnext/controllers/queries.py @@ -25,7 +25,7 @@ from pypika import Order import erpnext from erpnext.accounts.utils import build_qb_match_conditions -from erpnext.stock.get_item_details import ItemDetailsCtx, _get_item_tax_template +from erpnext.stock.get_item_details import _get_item_tax_template from erpnext.stock.utils import get_combine_datetime from erpnext.utilities.query import get_filter_conditions_qb @@ -1056,7 +1056,7 @@ def get_tax_template(doctype: str, txt: str, searchfield: str, start: int, page_ valid_from = filters.get("valid_from") valid_from = valid_from[1] if isinstance(valid_from, list) else valid_from - ctx = ItemDetailsCtx( + ctx = frappe._dict( { "item_code": filters.get("item_code"), "posting_date": valid_from, diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py index 604e96212c1..a2afea8c8ec 100644 --- a/erpnext/controllers/taxes_and_totals.py +++ b/erpnext/controllers/taxes_and_totals.py @@ -21,7 +21,6 @@ from erpnext.controllers.accounts_controller import ( from erpnext.deprecation_dumpster import deprecated from erpnext.stock.get_item_details import ( NOT_APPLICABLE_TAX, - ItemDetailsCtx, _get_item_tax_template, get_item_tax_map, ) @@ -99,7 +98,7 @@ class calculate_taxes_and_totals: for item in self.doc.items: if item.item_code and item.get("item_tax_template"): item_doc = frappe.get_cached_doc("Item", item.item_code) - ctx = ItemDetailsCtx( + ctx = frappe._dict( { "net_rate": item.net_rate or item.rate, "base_net_rate": item.base_net_rate or item.base_rate, diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index 144cd302a4a..b16960c994e 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -16,7 +16,7 @@ from frappe.website.website_generator import WebsiteGenerator import erpnext from erpnext.setup.utils import get_exchange_rate from erpnext.stock.doctype.item.item import get_item_details -from erpnext.stock.get_item_details import ItemDetailsCtx, get_conversion_factor, get_price_list_rate +from erpnext.stock.get_item_details import get_conversion_factor, get_price_list_rate form_grid_templates = {"items": "templates/form_grid/item_grid.html"} @@ -1072,7 +1072,7 @@ def _get_price_list_item_rate(args, bom_doc): if not bom_doc.buying_price_list: frappe.throw(_("Please select Price List")) - ctx = ItemDetailsCtx( + ctx = frappe._dict( { "doctype": "BOM", "price_list": bom_doc.buying_price_list, diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index ccd543d6d66..21146de9fc8 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -2132,7 +2132,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe frappe.call({ method: "erpnext.stock.get_item_details.get_batch_based_item_price", args: { - pctx: params, + ctx: params, item_code: row.item_code, }, callback: function (r) { diff --git a/erpnext/selling/doctype/quotation/test_quotation.py b/erpnext/selling/doctype/quotation/test_quotation.py index b3f9273e0b1..22623366339 100644 --- a/erpnext/selling/doctype/quotation/test_quotation.py +++ b/erpnext/selling/doctype/quotation/test_quotation.py @@ -290,7 +290,7 @@ class TestQuotation(ERPNextTestSuite): def test_gross_profit(self): from erpnext.stock.doctype.item.test_item import make_item from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry - from erpnext.stock.get_item_details import ItemDetailsCtx, insert_item_price + from erpnext.stock.get_item_details import insert_item_price item_doc = make_item("_Test Item for Gross Profit", {"is_stock_item": 1}) item_code = item_doc.name @@ -299,7 +299,7 @@ class TestQuotation(ERPNextTestSuite): selling_price_list = frappe.get_all("Price List", filters={"selling": 1}, limit=1)[0].name frappe.db.set_single_value("Stock Settings", "auto_insert_price_list_rate_if_missing", 1) insert_item_price( - ItemDetailsCtx( + frappe._dict( { "item_code": item_code, "price_list": selling_price_list, diff --git a/erpnext/selling/doctype/sales_order/mapper.py b/erpnext/selling/doctype/sales_order/mapper.py index 9fddf353d92..5cd85b3bd6a 100644 --- a/erpnext/selling/doctype/sales_order/mapper.py +++ b/erpnext/selling/doctype/sales_order/mapper.py @@ -26,7 +26,7 @@ from erpnext.stock.doctype.stock_reservation_entry.stock_reservation_entry impor get_sre_reserved_qty_details_for_voucher, get_ssb_bundle_for_voucher, ) -from erpnext.stock.get_item_details import ItemDetailsCtx, get_bin_details, get_price_list_rate +from erpnext.stock.get_item_details import get_bin_details, get_price_list_rate def get_requested_item_qty(sales_order: str) -> dict: @@ -105,7 +105,7 @@ def make_material_request(source_name: str, target_doc: str | Document | None = target.item_code, target.warehouse, source_parent.company, True ).get("actual_qty", 0) - ctx = ItemDetailsCtx(target.as_dict().copy()) + ctx = frappe._dict(target.as_dict().copy()) ctx.update( { "company": source_parent.get("company"), diff --git a/erpnext/stock/doctype/batch/test_batch.py b/erpnext/stock/doctype/batch/test_batch.py index 20d49d780d8..cc7b55031c1 100644 --- a/erpnext/stock/doctype/batch/test_batch.py +++ b/erpnext/stock/doctype/batch/test_batch.py @@ -19,7 +19,7 @@ from erpnext.stock.doctype.serial_and_batch_bundle.test_serial_and_batch_bundle get_batch_from_bundle, ) from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry -from erpnext.stock.get_item_details import ItemDetailsCtx, get_item_details +from erpnext.stock.get_item_details import get_item_details from erpnext.stock.serial_batch_bundle import SerialBatchCreation from erpnext.tests.utils import ERPNextTestSuite @@ -595,7 +595,7 @@ class TestBatch(ERPNextTestSuite): company = "_Test Company with perpetual inventory" currency = frappe.get_cached_value("Company", company, "default_currency") - ctx = ItemDetailsCtx( + ctx = frappe._dict( { "item_code": "_Test Batch Price Item", "company": company, diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py index 16d8f0f469c..06cc5c33f94 100644 --- a/erpnext/stock/doctype/item/test_item.py +++ b/erpnext/stock/doctype/item/test_item.py @@ -25,7 +25,7 @@ from erpnext.stock.doctype.item.item import ( validate_is_stock_item, ) from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry -from erpnext.stock.get_item_details import ItemDetailsCtx, get_item_details +from erpnext.stock.get_item_details import get_item_details from erpnext.tests.utils import ERPNextTestSuite @@ -158,7 +158,7 @@ class TestItem(ERPNextTestSuite): currency = frappe.get_cached_value("Company", company, "default_currency") details = get_item_details( - ItemDetailsCtx( + frappe._dict( { "item_code": "_Test Item", "company": company, @@ -188,7 +188,7 @@ class TestItem(ERPNextTestSuite): create_fixed_asset_item() details = get_item_details( - ItemDetailsCtx( + frappe._dict( { "item_code": "Macbook Pro", "company": "_Test Company", @@ -201,7 +201,7 @@ class TestItem(ERPNextTestSuite): frappe.db.set_value("Asset Category", "Computers", "enable_cwip_accounting", "1") details = get_item_details( - ItemDetailsCtx( + frappe._dict( { "item_code": "Macbook Pro", "company": "_Test Company", @@ -291,7 +291,7 @@ class TestItem(ERPNextTestSuite): for data in expected_item_tax_template: details = get_item_details( - ItemDetailsCtx( + frappe._dict( { "item_code": data["item_code"], "tax_category": data["tax_category"], @@ -343,7 +343,7 @@ class TestItem(ERPNextTestSuite): "cost_center": "_Test Cost Center 2 - _TC", # from item group } sales_item_details = get_item_details( - ItemDetailsCtx( + frappe._dict( { "item_code": "Test Item With Defaults", "company": "_Test Company", @@ -368,7 +368,7 @@ class TestItem(ERPNextTestSuite): "cost_center": "_Test Write Off Cost Center - _TC", # from item } purchase_item_details = get_item_details( - ItemDetailsCtx( + frappe._dict( { "item_code": "Test Item With Defaults", "company": "_Test Company", diff --git a/erpnext/stock/doctype/item_price/test_item_price.py b/erpnext/stock/doctype/item_price/test_item_price.py index d98339bb0c7..9b6fae7ad12 100644 --- a/erpnext/stock/doctype/item_price/test_item_price.py +++ b/erpnext/stock/doctype/item_price/test_item_price.py @@ -5,7 +5,7 @@ import frappe from erpnext.stock.doctype.item_price.item_price import ItemPriceDuplicateItem -from erpnext.stock.get_item_details import ItemDetailsCtx, get_price_list_rate_for +from erpnext.stock.get_item_details import get_price_list_rate_for from erpnext.tests.utils import ERPNextTestSuite @@ -68,7 +68,7 @@ class TestItemPrice(ERPNextTestSuite): # Check correct price at this quantity doc = frappe.copy_doc(self.globalTestRecords["Item Price"][2]) - ctx = ItemDetailsCtx( + ctx = frappe._dict( { "price_list": doc.price_list, "customer": doc.customer, @@ -84,7 +84,7 @@ class TestItemPrice(ERPNextTestSuite): def test_price_with_no_qty(self): # Check correct price when no quantity doc = frappe.copy_doc(self.globalTestRecords["Item Price"][2]) - ctx = ItemDetailsCtx( + ctx = frappe._dict( { "price_list": doc.price_list, "customer": doc.customer, @@ -100,7 +100,7 @@ class TestItemPrice(ERPNextTestSuite): # Check correct price at first date doc = frappe.copy_doc(self.globalTestRecords["Item Price"][2]) - ctx = ItemDetailsCtx( + ctx = frappe._dict( { "price_list": doc.price_list, "customer": "_Test Customer", @@ -117,7 +117,7 @@ class TestItemPrice(ERPNextTestSuite): # Check correct price at invalid date doc = frappe.copy_doc(self.globalTestRecords["Item Price"][3]) - ctx = ItemDetailsCtx( + ctx = frappe._dict( { "price_list": doc.price_list, "qty": 7, @@ -133,7 +133,7 @@ class TestItemPrice(ERPNextTestSuite): # Check correct price when outside of the date doc = frappe.copy_doc(self.globalTestRecords["Item Price"][4]) - ctx = ItemDetailsCtx( + ctx = frappe._dict( { "price_list": doc.price_list, "customer": "_Test Customer", @@ -150,7 +150,7 @@ class TestItemPrice(ERPNextTestSuite): # Check lowest price when no date provided doc = frappe.copy_doc(self.globalTestRecords["Item Price"][1]) - ctx = ItemDetailsCtx( + ctx = frappe._dict( { "price_list": doc.price_list, "uom": "_Test UOM", @@ -182,7 +182,7 @@ class TestItemPrice(ERPNextTestSuite): doc.price_list_rate = 21 doc.insert() - ctx = ItemDetailsCtx( + ctx = frappe._dict( { "price_list": doc.price_list, "uom": "_Test UOM", diff --git a/erpnext/stock/doctype/packed_item/packed_item.py b/erpnext/stock/doctype/packed_item/packed_item.py index 9ec908c6b62..7979ac6ff79 100644 --- a/erpnext/stock/doctype/packed_item/packed_item.py +++ b/erpnext/stock/doctype/packed_item/packed_item.py @@ -12,7 +12,7 @@ from frappe import _ from frappe.model.document import Document from frappe.utils import flt -from erpnext.stock.get_item_details import ItemDetailsCtx, get_item_details, get_price_list_rate +from erpnext.stock.get_item_details import get_item_details, get_price_list_rate class PackedItem(Document): @@ -344,7 +344,7 @@ def update_packed_item_price_data(pi_row, item_data, doc): return item_doc = frappe.get_cached_doc("Item", pi_row.item_code) - ctx = ItemDetailsCtx(pi_row.as_dict().copy()) + ctx = frappe._dict(pi_row.as_dict().copy()) ctx.update( { "company": doc.get("company"), @@ -442,7 +442,7 @@ def get_items_from_product_bundle(row: str | dict): """ from erpnext.selling.doctype.product_bundle.product_bundle import get_active_product_bundle - row, items = ItemDetailsCtx(frappe.parse_json(row)), [] + row, items = frappe._dict(frappe.parse_json(row)), [] if bundle_name := row.get("product_bundle"): frappe.has_permission("Product Bundle", "read", bundle_name, throw=True) diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index b3003082231..f5a090262fb 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -2148,7 +2148,7 @@ class TestPurchaseReceipt(ERPNextTestSuite): self.assertEqual(return_pi.docstatus, 1) def test_disable_last_purchase_rate(self): - from erpnext.stock.get_item_details import ItemDetailsCtx, get_item_details + from erpnext.stock.get_item_details import get_item_details item = make_item( "_Test Disable Last Purchase Rate", @@ -2163,7 +2163,7 @@ class TestPurchaseReceipt(ERPNextTestSuite): item_code=item.name, ) - ctx = ItemDetailsCtx(pr.items[0].as_dict()) + ctx = frappe._dict(pr.items[0].as_dict()) ctx.update( { "supplier": pr.supplier, diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index e575e8eedb4..ccb096d29ea 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -28,7 +28,6 @@ from erpnext.manufacturing.doctype.bom.bom import ( from erpnext.setup.doctype.brand.brand import get_brand_defaults from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults from erpnext.stock.get_item_details import ( - ItemDetailsCtx, get_barcode_data, get_bin_details, get_conversion_factor, @@ -1189,7 +1188,7 @@ class StockEntry(StockController, SubcontractingInwardController): return reserved_work_orders @frappe.whitelist() - def get_item_details(self, args: ItemDetailsCtx | None = None, for_update: bool = False): + def get_item_details(self, args: frappe._dict | None = None, for_update: bool = False): item = self._fetch_item_data(args) item_group_defaults = get_item_group_defaults(item.name, self.company) brand_defaults = get_brand_defaults(item.name, self.company) diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index aa9750f7523..be563e9941a 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -27,9 +27,7 @@ from erpnext.stock.doctype.item.item import get_item_defaults, get_uom_conv_fact from erpnext.stock.doctype.item_manufacturer.item_manufacturer import get_item_manufacturer_part_no from erpnext.stock.doctype.price_list.price_list import get_price_list_details -ItemDetails = frappe._dict ItemDetailsCtx = frappe._dict -ItemPriceCtx = frappe._dict sales_doctypes = ["Quotation", "Sales Order", "Delivery Note", "Sales Invoice", "POS Invoice"] purchase_doctypes = [ @@ -58,7 +56,7 @@ def _preprocess_ctx(ctx): @frappe.whitelist() @erpnext.normalize_ctx_input(ItemDetailsCtx) def get_item_details( - ctx: ItemDetailsCtx | str, + ctx: ItemDetailsCtx, doc: Document | str | None = None, for_validate: bool | None = False, overwrite_warehouse: bool = True, @@ -98,7 +96,7 @@ def get_item_details( if doc.get("doctype") == "Purchase Invoice": ctx.bill_date = doc.get("bill_date") - out: ItemDetails = get_basic_details(ctx, item, overwrite_warehouse) + out: frappe._dict = get_basic_details(ctx, item, overwrite_warehouse) get_item_tax_template(ctx, item, out) out.item_tax_rate = get_item_tax_map( @@ -184,13 +182,13 @@ def get_item_details( return out -def remove_standard_fields(out: ItemDetails): +def remove_standard_fields(out: frappe._dict): for key in child_table_fields + default_fields: out.pop(key, None) return out -def set_valuation_rate(out: ItemDetails | dict, ctx: ItemDetailsCtx): +def set_valuation_rate(out: frappe._dict, ctx: frappe._dict): from erpnext.selling.doctype.product_bundle.product_bundle import get_active_product_bundle active_bundle = get_active_product_bundle(ctx.item_code) @@ -320,7 +318,7 @@ def get_filtered_serial_nos(serial_nos, doc, table=None): return serial_nos -def update_bin_details(ctx: ItemDetailsCtx, out: ItemDetails, doc): +def update_bin_details(ctx: frappe._dict, out: frappe._dict, doc): if ctx.doctype == "Material Request" and ctx.material_request_type == "Material Transfer": out.update(get_bin_details(ctx.item_code, ctx.from_warehouse)) @@ -346,7 +344,7 @@ def get_item_code(barcode=None, serial_no=None): return item_code -def validate_item_details(ctx: ItemDetailsCtx, item): +def validate_item_details(ctx: frappe._dict, item): if not ctx.company: throw(_("Please specify Company")) @@ -365,7 +363,7 @@ def validate_item_details(ctx: ItemDetailsCtx, item): throw(_("Item {0} must be a Non-Stock Item").format(item.name)) -def get_basic_details(ctx: ItemDetailsCtx, item, overwrite_warehouse=True) -> ItemDetails: +def get_basic_details(ctx: frappe._dict, item, overwrite_warehouse=True) -> frappe._dict: """ :param ctx: { "item_code": "", @@ -491,7 +489,7 @@ def get_basic_details(ctx: ItemDetailsCtx, item, overwrite_warehouse=True) -> It if ctx.batch_no and item.name != frappe.get_cached_value("Batch", ctx.batch_no, "item"): ctx.batch_no = "" - out = ItemDetails( + out = frappe._dict( { "item_code": item.name, "item_name": item.item_name, @@ -721,9 +719,9 @@ def get_item_tax_info( if not item_code or item_code[1] in out or not item_tax_templates.get(item_code[1]): continue - out[item_code[1]] = ItemDetails() + out[item_code[1]] = frappe._dict() item = frappe.get_cached_doc("Item", item_code[0]) - ctx: ItemDetailsCtx = { + ctx: frappe._dict = { "company": doc.company, "tax_category": tax_category, "base_net_rate": item_rates.get(item_code[1]), @@ -744,9 +742,7 @@ def get_item_tax_info( @frappe.whitelist() @erpnext.normalize_ctx_input(ItemDetailsCtx) -def get_item_tax_template( - ctx: ItemDetailsCtx | str, item: Document | None = None, out: ItemDetails | None = None -): +def get_item_tax_template(ctx: ItemDetailsCtx, item: Document | None = None, out: frappe._dict | None = None): """ Determines item_tax template from item or parent item groups. @@ -797,7 +793,7 @@ def _get_item_tax_template_from_item_group(ctx, item_group, out=None): @erpnext.normalize_ctx_input(ItemDetailsCtx) def _get_item_tax_template( - ctx: ItemDetailsCtx, taxes, out: ItemDetails | None = None, for_validate=False + ctx: ItemDetailsCtx, taxes, out: frappe._dict | None = None, for_validate=False ) -> None | str | list[str]: """ Accesses: @@ -814,7 +810,7 @@ def _get_item_tax_template( } """ if out is None: - out = ItemDetails() + out = frappe._dict() taxes_with_validity = [] taxes_with_no_validity = [] @@ -929,7 +925,7 @@ def calculate_service_end_date(ctx: ItemDetailsCtx, item: Document | None = None return deferred_detail -def get_default_income_account(ctx: ItemDetailsCtx, item, item_group, brand): +def get_default_income_account(ctx: frappe._dict, item, item_group, brand): return ( item.get("income_account") or item_group.get("income_account") @@ -938,7 +934,7 @@ def get_default_income_account(ctx: ItemDetailsCtx, item, item_group, brand): ) -def get_default_inventory_account(ctx: ItemDetailsCtx, item, item_group, brand): +def get_default_inventory_account(ctx: frappe._dict, item, item_group, brand): if not frappe.get_cached_value("Company", ctx.company, "enable_item_wise_inventory_account"): return None @@ -950,7 +946,7 @@ def get_default_inventory_account(ctx: ItemDetailsCtx, item, item_group, brand): ) -def get_default_expense_account(ctx: ItemDetailsCtx, item, item_group, brand): +def get_default_expense_account(ctx: frappe._dict, item, item_group, brand): if ctx.get("doctype") in ["Sales Invoice", "Delivery Note"]: expense_account = ( item.get("default_cogs_account") @@ -972,7 +968,7 @@ def get_default_expense_account(ctx: ItemDetailsCtx, item, item_group, brand): ) -def get_provisional_account(ctx: ItemDetailsCtx, item, item_group, brand): +def get_provisional_account(ctx: frappe._dict, item, item_group, brand): return ( item.get("default_provisional_account") or item_group.get("default_provisional_account") @@ -981,7 +977,7 @@ def get_provisional_account(ctx: ItemDetailsCtx, item, item_group, brand): ) -def get_default_discount_account(ctx: ItemDetailsCtx, item, item_group, brand): +def get_default_discount_account(ctx: frappe._dict, item, item_group, brand): return ( item.get("default_discount_account") or item_group.get("default_discount_account") @@ -990,7 +986,7 @@ def get_default_discount_account(ctx: ItemDetailsCtx, item, item_group, brand): ) -def get_default_deferred_account(ctx: ItemDetailsCtx, item, fieldname=None): +def get_default_deferred_account(ctx: frappe._dict, item, fieldname=None): if item.get("enable_deferred_revenue") or item.get("enable_deferred_expense"): return ( frappe.get_cached_value( @@ -1055,13 +1051,13 @@ def get_default_cost_center(ctx: ItemDetailsCtx, item=None, item_group=None, bra return cost_center -def get_default_supplier(_ctx: ItemDetailsCtx, item, item_group, brand): +def get_default_supplier(_ctx: frappe._dict, item, item_group, brand): return item.get("default_supplier") or item_group.get("default_supplier") or brand.get("default_supplier") -def get_price_list_rate(ctx: ItemDetailsCtx, item_doc, out: ItemDetails = None): +def get_price_list_rate(ctx: frappe._dict, item_doc, out: frappe._dict = None): if out is None: - out = ItemDetails() + out = frappe._dict() meta = frappe.get_meta(ctx.parenttype or ctx.doctype) @@ -1103,7 +1099,7 @@ def get_price_list_rate(ctx: ItemDetailsCtx, item_doc, out: ItemDetails = None): return out -def insert_item_price(ctx: ItemDetailsCtx): +def insert_item_price(ctx: frappe._dict): """Insert Item Price if Price List and Price List Rate are specified and currency is the same""" if not ctx.price_list or not ctx.rate or ctx.is_internal_supplier or ctx.is_internal_customer: return @@ -1212,13 +1208,11 @@ def insert_item_price(ctx: ItemDetailsCtx): ) -def _get_stock_uom_rate(rate: float, ctx: ItemDetailsCtx): +def _get_stock_uom_rate(rate: float, ctx: frappe._dict): return rate / ctx.conversion_factor if ctx.conversion_factor else rate -def get_item_price( - pctx: ItemPriceCtx | dict, item_code, ignore_party=False, force_batch_no=False -) -> list[dict]: +def get_item_price(pctx: frappe._dict, item_code, ignore_party=False, force_batch_no=False) -> list[dict]: """ Get name, price_list_rate from Item Price based on conditions Check if the desired qty is within the increment of the packing list. @@ -1226,7 +1220,7 @@ def get_item_price( optional fields transaction_date, customer, supplier :param item_code: str, Item Doctype field item_code """ - pctx: ItemPriceCtx = frappe._dict(pctx) + pctx: frappe._dict = frappe._dict(pctx) ip = frappe.qb.DocType("Item Price") query = ( @@ -1277,16 +1271,15 @@ def get_item_price( @frappe.whitelist() -def get_batch_based_item_price(pctx: ItemPriceCtx | dict | str, item_code: str): - pctx = parse_json(pctx) - - item_price = get_item_price(pctx, item_code, force_batch_no=True) +@erpnext.normalize_ctx_input(ItemDetailsCtx) +def get_batch_based_item_price(ctx: ItemDetailsCtx, item_code: str): + item_price = get_item_price(ctx, item_code, force_batch_no=True) if not item_price: - item_price = get_item_price(pctx, item_code, ignore_party=True, force_batch_no=True) + item_price = get_item_price(ctx, item_code, ignore_party=True, force_batch_no=True) - is_free_item = pctx.get("items", [{}])[0].get("is_free_item") + is_free_item = ctx.get("items", [{}])[0].get("is_free_item") - if item_price and item_price[0].uom == pctx.uom and not is_free_item: + if item_price and item_price[0].uom == ctx.uom and not is_free_item: return item_price[0].price_list_rate return 0.0 @@ -1302,7 +1295,7 @@ def get_price_list_rate_for(ctx: ItemDetailsCtx, item_code: str): :param qty: Desired Qty :param transaction_date: Date of the price """ - pctx = ItemPriceCtx( + pctx = frappe._dict( { "item_code": item_code, "price_list": ctx.get("price_list"), @@ -1358,7 +1351,7 @@ def check_packing_list(price_list_rate_name, desired_qty, item_code): return flag -def validate_conversion_rate(ctx: ItemDetailsCtx, meta): +def validate_conversion_rate(ctx: frappe._dict, meta): from erpnext.controllers.accounts_controller import validate_conversion_rate company_currency = frappe.get_cached_value("Company", ctx.company, "default_currency") @@ -1404,7 +1397,7 @@ def validate_conversion_rate(ctx: ItemDetailsCtx, meta): ) -def get_party_item_code(ctx: ItemDetailsCtx, item_doc, out: ItemDetails): +def get_party_item_code(ctx: frappe._dict, item_doc, out: frappe._dict): if ctx.transaction_type == "selling" and ctx.customer: out.customer_item_code = None @@ -1426,7 +1419,7 @@ def get_party_item_code(ctx: ItemDetailsCtx, item_doc, out: ItemDetails): out.supplier_part_no = item_supplier[0].supplier_part_no if item_supplier else None -def get_tax_withholding_category(ctx: ItemDetailsCtx, item_doc, out: ItemDetails): +def get_tax_withholding_category(ctx: frappe._dict, item_doc, out: frappe._dict): """ Get tax withholding category for the item based on the transaction type and party. """ @@ -1601,7 +1594,7 @@ def get_batch_qty(batch_no: str, warehouse: str, item_code: str): @frappe.whitelist() @erpnext.normalize_ctx_input(ItemDetailsCtx) -def apply_price_list(ctx: ItemDetailsCtx | str, as_doc: bool = False, doc: Document | str | None = None): +def apply_price_list(ctx: ItemDetailsCtx, as_doc: bool = False, doc: Document | str | None = None): """Apply pricelist on a document-like dict object and return as {'parent': dict, 'children': list} @@ -1637,7 +1630,7 @@ def apply_price_list(ctx: ItemDetailsCtx | str, as_doc: bool = False, doc: Docum ctx.update(parent) for item in item_list: - ctx_copy = ItemDetailsCtx(ctx.copy()) + ctx_copy = frappe._dict(ctx.copy()) ctx_copy.update(item) item_details = apply_price_list_on_item(ctx_copy, doc=doc) children.append(item_details) @@ -1665,7 +1658,7 @@ def apply_price_list_on_item(ctx, doc=None): return item_details -def get_price_list_currency_and_exchange_rate(ctx: ItemDetailsCtx): +def get_price_list_currency_and_exchange_rate(ctx: frappe._dict): if not ctx.price_list: return {} @@ -1752,7 +1745,7 @@ def get_valuation_rate(item_code: str, company: str, warehouse: str | None = Non return {"valuation_rate": 0.0} -def get_gross_profit(out: ItemDetails): +def get_gross_profit(out: frappe._dict): if out.valuation_rate: out.update({"gross_profit": ((out.base_rate - out.valuation_rate) * out.stock_qty)}) @@ -1765,7 +1758,7 @@ def get_serial_no(_args: Any, serial_nos: list | None = None, sales_order: str | return serial_nos -def update_party_blanket_order(ctx: ItemDetailsCtx, out: ItemDetails | dict): +def update_party_blanket_order(ctx: frappe._dict, out: frappe._dict): if out["against_blanket_order"]: blanket_order_details = get_blanket_order_details(ctx) if blanket_order_details: