brotherton-erpnext/erpnext/buying/utils.py
2022-03-28 18:52:46 +05:30

130 lines
3.9 KiB
Python

# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
import json
import frappe
from frappe import _
from frappe.utils import cint, cstr, flt
from erpnext.stock.doctype.item.item import get_last_purchase_details, validate_end_of_life
def update_last_purchase_rate(doc, is_submit):
"""updates last_purchase_rate in item table for each item"""
import frappe.utils
this_purchase_date = frappe.utils.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):
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))
# update with latest quantities
bin = frappe.db.sql(
"""select projected_qty from `tabBin` where
item_code = %s and warehouse = %s""",
(d.item_code, d.warehouse),
as_dict=1,
)
f_lst = {
"projected_qty": bin and flt(bin[0]["projected_qty"]) or 0,
"ordered_qty": 0,
"received_qty": 0,
}
if d.doctype in ("Purchase Receipt Item", "Purchase Invoice Item"):
f_lst.pop("received_qty")
for x in f_lst:
if d.meta.get_field(x):
d.set(x, f_lst[x])
item = frappe.db.sql(
"""select is_stock_item,
is_sub_contracted_item, end_of_life, disabled from `tabItem` where name=%s""",
d.item_code,
as_dict=1,
)[0]
validate_end_of_life(d.item_code, item.end_of_life, item.disabled)
# validate stock item
if item.is_stock_item == 1 and d.qty and not d.warehouse and not d.get("delivered_by_supplier"):
frappe.throw(
_("Warehouse is mandatory for stock Item {0} in row {1}").format(d.item_code, d.idx)
)
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 check_on_hold_or_closed_status(doctype, docname):
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