Merge pull request #17476 from Anurag810/subs
feat: subcontracting report
diff --git a/erpnext/buying/report/subcontracted_item_to_be_received/__init__.py b/erpnext/buying/report/subcontracted_item_to_be_received/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/buying/report/subcontracted_item_to_be_received/__init__.py
diff --git a/erpnext/buying/report/subcontracted_item_to_be_received/subcontracted_item_to_be_received.js b/erpnext/buying/report/subcontracted_item_to_be_received/subcontracted_item_to_be_received.js
new file mode 100644
index 0000000..fc58b6a
--- /dev/null
+++ b/erpnext/buying/report/subcontracted_item_to_be_received/subcontracted_item_to_be_received.js
@@ -0,0 +1,29 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+/* eslint-disable */
+
+frappe.query_reports["Subcontracted Item To Be Received"] = {
+ "filters": [
+ {
+ fieldname: "supplier",
+ label: __("Supplier"),
+ fieldtype: "Link",
+ options: "Supplier",
+ reqd: 1
+ },
+ {
+ fieldname:"from_date",
+ label: __("From Date"),
+ fieldtype: "Date",
+ default: frappe.datetime.add_months(frappe.datetime.month_start(), -1),
+ reqd: 1
+ },
+ {
+ fieldname:"to_date",
+ label: __("To Date"),
+ fieldtype: "Date",
+ default: frappe.datetime.add_days(frappe.datetime.month_start(),-1),
+ reqd: 1
+ },
+ ]
+};
diff --git a/erpnext/buying/report/subcontracted_item_to_be_received/subcontracted_item_to_be_received.json b/erpnext/buying/report/subcontracted_item_to_be_received/subcontracted_item_to_be_received.json
new file mode 100644
index 0000000..fdf6cf7
--- /dev/null
+++ b/erpnext/buying/report/subcontracted_item_to_be_received/subcontracted_item_to_be_received.json
@@ -0,0 +1,30 @@
+{
+ "add_total_row": 1,
+ "creation": "2019-05-03 11:25:03.685247",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "idx": 0,
+ "is_standard": "Yes",
+ "modified": "2019-05-03 11:25:03.685247",
+ "modified_by": "Administrator",
+ "module": "Buying",
+ "name": "Subcontracted Item To Be Received",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "Purchase Order",
+ "report_name": "Subcontracted Item To Be Received",
+ "report_type": "Script Report",
+ "roles": [
+ {
+ "role": "Stock User"
+ },
+ {
+ "role": "Purchase Manager"
+ },
+ {
+ "role": "Purchase User"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/buying/report/subcontracted_item_to_be_received/subcontracted_item_to_be_received.py b/erpnext/buying/report/subcontracted_item_to_be_received/subcontracted_item_to_be_received.py
new file mode 100644
index 0000000..2da53d7
--- /dev/null
+++ b/erpnext/buying/report/subcontracted_item_to_be_received/subcontracted_item_to_be_received.py
@@ -0,0 +1,104 @@
+# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+
+def execute(filters=None):
+ if filters.from_date >= filters.to_date:
+ frappe.msgprint(_("To Date must be greater than From Date"))
+
+ data = []
+ columns = get_columns()
+ get_data(data , filters)
+ return columns, data
+
+def get_columns():
+ return [
+ {
+ "label": _("Purchase Order"),
+ "fieldtype": "Link",
+ "fieldname": "purchase_order",
+ "options": "Purchase Order",
+ "width": 150
+ },
+ {
+ "label": _("Date"),
+ "fieldtype": "Date",
+ "fieldname": "date",
+ "hidden": 1,
+ "width": 150
+ },
+ {
+ "label": _("Supplier"),
+ "fieldtype": "Link",
+ "fieldname": "supplier",
+ "options": "Supplier",
+ "width": 150
+ },
+ {
+ "label": _("Finished Good Item Code"),
+ "fieldtype": "Data",
+ "fieldname": "fg_item_code",
+ "width": 100
+ },
+ {
+ "label": _("Item name"),
+ "fieldtype": "Data",
+ "fieldname": "item_name",
+ "width": 100
+ },
+ {
+ "label": _("Required Quantity"),
+ "fieldtype": "Float",
+ "fieldname": "required_qty",
+ "width": 100
+ },
+ {
+ "label": _("Received Quantity"),
+ "fieldtype": "Float",
+ "fieldname": "received_qty",
+ "width": 100
+ },
+ {
+ "label": _("Pending Quantity"),
+ "fieldtype": "Float",
+ "fieldname": "pending_qty",
+ "width": 100
+ }
+ ]
+
+def get_data(data, filters):
+ po = get_po(filters)
+ po_name = [v.name for v in po]
+ sub_items = get_purchase_order_item_supplied(po_name)
+ for item in sub_items:
+ for order in po:
+ if order.name == item.parent and item.received_qty < item.qty:
+ row ={
+ 'purchase_order': item.parent,
+ 'date': order.transaction_date,
+ 'supplier': order.supplier,
+ 'fg_item_code': item.item_code,
+ 'item_name': item.item_name,
+ 'required_qty': item.qty,
+ 'received_qty':item.received_qty,
+ 'pending_qty':item.qty - item.received_qty
+ }
+ data.append(row)
+
+def get_po(filters):
+ record_filters = [
+ ["is_subcontracted", "=", "Yes"],
+ ["supplier", "=", filters.supplier],
+ ["transaction_date", "<=", filters.to_date],
+ ["transaction_date", ">=", filters.from_date],
+ ["docstatus", "=", 1]
+ ]
+ return frappe.get_all("Purchase Order", filters=record_filters, fields=["name", "transaction_date", "supplier"])
+
+def get_purchase_order_item_supplied(po):
+ return frappe.get_all("Purchase Order Item", filters=[
+ ('parent', 'IN', po)
+ ], fields=["parent", "item_code", "item_name", "qty", "received_qty"])
diff --git a/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py b/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py
new file mode 100644
index 0000000..d8de701
--- /dev/null
+++ b/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py
@@ -0,0 +1,36 @@
+# Python bytecode 2.7 (62211)
+# Embedded file name: /Users/anuragmishra/frappe-develop/apps/erpnext/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py
+# Compiled at: 2019-05-06 09:51:46
+# Decompiled by https://python-decompiler.com
+from __future__ import unicode_literals
+from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
+from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_receipt
+from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
+from erpnext.buying.report.subcontracted_item_to_be_received.subcontracted_item_to_be_received import execute
+import frappe, unittest
+from pprint import pprint
+
+class TestSubcontractedItemToBeReceived(unittest.TestCase):
+
+ def test_pending_and_received_qty(self):
+ po = create_purchase_order(item_code='_Test FG Item', is_subcontracted='Yes')
+ transfer_param = []
+ make_stock_entry(item_code='_Test Item', target='_Test Warehouse 1 - _TC', qty=100, basic_rate=100)
+ make_stock_entry(item_code='_Test Item Home Desktop 100', target='_Test Warehouse 1 - _TC', qty=100, basic_rate=100)
+ make_purchase_receipt_against_po(po.name)
+ po.reload()
+ col, data = execute(filters=frappe._dict({'supplier': po.supplier,
+ 'from_date': frappe.utils.get_datetime(frappe.utils.add_to_date(po.transaction_date, days=-10)),
+ 'to_date': frappe.utils.get_datetime(frappe.utils.add_to_date(po.transaction_date, days=10))}))
+ self.assertEqual(data[0]['pending_qty'], 5)
+ self.assertEqual(data[0]['received_qty'], 5)
+ self.assertEqual(data[0]['purchase_order'], po.name)
+ self.assertEqual(data[0]['supplier'], po.supplier)
+
+
+def make_purchase_receipt_against_po(po, quantity=5):
+ pr = make_purchase_receipt(po)
+ pr.items[0].qty = quantity
+ pr.supplier_warehouse = '_Test Warehouse 1 - _TC'
+ pr.insert()
+ pr.submit()
\ No newline at end of file
diff --git a/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/__init__.py b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/__init__.py
diff --git a/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/subcontracted_raw_materials_to_be_transferred.js b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/subcontracted_raw_materials_to_be_transferred.js
new file mode 100644
index 0000000..0853afd
--- /dev/null
+++ b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/subcontracted_raw_materials_to_be_transferred.js
@@ -0,0 +1,29 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+/* eslint-disable */
+
+frappe.query_reports["Subcontracted Raw Materials To Be Transferred"] = {
+ "filters": [
+ {
+ fieldname: "supplier",
+ label: __("Supplier"),
+ fieldtype: "Link",
+ options: "Supplier",
+ reqd: 1
+ },
+ {
+ fieldname:"from_date",
+ label: __("From Date"),
+ fieldtype: "Date",
+ default: frappe.datetime.add_months(frappe.datetime.month_start(), -1),
+ reqd: 1
+ },
+ {
+ fieldname:"to_date",
+ label: __("To Date"),
+ fieldtype: "Date",
+ default: frappe.datetime.add_days(frappe.datetime.month_start(),-1),
+ reqd: 1
+ },
+ ]
+}
diff --git a/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/subcontracted_raw_materials_to_be_transferred.json b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/subcontracted_raw_materials_to_be_transferred.json
new file mode 100644
index 0000000..c7cee5e
--- /dev/null
+++ b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/subcontracted_raw_materials_to_be_transferred.json
@@ -0,0 +1,30 @@
+{
+ "add_total_row": 1,
+ "creation": "2019-05-03 12:04:14.438345",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "idx": 0,
+ "is_standard": "Yes",
+ "modified": "2019-05-03 12:04:24.203721",
+ "modified_by": "Administrator",
+ "module": "Buying",
+ "name": "Subcontracted Raw Materials To Be Transferred",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "Purchase Order",
+ "report_name": "Subcontracted Raw Materials To Be Transferred",
+ "report_type": "Script Report",
+ "roles": [
+ {
+ "role": "Stock User"
+ },
+ {
+ "role": "Purchase Manager"
+ },
+ {
+ "role": "Purchase User"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/subcontracted_raw_materials_to_be_transferred.py b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/subcontracted_raw_materials_to_be_transferred.py
new file mode 100644
index 0000000..de2ae8f
--- /dev/null
+++ b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/subcontracted_raw_materials_to_be_transferred.py
@@ -0,0 +1,137 @@
+# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+
+def execute(filters=None):
+ if filters.from_date >= filters.to_date:
+ frappe.msgprint(_("To Date must be greater than From Date"))
+
+ data = []
+ columns = get_columns()
+ get_data(data , filters)
+ return columns, data
+
+def get_columns():
+ return [
+ {
+ "label": _("Purchase Order"),
+ "fieldtype": "Link",
+ "fieldname": "purchase_order",
+ "options": "Purchase Order",
+ "width": 150
+ },
+ {
+ "label": _("Date"),
+ "fieldtype": "Date",
+ "fieldname": "date",
+ "hidden": 1,
+ "width": 150
+ },
+ {
+ "label": _("Supplier"),
+ "fieldtype": "Link",
+ "fieldname": "supplier",
+ "options": "Supplier",
+ "width": 150
+ },
+ {
+ "label": _("Item Code"),
+ "fieldtype": "Data",
+ "fieldname": "rm_item_code",
+ "width": 100
+ },
+ {
+ "label": _("Required Quantity"),
+ "fieldtype": "Float",
+ "fieldname": "r_qty",
+ "width": 100
+ },
+ {
+ "label": _("Transferred Quantity"),
+ "fieldtype": "Float",
+ "fieldname": "t_qty",
+ "width": 100
+ },
+ {
+ "label": _("Pending Quantity"),
+ "fieldtype": "Float",
+ "fieldname": "p_qty",
+ "width": 100
+ }
+ ]
+
+def get_data(data, filters):
+ po = get_po(filters)
+ po_transferred_qty_map = frappe._dict(get_transferred_quantity([v.name for v in po]))
+
+ sub_items = get_purchase_order_item_supplied([v.name for v in po])
+
+ for order in po:
+ for item in sub_items:
+ if order.name == item.parent and order.name in po_transferred_qty_map and \
+ item.required_qty != po_transferred_qty_map.get(order.name).get(item.rm_item_code):
+ transferred_qty = po_transferred_qty_map.get(order.name).get(item.rm_item_code) \
+ if po_transferred_qty_map.get(order.name).get(item.rm_item_code) else 0
+ row ={
+ 'purchase_order': item.parent,
+ 'date': order.transaction_date,
+ 'supplier': order.supplier,
+ 'rm_item_code': item.rm_item_code,
+ 'r_qty': item.required_qty,
+ 't_qty':transferred_qty,
+ 'p_qty':item.required_qty - transferred_qty
+ }
+
+ data.append(row)
+
+ return(data)
+
+def get_po(filters):
+ record_filters = [
+ ["is_subcontracted", "=", "Yes"],
+ ["supplier", "=", filters.supplier],
+ ["transaction_date", "<=", filters.to_date],
+ ["transaction_date", ">=", filters.from_date],
+ ["docstatus", "=", 1]
+ ]
+ return frappe.get_all("Purchase Order", filters=record_filters, fields=["name", "transaction_date", "supplier"])
+
+def get_transferred_quantity(po_name):
+ stock_entries = get_stock_entry(po_name)
+ stock_entries_detail = get_stock_entry_detail([v.name for v in stock_entries])
+ po_transferred_qty_map = {}
+
+
+ for entry in stock_entries:
+ for details in stock_entries_detail:
+ if details.parent == entry.name:
+ details["Purchase_order"] = entry.purchase_order
+ if entry.purchase_order not in po_transferred_qty_map:
+ po_transferred_qty_map[entry.purchase_order] = {}
+ po_transferred_qty_map[entry.purchase_order][details.item_code] = details.qty
+ else:
+ po_transferred_qty_map[entry.purchase_order][details.item_code] = po_transferred_qty_map[entry.purchase_order].get(details.item_code, 0) + details.qty
+
+ return po_transferred_qty_map
+
+
+def get_stock_entry(po):
+ return frappe.get_all("Stock Entry", filters=[
+ ('purchase_order', 'IN', po),
+ ('stock_entry_type', '=', 'Send to Subcontractor'),
+ ('docstatus', '=', 1)
+ ], fields=["name", "purchase_order"])
+
+def get_stock_entry_detail(se):
+ return frappe.get_all("Stock Entry Detail", filters=[
+ ["parent", "in", se]
+ ],
+ fields=["parent", "item_code", "qty"])
+
+def get_purchase_order_item_supplied(po):
+ return frappe.get_all("Purchase Order Item Supplied", filters=[
+ ('parent', 'IN', po)
+ ], fields=['parent', 'rm_item_code', 'required_qty'])
diff --git a/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py
new file mode 100644
index 0000000..6900938
--- /dev/null
+++ b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py
@@ -0,0 +1,44 @@
+# Python bytecode 2.7 (62211)
+# Embedded file name: /Users/anuragmishra/frappe-develop/apps/erpnext/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py
+# Compiled at: 2019-05-06 10:24:35
+# Decompiled by https://python-decompiler.com
+from __future__ import unicode_literals
+from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
+from erpnext.buying.doctype.purchase_order.purchase_order import make_rm_stock_entry
+from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
+from erpnext.buying.report.subcontracted_raw_materials_to_be_transferred.subcontracted_raw_materials_to_be_transferred import execute
+import json, frappe, unittest
+
+class TestSubcontractedItemToBeReceived(unittest.TestCase):
+
+ def test_pending_and_received_qty(self):
+ po = create_purchase_order(item_code='_Test FG Item', is_subcontracted='Yes')
+ make_stock_entry(item_code='_Test Item', target='_Test Warehouse 1 - _TC', qty=100, basic_rate=100)
+ make_stock_entry(item_code='_Test Item Home Desktop 100', target='_Test Warehouse 1 - _TC', qty=100, basic_rate=100)
+ transfer_subcontracted_raw_materials(po.name)
+ col, data = execute(filters=frappe._dict({'supplier': po.supplier,
+ 'from_date': frappe.utils.get_datetime(frappe.utils.add_to_date(po.transaction_date, days=-10)),
+ 'to_date': frappe.utils.get_datetime(frappe.utils.add_to_date(po.transaction_date, days=10))}))
+ self.assertEqual(data[0]['purchase_order'], po.name)
+ self.assertIn(data[0]['rm_item_code'], ['_Test Item', '_Test Item Home Desktop 100'])
+ self.assertIn(data[0]['p_qty'], [9, 18])
+ self.assertIn(data[0]['t_qty'], [1, 2])
+
+ self.assertEqual(data[1]['purchase_order'], po.name)
+ self.assertIn(data[1]['rm_item_code'], ['_Test Item', '_Test Item Home Desktop 100'])
+ self.assertIn(data[1]['p_qty'], [9, 18])
+ self.assertIn(data[1]['t_qty'], [1, 2])
+
+
+def transfer_subcontracted_raw_materials(po):
+ rm_item = [
+ {'item_code': '_Test Item', 'rm_item_code': '_Test Item', 'item_name': '_Test Item', 'qty': 1,
+ 'warehouse': '_Test Warehouse - _TC', 'rate': 100, 'amount': 100, 'stock_uom': 'Nos'},
+ {'item_code': '_Test Item Home Desktop 100', 'rm_item_code': '_Test Item Home Desktop 100', 'item_name': '_Test Item Home Desktop 100', 'qty': 2,
+ 'warehouse': '_Test Warehouse - _TC', 'rate': 100, 'amount': 200, 'stock_uom': 'Nos'}]
+ rm_item_string = json.dumps(rm_item)
+ se = frappe.get_doc(make_rm_stock_entry(po, rm_item_string))
+ se.to_warehouse = '_Test Warehouse 1 - _TC'
+ se.stock_entry_type = 'Send to Subcontractor'
+ se.save()
+ se.submit()
\ No newline at end of file