Skip to content

Commit

Permalink
refactor: pass typed arguments to get_item_details methods (#44230)
Browse files Browse the repository at this point in the history
* refactor: pass proper types to get_item_details methods

* chore: excempt previous commit from git blame
  • Loading branch information
blaggacao authored Nov 20, 2024
1 parent 4ec23b5 commit 9673bf8
Show file tree
Hide file tree
Showing 16 changed files with 288 additions and 246 deletions.
1 change: 1 addition & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,4 @@ a308792ee7fda18a681e9181f4fd00b36385bc23

# noisy typing refactoring of get_item_details
7b7211ac79c248a79ba8a999ff34e734d874c0ae
d827ed21adc7b36047e247cbb0dc6388d048a7f9
8 changes: 6 additions & 2 deletions erpnext/accounts/doctype/pos_invoice/pos_invoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,11 @@ def set_status(self, update=False, status=None, update_modified=True):

def set_pos_fields(self, for_validate=False):
"""Set retail related fields from POS Profiles"""
from erpnext.stock.get_item_details import get_pos_profile, get_pos_profile_item_details_
from erpnext.stock.get_item_details import (
ItemDetailsCtx,
get_pos_profile,
get_pos_profile_item_details_,
)

if not self.pos_profile:
pos_profile = get_pos_profile(self.company) or {}
Expand Down Expand Up @@ -603,7 +607,7 @@ def set_pos_fields(self, for_validate=False):
for item in self.get("items"):
if item.get("item_code"):
profile_details = get_pos_profile_item_details_(
frappe._dict(item.as_dict()), profile.get("company"), profile
ItemDetailsCtx(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)):
Expand Down
8 changes: 6 additions & 2 deletions erpnext/accounts/doctype/sales_invoice/sales_invoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -766,7 +766,11 @@ def set_pos_fields(self, for_validate=False):
"Company", self.company, "default_cash_account"
)

from erpnext.stock.get_item_details import get_pos_profile, get_pos_profile_item_details_
from erpnext.stock.get_item_details import (
ItemDetailsCtx,
get_pos_profile,
get_pos_profile_item_details_,
)

