Rushabh Mehta | cc8b2b2 | 2017-03-31 12:44:29 +0530 | [diff] [blame] | 1 | # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors |
| 2 | # License: GNU General Public License v3. See license.txt |
| 3 | |
| 4 | from __future__ import unicode_literals |
| 5 | import frappe |
| 6 | from frappe.utils import flt, cstr, cint |
| 7 | from frappe import _ |
mbauskar | c482aed | 2017-05-02 12:53:12 +0530 | [diff] [blame] | 8 | import json |
Rushabh Mehta | cc8b2b2 | 2017-03-31 12:44:29 +0530 | [diff] [blame] | 9 | |
| 10 | from erpnext.stock.doctype.item.item import get_last_purchase_details |
| 11 | from erpnext.stock.doctype.item.item import validate_end_of_life |
| 12 | |
| 13 | def update_last_purchase_rate(doc, is_submit): |
| 14 | """updates last_purchase_rate in item table for each item""" |
| 15 | |
| 16 | import frappe.utils |
| 17 | this_purchase_date = frappe.utils.getdate(doc.get('posting_date') or doc.get('transaction_date')) |
| 18 | |
| 19 | for d in doc.get("items"): |
| 20 | # get last purchase details |
| 21 | last_purchase_details = get_last_purchase_details(d.item_code, doc.name) |
| 22 | |
| 23 | # compare last purchase date and this transaction's date |
| 24 | last_purchase_rate = None |
| 25 | if last_purchase_details and \ |
| 26 | (last_purchase_details.purchase_date > this_purchase_date): |
| 27 | last_purchase_rate = last_purchase_details['base_rate'] |
| 28 | elif is_submit == 1: |
| 29 | # even if this transaction is the latest one, it should be submitted |
| 30 | # for it to be considered for latest purchase rate |
| 31 | if flt(d.conversion_factor): |
| 32 | last_purchase_rate = flt(d.base_rate) / flt(d.conversion_factor) |
| 33 | else: |
| 34 | frappe.throw(_("UOM Conversion factor is required in row {0}").format(d.idx)) |
| 35 | |
| 36 | # update last purchsae rate |
| 37 | if last_purchase_rate: |
| 38 | frappe.db.sql("""update `tabItem` set last_purchase_rate = %s where name = %s""", |
| 39 | (flt(last_purchase_rate), d.item_code)) |
| 40 | |
| 41 | def validate_for_items(doc): |
| 42 | items = [] |
| 43 | for d in doc.get("items"): |
| 44 | if not d.qty: |
| 45 | if doc.doctype == "Purchase Receipt" and d.rejected_qty: |
| 46 | continue |
| 47 | frappe.throw(_("Please enter quantity for Item {0}").format(d.item_code)) |
| 48 | |
| 49 | # update with latest quantities |
| 50 | bin = frappe.db.sql("""select projected_qty from `tabBin` where |
| 51 | item_code = %s and warehouse = %s""", (d.item_code, d.warehouse), as_dict=1) |
| 52 | |
| 53 | f_lst ={'projected_qty': bin and flt(bin[0]['projected_qty']) or 0, 'ordered_qty': 0, 'received_qty' : 0} |
| 54 | if d.doctype in ('Purchase Receipt Item', 'Purchase Invoice Item'): |
| 55 | f_lst.pop('received_qty') |
| 56 | for x in f_lst : |
| 57 | if d.meta.get_field(x): |
| 58 | d.set(x, f_lst[x]) |
| 59 | |
| 60 | item = frappe.db.sql("""select is_stock_item, |
| 61 | is_sub_contracted_item, end_of_life, disabled from `tabItem` where name=%s""", |
| 62 | d.item_code, as_dict=1)[0] |
| 63 | |
| 64 | validate_end_of_life(d.item_code, item.end_of_life, item.disabled) |
| 65 | |
| 66 | # validate stock item |
Makarand Bauskar | c4ec937 | 2017-05-05 11:52:17 +0530 | [diff] [blame] | 67 | if item.is_stock_item==1 and d.qty and not d.warehouse and not d.get("delivered_by_supplier"): |
Rushabh Mehta | cc8b2b2 | 2017-03-31 12:44:29 +0530 | [diff] [blame] | 68 | frappe.throw(_("Warehouse is mandatory for stock Item {0} in row {1}").format(d.item_code, d.idx)) |
| 69 | |
| 70 | items.append(cstr(d.item_code)) |
| 71 | |
| 72 | if items and len(items) != len(set(items)) and \ |
| 73 | not cint(frappe.db.get_single_value("Buying Settings", "allow_multiple_items") or 0): |
| 74 | frappe.throw(_("Same item cannot be entered multiple times.")) |
| 75 | |
Mangesh-Khairnar | a1afd78 | 2019-03-11 17:15:05 +0530 | [diff] [blame] | 76 | def check_on_hold_or_closed_status(doctype, docname): |
Rushabh Mehta | cc8b2b2 | 2017-03-31 12:44:29 +0530 | [diff] [blame] | 77 | status = frappe.db.get_value(doctype, docname, "status") |
| 78 | |
Mangesh-Khairnar | a1afd78 | 2019-03-11 17:15:05 +0530 | [diff] [blame] | 79 | if status in ("Closed", "On Hold"): |
Rushabh Mehta | cc8b2b2 | 2017-03-31 12:44:29 +0530 | [diff] [blame] | 80 | frappe.throw(_("{0} {1} status is {2}").format(doctype, docname, status), frappe.InvalidStatusError) |
| 81 | |
mbauskar | c482aed | 2017-05-02 12:53:12 +0530 | [diff] [blame] | 82 | @frappe.whitelist() |
| 83 | def get_linked_material_requests(items): |
| 84 | items = json.loads(items) |
| 85 | mr_list = [] |
| 86 | for item in items: |
| 87 | material_request = frappe.db.sql("""SELECT distinct mr.name AS mr_name, |
| 88 | (mr_item.qty - mr_item.ordered_qty) AS qty, |
| 89 | mr_item.item_code AS item_code, |
| 90 | mr_item.name AS mr_item |
| 91 | FROM `tabMaterial Request` mr, `tabMaterial Request Item` mr_item |
| 92 | WHERE mr.name = mr_item.parent |
| 93 | AND mr_item.item_code = %(item)s |
| 94 | AND mr.material_request_type = 'Purchase' |
| 95 | AND mr.per_ordered < 99.99 |
| 96 | AND mr.docstatus = 1 |
| 97 | AND mr.status != 'Stopped' |
| 98 | ORDER BY mr_item.item_code ASC""",{"item": item}, as_dict=1) |
| 99 | if material_request: |
| 100 | mr_list.append(material_request) |
| 101 | |
| 102 | return mr_list |
| 103 | |