Merge pull request #26020 from marination/subcontracted-rm-to-transfer-report-develop
fix: Report Subcontracted Raw Materials to be Transferred
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
index de2ae8f..68426ab 100644
--- 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
@@ -9,10 +9,10 @@
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
+ data = get_data(filters)
+
+ return columns, data or []
def get_columns():
return [
@@ -21,13 +21,12 @@
"fieldtype": "Link",
"fieldname": "purchase_order",
"options": "Purchase Order",
- "width": 150
+ "width": 200
},
{
"label": _("Date"),
"fieldtype": "Date",
"fieldname": "date",
- "hidden": 1,
"width": 150
},
{
@@ -41,97 +40,58 @@
"label": _("Item Code"),
"fieldtype": "Data",
"fieldname": "rm_item_code",
- "width": 100
+ "width": 150
},
{
"label": _("Required Quantity"),
"fieldtype": "Float",
- "fieldname": "r_qty",
- "width": 100
+ "fieldname": "reqd_qty",
+ "width": 150
},
{
"label": _("Transferred Quantity"),
"fieldtype": "Float",
- "fieldname": "t_qty",
- "width": 100
+ "fieldname": "transferred_qty",
+ "width": 200
},
{
"label": _("Pending Quantity"),
"fieldtype": "Float",
"fieldname": "p_qty",
- "width": 100
+ "width": 150
}
]
-def get_data(data, filters):
- po = get_po(filters)
- po_transferred_qty_map = frappe._dict(get_transferred_quantity([v.name for v in po]))
+def get_data(filters):
+ po_rm_item_details = get_po_items_to_supply(filters)
- sub_items = get_purchase_order_item_supplied([v.name for v in po])
+ data = []
+ for row in po_rm_item_details:
+ transferred_qty = row.get("transferred_qty") or 0
+ if transferred_qty < row.get("reqd_qty", 0):
+ pending_qty = frappe.utils.flt(row.get("reqd_qty", 0) - transferred_qty)
+ row.p_qty = pending_qty if pending_qty > 0 else 0
+ data.append(row)
- 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
- }
+ return data
- 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]
+def get_po_items_to_supply(filters):
+ return frappe.db.get_all(
+ "Purchase Order",
+ fields=[
+ "name as purchase_order",
+ "transaction_date as date",
+ "supplier as supplier",
+ "`tabPurchase Order Item Supplied`.rm_item_code as rm_item_code",
+ "`tabPurchase Order Item Supplied`.required_qty as reqd_qty",
+ "`tabPurchase Order Item Supplied`.supplied_qty as transferred_qty"
],
- 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'])
+ filters = [
+ ["Purchase Order", "per_received", "<", "100"],
+ ["Purchase Order", "is_subcontracted", "=", "Yes"],
+ ["Purchase Order", "supplier", "=", filters.supplier],
+ ["Purchase Order", "transaction_date", "<=", filters.to_date],
+ ["Purchase Order", "transaction_date", ">=", filters.from_date],
+ ["Purchase Order", "docstatus", "=", 1]
+ ]
+ )
\ No newline at end of file
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
index c1fc6fb..2448e17 100644
--- 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
@@ -12,34 +12,80 @@
class TestSubcontractedItemToBeTransferred(unittest.TestCase):
def test_pending_and_transferred_qty(self):
- po = create_purchase_order(item_code='_Test FG Item', is_subcontracted='Yes')
+ po = create_purchase_order(item_code='_Test FG Item', is_subcontracted='Yes', supplier_warehouse="_Test Warehouse 1 - _TC")
+
+ # Material Receipt of RMs
make_stock_entry(item_code='_Test Item', target='_Test Warehouse - _TC', qty=100, basic_rate=100)
make_stock_entry(item_code='_Test Item Home Desktop 100', target='_Test Warehouse - _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])
+ se = transfer_subcontracted_raw_materials(po)
+ 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))
+ }
+ ))
+ po.reload()
+
+ po_data = [row for row in data if row.get('purchase_order') == po.name]
+ # Alphabetically sort to be certain of order
+ po_data = sorted(po_data, key = lambda i: i['rm_item_code'])
+
+ self.assertEqual(len(po_data), 2)
+ self.assertEqual(po_data[0]['purchase_order'], po.name)
+
+ self.assertEqual(po_data[0]['rm_item_code'], '_Test Item')
+ self.assertEqual(po_data[0]['p_qty'], 8)
+ self.assertEqual(po_data[0]['transferred_qty'], 2)
+
+ self.assertEqual(po_data[1]['rm_item_code'], '_Test Item Home Desktop 100')
+ self.assertEqual(po_data[1]['p_qty'], 19)
+ self.assertEqual(po_data[1]['transferred_qty'], 1)
+
+ se.cancel()
+ po.cancel()
def transfer_subcontracted_raw_materials(po):
+ # Order of supplied items fetched in PO is flaky
+ transfer_qty_map = {
+ '_Test Item': 2,
+ '_Test Item Home Desktop 100': 1
+ }
+
+ item_1 = po.supplied_items[0].rm_item_code
+ item_2 = po.supplied_items[1].rm_item_code
+
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'}]
+ {
+ 'name': po.supplied_items[0].name,
+ 'item_code': item_1,
+ 'rm_item_code': item_1,
+ 'item_name': item_1,
+ 'qty': transfer_qty_map[item_1],
+ 'warehouse': '_Test Warehouse - _TC',
+ 'rate': 100,
+ 'amount': 100 * transfer_qty_map[item_1],
+ 'stock_uom': 'Nos'
+ },
+ {
+ 'name': po.supplied_items[1].name,
+ 'item_code': item_2,
+ 'rm_item_code': item_2,
+ 'item_name': item_2,
+ 'qty': transfer_qty_map[item_2],
+ 'warehouse': '_Test Warehouse - _TC',
+ 'rate': 100,
+ 'amount': 100 * transfer_qty_map[item_2],
+ 'stock_uom': 'Nos'
+ }
+ ]
rm_item_string = json.dumps(rm_item)
- se = frappe.get_doc(make_rm_stock_entry(po, rm_item_string))
- se.from_warehouse = '_Test Warehouse 1 - _TC'
- se.to_warehouse = '_Test Warehouse 1 - _TC'
+ se = frappe.get_doc(make_rm_stock_entry(po.name, rm_item_string))
+ se.from_warehouse = '_Test Warehouse - _TC'
+ se.to_warehouse = '_Test Warehouse - _TC'
se.stock_entry_type = 'Send to Subcontractor'
se.save()
se.submit()
+ return se