if not self.pos_profile and not self.flags.ignore_pos_profile:
pos_profile = get_pos_profile(self.company) or {}
Expand Down Expand Up @@ -835,7 +839,7 @@ def set_pos_fields(self, for_validate=False):
for item in self.get("items"):
if item.get("item_code"):
profile_details = get_pos_profile_item_details_(
frappe._dict(item.as_dict()), pos, pos, update_data=True
ItemDetailsCtx(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)):
Expand Down
98 changes: 44 additions & 54 deletions erpnext/assets/doctype/asset_capitalization/asset_capitalization.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from erpnext.stock import get_warehouse_account_map
from erpnext.stock.doctype.item.item import get_item_defaults
from erpnext.stock.get_item_details import (
ItemDetailsCtx,
get_default_cost_center,
get_default_expense_account,
get_item_warehouse_,
Expand Down Expand Up @@ -748,7 +749,7 @@ def get_target_item_details(item_code=None, company=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(
frappe._dict({"item_code": item.name, "company": company}),
ItemDetailsCtx({"item_code": item.name, "company": company}),
item_defaults,
item_group_defaults,
brand_defaults,
Expand Down Expand Up @@ -785,45 +786,42 @@ def get_target_asset_details(asset=None, company=None):


@frappe.whitelist()
def get_consumed_stock_item_details(args_):
if isinstance(args_, str):
args_ = json.loads(args_)

args = frappe._dict(args_)
@erpnext.normalize_ctx_input(ItemDetailsCtx)
def get_consumed_stock_item_details(ctx: ItemDetailsCtx):
out = frappe._dict()

item = frappe._dict()
if args.item_code:
item = frappe.get_cached_doc("Item", args.item_code)
if ctx.item_code:
item = frappe.get_cached_doc("Item", ctx.item_code)

out.item_name = item.item_name
out.batch_no = None
out.serial_no = ""

out.stock_qty = flt(args.stock_qty) or 1
out.stock_qty = flt(ctx.stock_qty) or 1
out.stock_uom = item.stock_uom

out.warehouse = get_item_warehouse_(args, item, overwrite_warehouse=True) if item else None
out.warehouse = get_item_warehouse_(ctx, item, overwrite_warehouse=True) if item else None

# Cost Center
item_defaults = get_item_defaults(item.name, args.company)
item_group_defaults = get_item_group_defaults(item.name, args.company)
brand_defaults = get_brand_defaults(item.name, args.company)
out.cost_center = get_default_cost_center(args, item_defaults, item_group_defaults, brand_defaults)
item_defaults = get_item_defaults(item.name, ctx.company)
item_group_defaults = get_item_group_defaults(item.name, ctx.company)
brand_defaults = get_brand_defaults(item.name, ctx.company)
out.cost_center = get_default_cost_center(ctx, item_defaults, item_group_defaults, brand_defaults)

if args.item_code and out.warehouse:
if ctx.item_code and out.warehouse:
incoming_rate_args = frappe._dict(
{
"item_code": args.item_code,
"item_code": ctx.item_code,
"warehouse": out.warehouse,
"posting_date": args.posting_date,
"posting_time": args.posting_time,
"posting_date": ctx.posting_date,
"posting_time": ctx.posting_time,
"qty": -1 * flt(out.stock_qty),
"voucher_type": args.doctype,
"voucher_no": args.name,
"company": args.company,
"serial_no": args.serial_no,
"batch_no": args.batch_no,
"voucher_type": ctx.doctype,
"voucher_no": ctx.name,
"company": ctx.company,
"serial_no": ctx.serial_no,
"batch_no": ctx.batch_no,
}
)
out.update(get_warehouse_details(incoming_rate_args))
Expand Down Expand Up @@ -851,31 +849,28 @@ def get_warehouse_details(args):


@frappe.whitelist()
def get_consumed_asset_details(args):
if isinstance(args, str):
args = json.loads(args)

args = frappe._dict(args)
@erpnext.normalize_ctx_input(ItemDetailsCtx)
def get_consumed_asset_details(ctx):
out = frappe._dict()

asset_details = frappe._dict()
if args.asset:
if ctx.asset:
asset_details = frappe.db.get_value(
"Asset", args.asset, ["asset_name", "item_code", "item_name"], as_dict=1
"Asset", ctx.asset, ["asset_name", "item_code", "item_name"], as_dict=1
)
if not asset_details:
frappe.throw(_("Asset {0} does not exist").format(args.asset))
frappe.throw(_("Asset {0} does not exist").format(ctx.asset))

out.item_code = asset_details.item_code
out.asset_name = asset_details.asset_name
out.item_name = asset_details.item_name

if args.asset:
if ctx.asset:
out.current_asset_value = flt(
get_asset_value_after_depreciation(args.asset, finance_book=args.finance_book)
get_asset_value_after_depreciation(ctx.asset, finance_book=ctx.finance_book)
)
out.asset_value = get_value_after_depreciation_on_disposal_date(
args.asset, args.posting_date, finance_book=args.finance_book
ctx.asset, ctx.posting_date, finance_book=ctx.finance_book
)
else:
out.current_asset_value = 0
Expand All @@ -884,45 +879,40 @@ def get_consumed_asset_details(args):
# Account
if asset_details.item_code:
out.fixed_asset_account = get_asset_category_account(
"fixed_asset_account", item=asset_details.item_code, company=args.company
"fixed_asset_account", item=asset_details.item_code, company=ctx.company
)
else:
out.fixed_asset_account = None

# Cost Center
if asset_details.item_code:
item = frappe.get_cached_doc("Item", asset_details.item_code)
item_defaults = get_item_defaults(item.name, args.company)
item_group_defaults = get_item_group_defaults(item.name, args.company)
brand_defaults = get_brand_defaults(item.name, args.company)
out.cost_center = get_default_cost_center(args, item_defaults, item_group_defaults, brand_defaults)
item_defaults = get_item_defaults(item.name, ctx.company)
item_group_defaults = get_item_group_defaults(item.name, ctx.company)
brand_defaults = get_brand_defaults(item.name, ctx.company)
out.cost_center = get_default_cost_center(ctx, item_defaults, item_group_defaults, brand_defaults)
return out


@frappe.whitelist()
def get_service_item_details(args):
if isinstance(args, str):
args = json.loads(args)

args = frappe._dict(args)
@erpnext.normalize_ctx_input(ItemDetailsCtx)
def get_service_item_details(ctx):
out = frappe._dict()

item = frappe._dict()
if args.item_code:
item = frappe.get_cached_doc("Item", args.item_code)
if ctx.item_code:
item = frappe.get_cached_doc("Item", ctx.item_code)

out.item_name = item.item_name
out.qty = flt(args.qty) or 1
out.qty = flt(ctx.qty) or 1
out.uom = item.purchase_uom or item.stock_uom

item_defaults = get_item_defaults(item.name, args.company)
item_group_defaults = get_item_group_defaults(item.name, args.company)
brand_defaults = get_brand_defaults(item.name, args.company)
item_defaults = get_item_defaults(item.name, ctx.company)
item_group_defaults = get_item_group_defaults(item.name, ctx.company)
brand_defaults = get_brand_defaults(item.name, ctx.company)

out.expense_account = get_default_expense_account(
args, item_defaults, item_group_defaults, brand_defaults
)
out.cost_center = get_default_cost_center(args, item_defaults, item_group_defaults, brand_defaults)
out.expense_account = get_default_expense_account(ctx, item_defaults, item_group_defaults, brand_defaults)
out.cost_center = get_default_cost_center(ctx, item_defaults, item_group_defaults, brand_defaults)

return out

Expand Down
47 changes: 27 additions & 20 deletions erpnext/controllers/accounts_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
from erpnext.stock.doctype.item.item import get_uom_conv_factor
from erpnext.stock.doctype.packed_item.packed_item import make_packing_list
from erpnext.stock.get_item_details import (
ItemDetailsCtx,
_get_item_tax_template,
get_conversion_factor,
get_item_details,
Expand Down Expand Up @@ -752,24 +753,28 @@ def set_missing_item_details(self, for_validate=False):

for item in self.get("items"):
if item.get("item_code"):
args = parent_dict.copy()
args.update(item.as_dict())

args["doctype"] = self.doctype
args["name"] = self.name
args["child_doctype"] = item.doctype
args["child_docname"] = item.name
args["ignore_pricing_rule"] = (
self.ignore_pricing_rule if hasattr(self, "ignore_pricing_rule") else 0
ctx: ItemDetailsCtx = ItemDetailsCtx(parent_dict.copy())
ctx.update(item.as_dict())

ctx.update(
{
"doctype": self.doctype,
"name": self.name,
"child_doctype": item.doctype,
"child_docname": item.name,
"ignore_pricing_rule": (
self.ignore_pricing_rule if hasattr(self, "ignore_pricing_rule") else 0
),
}
)

if not args.get("transaction_date"):
args["transaction_date"] = args.get("posting_date")
if not ctx.transaction_date:
ctx.transaction_date = ctx.posting_date

if self.get("is_subcontracted"):
args["is_subcontracted"] = self.is_subcontracted
ctx.is_subcontracted = self.is_subcontracted

ret = get_item_details(args, self, for_validate=for_validate, overwrite_warehouse=False)
ret = get_item_details(ctx, self, for_validate=for_validate, overwrite_warehouse=False)
for fieldname, value in ret.items():
if item.meta.get_field(fieldname) and value is not None:
if item.get(fieldname) is None or fieldname in force_item_fields:
Expand Down Expand Up @@ -3161,14 +3166,16 @@ def get_supplier_block_status(party_name):


def set_child_tax_template_and_map(item, child_item, parent_doc):
args = {
"item_code": item.item_code,
"posting_date": parent_doc.transaction_date,
"tax_category": parent_doc.get("tax_category"),
"company": parent_doc.get("company"),
}
ctx = ItemDetailsCtx(
{
"item_code": item.item_code,
"posting_date": parent_doc.transaction_date,
"tax_category": parent_doc.get("tax_category"),
"company": parent_doc.get("company"),
}
)

child_item.item_tax_template = _get_item_tax_template(args, item.taxes)
child_item.item_tax_template = _get_item_tax_template(ctx, item.taxes)
if child_item.get("item_tax_template"):
child_item.item_tax_rate = get_item_tax_map(
parent_doc.get("company"), child_item.item_tax_template, as_json=True
Expand Down
18 changes: 10 additions & 8 deletions erpnext/controllers/queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from pypika import Order

import erpnext
from erpnext.stock.get_item_details import _get_item_tax_template
from erpnext.stock.get_item_details import ItemDetailsCtx, _get_item_tax_template


# searches for active employees
Expand Down Expand Up @@ -813,14 +813,16 @@ def get_tax_template(doctype, txt, searchfield, start, page_len, filters):
valid_from = filters.get("valid_from")
valid_from = valid_from[1] if isinstance(valid_from, list) else valid_from

args = {
"item_code": filters.get("item_code"),
"posting_date": valid_from,
"tax_category": filters.get("tax_category"),
"company": company,
}
ctx = ItemDetailsCtx(
{
"item_code": filters.get("item_code"),
"posting_date": valid_from,
"tax_category": filters.get("tax_category"),
"company": company,
}
)

taxes = _get_item_tax_template(args, taxes, for_validate=True)
taxes = _get_item_tax_template(ctx, taxes, for_validate=True)
return [(d,) for d in set(taxes)]


Expand Down
24 changes: 13 additions & 11 deletions erpnext/controllers/taxes_and_totals.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
validate_inclusive_tax,
validate_taxes_and_charges,
)
from erpnext.stock.get_item_details import _get_item_tax_template
from erpnext.stock.get_item_details import ItemDetailsCtx, _get_item_tax_template
from erpnext.utilities.regional import temporary_flag

logger = frappe.logger(__name__)
Expand Down Expand Up @@ -103,15 +103,17 @@ def validate_item_tax_template(self):
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)
args = {
"net_rate": item.net_rate or item.rate,
"base_net_rate": item.base_net_rate or item.base_rate,
"tax_category": self.doc.get("tax_category"),
"posting_date": self.doc.get("posting_date"),
"bill_date": self.doc.get("bill_date"),
"transaction_date": self.doc.get("transaction_date"),
"company": self.doc.get("company"),
}
ctx = ItemDetailsCtx(
{
"net_rate": item.net_rate or item.rate,
"base_net_rate": item.base_net_rate or item.base_rate,
"tax_category": self.doc.get("tax_category"),
"posting_date": self.doc.get("posting_date"),
"bill_date": self.doc.get("bill_date"),
"transaction_date": self.doc.get("transaction_date"),
"company": self.doc.get("company"),
}
)

item_group = item_doc.item_group
item_group_taxes = []
Expand All @@ -127,7 +129,7 @@ def validate_item_tax_template(self):
# No validation if no taxes in item or item group
continue

taxes = _get_item_tax_template(args, item_taxes + item_group_taxes, for_validate=True)
taxes = _get_item_tax_template(ctx, item_taxes + item_group_taxes, for_validate=True)

if taxes:
if item.item_tax_template not in taxes:
Expand Down
Loading

0 comments on commit 9673bf8

Please sign in to comment.