|
- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
- # License: GNU General Public License v3. See license.txt
-
-
- import json
- from typing import Dict
-
- import frappe
- from frappe import _
- from frappe.utils import cint, cstr, flt, getdate
-
- from erpnext.stock.doctype.item.item import get_last_purchase_details, validate_end_of_life
-
-
- def update_last_purchase_rate(doc, is_submit) -> None:
- """updates last_purchase_rate in item table for each item"""
-
- this_purchase_date = getdate(doc.get("posting_date") or doc.get("transaction_date"))
-
- for d in doc.get("items"):
- # get last purchase details
- last_purchase_details = get_last_purchase_details(d.item_code, doc.name)
-
- # compare last purchase date and this transaction's date
- last_purchase_rate = None
- if last_purchase_details and (
- doc.get("docstatus") == 2 or last_purchase_details.purchase_date > this_purchase_date
- ):
- last_purchase_rate = last_purchase_details["base_net_rate"]
- elif is_submit == 1:
- # even if this transaction is the latest one, it should be submitted
- # for it to be considered for latest purchase rate
- if flt(d.conversion_factor):
- last_purchase_rate = flt(d.base_net_rate) / flt(d.conversion_factor)
- # Check if item code is present
- # Conversion factor should not be mandatory for non itemized items
- elif d.item_code:
- frappe.throw(_("UOM Conversion factor is required in row {0}").format(d.idx))
-
- # update last purchsae rate
- frappe.db.set_value("Item", d.item_code, "last_purchase_rate", flt(last_purchase_rate))
-
-
- def validate_for_items(doc) -> None:
- items = []
- for d in doc.get("items"):
- if not d.qty:
- if doc.doctype == "Purchase Receipt" and d.rejected_qty:
- continue
- frappe.throw(_("Please enter quantity for Item {0}").format(d.item_code))
-
- set_stock_levels(row=d) # update with latest quantities
- item = validate_item_and_get_basic_data(row=d)
- validate_stock_item_warehouse(row=d, item=item)
- validate_end_of_life(d.item_code, item.end_of_life, item.disabled)
-
- items.append(cstr(d.item_code))
-
- if (
- items
- and len(items) != len(set(items))
- and not cint(frappe.db.get_single_value("Buying Settings", "allow_multiple_items") or 0)
- ):
- frappe.throw(_("Same item cannot be entered multiple times."))
-
-
- def set_stock_levels(row) -> None:
- projected_qty = frappe.db.get_value(
- "Bin",
- {
- "item_code": row.item_code,
- "warehouse": row.warehouse,
- },
- "projected_qty",
- )
-
- qty_data = {
- "projected_qty": flt(projected_qty),
- "ordered_qty": 0,
- "received_qty": 0,
- }
- if row.doctype in ("Purchase Receipt Item", "Purchase Invoice Item"):
- qty_data.pop("received_qty")
-
- for field in qty_data:
- if row.meta.get_field(field):
- row.set(field, qty_data[field])
-
-
- def validate_item_and_get_basic_data(row) -> Dict:
- item = frappe.db.get_values(
- "Item",
- filters={"name": row.item_code},
- fieldname=["is_stock_item", "is_sub_contracted_item", "end_of_life", "disabled"],
- as_dict=1,
- )
- if not item:
- frappe.throw(_("Row #{0}: Item {1} does not exist").format(row.idx, frappe.bold(row.item_code)))
-
- return item[0]
-
-
- def validate_stock_item_warehouse(row, item) -> None:
- if (
- item.is_stock_item == 1
- and row.qty
- and not row.warehouse
- and not row.get("delivered_by_supplier")
- ):
- frappe.throw(
- _("Row #{1}: Warehouse is mandatory for stock Item {0}").format(
- frappe.bold(row.item_code), row.idx
- )
- )
-
-
- def check_on_hold_or_closed_status(doctype, docname) -> None:
- status = frappe.db.get_value(doctype, docname, "status")
-
- if status in ("Closed", "On Hold"):
- frappe.throw(
- _("{0} {1} status is {2}").format(doctype, docname, status), frappe.InvalidStatusError
- )
-
-
- @frappe.whitelist()
- def get_linked_material_requests(items):
- items = json.loads(items)
- mr_list = []
- for item in items:
- material_request = frappe.db.sql(
- """SELECT distinct mr.name AS mr_name,
- (mr_item.qty - mr_item.ordered_qty) AS qty,
- mr_item.item_code AS item_code,
- mr_item.name AS mr_item
- FROM `tabMaterial Request` mr, `tabMaterial Request Item` mr_item
- WHERE mr.name = mr_item.parent
- AND mr_item.item_code = %(item)s
- AND mr.material_request_type = 'Purchase'
- AND mr.per_ordered < 99.99
- AND mr.docstatus = 1
- AND mr.status != 'Stopped'
- ORDER BY mr_item.item_code ASC""",
- {"item": item},
- as_dict=1,
- )
- if material_request:
- mr_list.append(material_request)
-
- return mr_list
|