2019-03-29 15:14:23 +00:00
|
|
|
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
|
|
|
|
# For license information, please see license.txt
|
|
|
|
|
2021-09-02 11:14:59 +00:00
|
|
|
|
2019-03-29 15:14:23 +00:00
|
|
|
import frappe
|
|
|
|
from frappe import _
|
2020-05-31 14:41:40 +00:00
|
|
|
from frappe.utils import flt
|
2019-03-29 15:14:23 +00:00
|
|
|
|
2021-09-02 11:14:59 +00:00
|
|
|
|
2019-03-29 15:14:23 +00:00
|
|
|
def execute(filters=None):
|
2019-04-28 11:41:02 +00:00
|
|
|
columns = get_columns(filters)
|
|
|
|
data = get_data(filters)
|
2019-03-29 15:14:23 +00:00
|
|
|
return columns, data
|
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
|
2019-04-28 11:41:02 +00:00
|
|
|
def get_columns(filters):
|
2019-03-29 15:14:23 +00:00
|
|
|
columns = [
|
|
|
|
{
|
2019-04-21 18:14:21 +00:00
|
|
|
"label": _("Material Request Date"),
|
|
|
|
"fieldname": "material_request_date",
|
2019-03-29 15:14:23 +00:00
|
|
|
"fieldtype": "Date",
|
|
|
|
"width": 140,
|
|
|
|
},
|
2019-04-25 19:59:36 +00:00
|
|
|
{
|
|
|
|
"label": _("Material Request No"),
|
|
|
|
"options": "Material Request",
|
|
|
|
"fieldname": "material_request_no",
|
|
|
|
"fieldtype": "Link",
|
|
|
|
"width": 140,
|
|
|
|
},
|
2019-03-29 15:14:23 +00:00
|
|
|
{
|
2019-04-21 18:14:21 +00:00
|
|
|
"label": _("Cost Center"),
|
|
|
|
"options": "Cost Center",
|
|
|
|
"fieldname": "cost_center",
|
|
|
|
"fieldtype": "Link",
|
2019-03-29 15:14:23 +00:00
|
|
|
"width": 140,
|
|
|
|
},
|
|
|
|
{
|
2019-04-21 18:14:21 +00:00
|
|
|
"label": _("Project"),
|
|
|
|
"options": "Project",
|
|
|
|
"fieldname": "project",
|
2019-03-29 15:14:23 +00:00
|
|
|
"fieldtype": "Link",
|
|
|
|
"width": 140,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"label": _("Requesting Site"),
|
|
|
|
"options": "Warehouse",
|
|
|
|
"fieldname": "requesting_site",
|
|
|
|
"fieldtype": "Link",
|
|
|
|
"width": 140,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"label": _("Requestor"),
|
|
|
|
"options": "Employee",
|
|
|
|
"fieldname": "requestor",
|
|
|
|
"fieldtype": "Link",
|
|
|
|
"width": 140,
|
|
|
|
},
|
|
|
|
{
|
2020-05-31 14:41:40 +00:00
|
|
|
"label": _("Item"),
|
|
|
|
"fieldname": "item_code",
|
|
|
|
"fieldtype": "Link",
|
|
|
|
"options": "Item",
|
|
|
|
"width": 150,
|
2019-03-29 15:14:23 +00:00
|
|
|
},
|
|
|
|
{"label": _("Quantity"), "fieldname": "quantity", "fieldtype": "Float", "width": 140},
|
|
|
|
{
|
|
|
|
"label": _("Unit of Measure"),
|
|
|
|
"options": "UOM",
|
|
|
|
"fieldname": "unit_of_measurement",
|
|
|
|
"fieldtype": "Link",
|
|
|
|
"width": 140,
|
|
|
|
},
|
|
|
|
{"label": _("Status"), "fieldname": "status", "fieldtype": "data", "width": 140},
|
|
|
|
{
|
|
|
|
"label": _("Purchase Order Date"),
|
|
|
|
"fieldname": "purchase_order_date",
|
|
|
|
"fieldtype": "Date",
|
|
|
|
"width": 140,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"label": _("Purchase Order"),
|
|
|
|
"options": "Purchase Order",
|
|
|
|
"fieldname": "purchase_order",
|
|
|
|
"fieldtype": "Link",
|
|
|
|
"width": 140,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"label": _("Supplier"),
|
|
|
|
"options": "Supplier",
|
|
|
|
"fieldname": "supplier",
|
|
|
|
"fieldtype": "Link",
|
|
|
|
"width": 140,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"label": _("Estimated Cost"),
|
|
|
|
"fieldname": "estimated_cost",
|
|
|
|
"fieldtype": "Float",
|
|
|
|
"width": 140,
|
|
|
|
},
|
|
|
|
{"label": _("Actual Cost"), "fieldname": "actual_cost", "fieldtype": "Float", "width": 140},
|
|
|
|
{
|
|
|
|
"label": _("Purchase Order Amount"),
|
2019-04-21 18:14:21 +00:00
|
|
|
"fieldname": "purchase_order_amt",
|
2019-03-29 15:14:23 +00:00
|
|
|
"fieldtype": "Float",
|
|
|
|
"width": 140,
|
|
|
|
},
|
|
|
|
{
|
2019-04-21 18:14:21 +00:00
|
|
|
"label": _("Purchase Order Amount(Company Currency)"),
|
2020-05-31 14:41:40 +00:00
|
|
|
"fieldname": "purchase_order_amt_in_company_currency",
|
2019-03-29 15:14:23 +00:00
|
|
|
"fieldtype": "Float",
|
|
|
|
"width": 140,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"label": _("Expected Delivery Date"),
|
|
|
|
"fieldname": "expected_delivery_date",
|
|
|
|
"fieldtype": "Date",
|
|
|
|
"width": 140,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"label": _("Actual Delivery Date"),
|
|
|
|
"fieldname": "actual_delivery_date",
|
|
|
|
"fieldtype": "Date",
|
|
|
|
"width": 140,
|
|
|
|
},
|
|
|
|
]
|
|
|
|
return columns
|
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
|
2022-10-07 12:43:33 +00:00
|
|
|
def apply_filters_on_query(filters, parent, child, query):
|
2019-04-28 11:41:02 +00:00
|
|
|
if filters.get("company"):
|
2022-10-07 12:43:33 +00:00
|
|
|
query = query.where(parent.company == filters.get("company"))
|
2019-05-03 10:30:02 +00:00
|
|
|
|
2019-04-28 11:41:02 +00:00
|
|
|
if filters.get("cost_center") or filters.get("project"):
|
2022-10-07 12:43:33 +00:00
|
|
|
query = query.where(
|
|
|
|
(child.cost_center == filters.get("cost_center")) | (child.project == filters.get("project"))
|
2020-04-26 17:59:13 +00:00
|
|
|
)
|
2019-05-03 10:30:02 +00:00
|
|
|
|
|
|
|
if filters.get("from_date"):
|
2022-10-07 12:43:33 +00:00
|
|
|
query = query.where(parent.transaction_date >= filters.get("from_date"))
|
2019-05-03 10:30:02 +00:00
|
|
|
|
|
|
|
if filters.get("to_date"):
|
2022-10-07 12:43:33 +00:00
|
|
|
query = query.where(parent.transaction_date <= filters.get("to_date"))
|
|
|
|
|
|
|
|
return query
|
2019-04-28 11:41:02 +00:00
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
|
2019-04-28 11:41:02 +00:00
|
|
|
def get_data(filters):
|
2022-10-07 12:43:33 +00:00
|
|
|
purchase_order_entry = get_po_entries(filters)
|
|
|
|
mr_records, procurement_record_against_mr = get_mapped_mr_details(filters)
|
2019-04-25 19:59:36 +00:00
|
|
|
pr_records = get_mapped_pr_records()
|
|
|
|
pi_records = get_mapped_pi_records()
|
2019-04-01 15:44:05 +00:00
|
|
|
|
2019-04-25 19:59:36 +00:00
|
|
|
procurement_record = []
|
|
|
|
if procurement_record_against_mr:
|
|
|
|
procurement_record += procurement_record_against_mr
|
|
|
|
for po in purchase_order_entry:
|
|
|
|
# fetch material records linked to the purchase order item
|
|
|
|
mr_record = mr_records.get(po.material_request_item, [{}])[0]
|
|
|
|
procurement_detail = {
|
2019-04-28 11:41:02 +00:00
|
|
|
"material_request_date": mr_record.get("transaction_date"),
|
2019-04-25 19:59:36 +00:00
|
|
|
"cost_center": po.cost_center,
|
|
|
|
"project": po.project,
|
|
|
|
"requesting_site": po.warehouse,
|
|
|
|
"requestor": po.owner,
|
|
|
|
"material_request_no": po.material_request,
|
2020-05-31 14:41:40 +00:00
|
|
|
"item_code": po.item_code,
|
|
|
|
"quantity": flt(po.qty),
|
2019-04-25 19:59:36 +00:00
|
|
|
"unit_of_measurement": po.stock_uom,
|
|
|
|
"status": po.status,
|
|
|
|
"purchase_order_date": po.transaction_date,
|
|
|
|
"purchase_order": po.parent,
|
|
|
|
"supplier": po.supplier,
|
2020-05-31 14:41:40 +00:00
|
|
|
"estimated_cost": flt(mr_record.get("amount")),
|
|
|
|
"actual_cost": flt(pi_records.get(po.name)),
|
|
|
|
"purchase_order_amt": flt(po.amount),
|
|
|
|
"purchase_order_amt_in_company_currency": flt(po.base_amount),
|
2019-04-25 19:59:36 +00:00
|
|
|
"expected_delivery_date": po.schedule_date,
|
2019-04-26 10:32:25 +00:00
|
|
|
"actual_delivery_date": pr_records.get(po.name),
|
2019-04-25 19:59:36 +00:00
|
|
|
}
|
|
|
|
procurement_record.append(procurement_detail)
|
|
|
|
return procurement_record
|
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
|
2022-10-07 12:43:33 +00:00
|
|
|
def get_mapped_mr_details(filters):
|
2019-04-25 19:59:36 +00:00
|
|
|
mr_records = {}
|
2022-10-07 12:43:33 +00:00
|
|
|
parent = frappe.qb.DocType("Material Request")
|
|
|
|
child = frappe.qb.DocType("Material Request Item")
|
|
|
|
|
|
|
|
query = (
|
|
|
|
frappe.qb.from_(parent)
|
|
|
|
.from_(child)
|
|
|
|
.select(
|
2020-10-14 04:59:25 +00:00
|
|
|
parent.transaction_date,
|
|
|
|
parent.per_ordered,
|
|
|
|
parent.owner,
|
2020-04-26 17:59:13 +00:00
|
|
|
child.name,
|
|
|
|
child.parent,
|
2020-05-31 14:41:40 +00:00
|
|
|
child.amount,
|
|
|
|
child.qty,
|
|
|
|
child.item_code,
|
|
|
|
child.uom,
|
2020-10-14 04:59:25 +00:00
|
|
|
parent.status,
|
|
|
|
child.project,
|
2022-10-07 12:43:33 +00:00
|
|
|
child.cost_center,
|
|
|
|
)
|
|
|
|
.where((parent.per_ordered >= 0) & (parent.name == child.parent) & (parent.docstatus == 1))
|
|
|
|
)
|
|
|
|
query = apply_filters_on_query(filters, parent, child, query)
|
|
|
|
|
|
|
|
mr_details = query.run(as_dict=True)
|
2019-04-03 14:15:08 +00:00
|
|
|
|
2019-04-25 19:59:36 +00:00
|
|
|
procurement_record_against_mr = []
|
|
|
|
for record in mr_details:
|
|
|
|
if record.per_ordered:
|
|
|
|
mr_records.setdefault(record.name, []).append(frappe._dict(record))
|
|
|
|
else:
|
|
|
|
procurement_record_details = dict(
|
|
|
|
material_request_date=record.transaction_date,
|
|
|
|
material_request_no=record.parent,
|
2020-05-31 14:41:40 +00:00
|
|
|
requestor=record.owner,
|
|
|
|
item_code=record.item_code,
|
|
|
|
estimated_cost=flt(record.amount),
|
|
|
|
quantity=flt(record.qty),
|
|
|
|
unit_of_measurement=record.uom,
|
|
|
|
status=record.status,
|
|
|
|
actual_cost=0,
|
|
|
|
purchase_order_amt=0,
|
2020-10-14 04:59:25 +00:00
|
|
|
purchase_order_amt_in_company_currency=0,
|
|
|
|
project=record.project,
|
|
|
|
cost_center=record.cost_center,
|
2019-04-25 19:59:36 +00:00
|
|
|
)
|
2019-04-26 10:32:25 +00:00
|
|
|
procurement_record_against_mr.append(procurement_record_details)
|
2019-04-25 19:59:36 +00:00
|
|
|
return mr_records, procurement_record_against_mr
|
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
|
2019-04-25 19:59:36 +00:00
|
|
|
def get_mapped_pi_records():
|
2022-10-07 12:43:33 +00:00
|
|
|
po = frappe.qb.DocType("Purchase Order")
|
|
|
|
pi_item = frappe.qb.DocType("Purchase Invoice Item")
|
|
|
|
pi_records = (
|
|
|
|
frappe.qb.from_(pi_item)
|
|
|
|
.inner_join(po)
|
|
|
|
.on(pi_item.purchase_order == po.name)
|
|
|
|
.select(pi_item.po_detail, pi_item.base_amount)
|
|
|
|
.where(
|
|
|
|
(pi_item.docstatus == 1)
|
|
|
|
& (po.status.notin(("Closed", "Completed", "Cancelled")))
|
|
|
|
& (pi_item.po_detail.isnotnull())
|
2019-04-03 14:15:08 +00:00
|
|
|
)
|
2022-10-07 12:43:33 +00:00
|
|
|
).run()
|
|
|
|
|
|
|
|
return frappe._dict(pi_records)
|
2022-03-28 13:22:46 +00:00
|
|
|
|
2019-04-03 14:15:08 +00:00
|
|
|
|
2019-04-25 19:59:36 +00:00
|
|
|
def get_mapped_pr_records():
|
2022-10-07 12:43:33 +00:00
|
|
|
pr = frappe.qb.DocType("Purchase Receipt")
|
|
|
|
pr_item = frappe.qb.DocType("Purchase Receipt Item")
|
|
|
|
pr_records = (
|
|
|
|
frappe.qb.from_(pr)
|
|
|
|
.from_(pr_item)
|
|
|
|
.select(pr_item.purchase_order_item, pr.posting_date)
|
|
|
|
.where(
|
|
|
|
(pr.docstatus == 1)
|
|
|
|
& (pr.name == pr_item.parent)
|
|
|
|
& (pr_item.purchase_order_item.isnotnull())
|
|
|
|
& (pr.status.notin(("Closed", "Completed", "Cancelled")))
|
2019-04-21 18:14:21 +00:00
|
|
|
)
|
2022-10-07 12:43:33 +00:00
|
|
|
).run()
|
|
|
|
|
|
|
|
return frappe._dict(pr_records)
|
2022-03-28 13:22:46 +00:00
|
|
|
|
2019-04-21 18:14:21 +00:00
|
|
|
|
2022-10-07 12:43:33 +00:00
|
|
|
def get_po_entries(filters):
|
|
|
|
parent = frappe.qb.DocType("Purchase Order")
|
|
|
|
child = frappe.qb.DocType("Purchase Order Item")
|
|
|
|
|
|
|
|
query = (
|
|
|
|
frappe.qb.from_(parent)
|
|
|
|
.from_(child)
|
|
|
|
.select(
|
2020-04-26 17:59:13 +00:00
|
|
|
child.name,
|
|
|
|
child.parent,
|
|
|
|
child.cost_center,
|
|
|
|
child.project,
|
|
|
|
child.warehouse,
|
|
|
|
child.material_request,
|
|
|
|
child.material_request_item,
|
2020-05-31 14:41:40 +00:00
|
|
|
child.item_code,
|
2020-04-26 17:59:13 +00:00
|
|
|
child.stock_uom,
|
|
|
|
child.qty,
|
|
|
|
child.amount,
|
|
|
|
child.base_amount,
|
|
|
|
child.schedule_date,
|
2020-10-14 04:59:25 +00:00
|
|
|
parent.transaction_date,
|
|
|
|
parent.supplier,
|
|
|
|
parent.status,
|
2022-10-07 12:43:33 +00:00
|
|
|
parent.owner,
|
|
|
|
)
|
|
|
|
.where(
|
|
|
|
(parent.docstatus == 1)
|
|
|
|
& (parent.name == child.parent)
|
|
|
|
& (parent.status.notin(("Closed", "Completed", "Cancelled")))
|
|
|
|
)
|
|
|
|
.groupby(parent.name, child.item_code)
|
|
|
|
)
|
|
|
|
query = apply_filters_on_query(filters, parent, child, query)
|
|
|
|
|
|
|
|
return query.run(as_dict=True)
|