fix: skip job card
diff --git a/erpnext/manufacturing/doctype/bom_operation/bom_operation.json b/erpnext/manufacturing/doctype/bom_operation/bom_operation.json
index 57062b8..1330636 100644
--- a/erpnext/manufacturing/doctype/bom_operation/bom_operation.json
+++ b/erpnext/manufacturing/doctype/bom_operation/bom_operation.json
@@ -11,6 +11,7 @@
   "workstation",
   "description",
   "col_break1",
+  "skip_job_card",
   "hour_rate",
   "time_in_mins",
   "operating_cost",
@@ -117,13 +118,20 @@
    "fieldname": "sequence_id",
    "fieldtype": "Int",
    "label": "Sequence ID"
+  },
+  {
+   "allow_on_submit": 1,
+   "default": "0",
+   "fieldname": "skip_job_card",
+   "fieldtype": "Check",
+   "label": "Skip Job Card"
   }
  ],
  "idx": 1,
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2020-12-14 15:01:33.142869",
+ "modified": "2021-01-05 14:29:11.887888",
  "modified_by": "Administrator",
  "module": "Manufacturing",
  "name": "BOM Operation",
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.js b/erpnext/manufacturing/doctype/work_order/work_order.js
index 6017349..adf6453 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.js
+++ b/erpnext/manufacturing/doctype/work_order/work_order.js
@@ -242,13 +242,15 @@
 			if(data.completed_qty != frm.doc.qty) {
 				pending_qty = frm.doc.qty - flt(data.completed_qty);
 
-				dialog.fields_dict.operations.df.data.push({
-					'name': data.name,
-					'operation': data.operation,
-					'workstation': data.workstation,
-					'qty': pending_qty,
-					'pending_qty': pending_qty,
-				});
+				if (pending_qty && !data.skip_job_card) {
+					dialog.fields_dict.operations.df.data.push({
+						'name': data.name,
+						'operation': data.operation,
+						'workstation': data.workstation,
+						'qty': pending_qty,
+						'pending_qty': pending_qty,
+					});
+				}
 			}
 		});
 		dialog.fields_dict.operations.grid.refresh();
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.json b/erpnext/manufacturing/doctype/work_order/work_order.json
index cb3c942..c80decb 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.json
+++ b/erpnext/manufacturing/doctype/work_order/work_order.json
@@ -27,7 +27,6 @@
   "column_break_17",
   "serial_no",
   "batch_size",
-  "batches",
   "settings_section",
   "allow_alternative_item",
   "use_multi_level_bom",
@@ -535,14 +534,6 @@
    "fieldname": "batch_size",
    "fieldtype": "Float",
    "label": "Batch Size"
-  },
-  {
-   "depends_on": "has_batch_no",
-   "fieldname": "batches",
-   "fieldtype": "Table",
-   "label": "Batches",
-   "options": "Work Order Batch",
-   "read_only": 1
   }
  ],
  "icon": "fa fa-cogs",
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index 587204c..23cc090 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -27,6 +27,7 @@
 class StockOverProductionError(frappe.ValidationError): pass
 class OperationTooLongError(frappe.ValidationError): pass
 class ItemHasVariantError(frappe.ValidationError): pass
+class SerialNoQtyError(frappe.ValidationError): pass
 
 from six import string_types
 
@@ -42,7 +43,6 @@
 		self.set_onload("overproduction_percentage", ms.overproduction_percentage_for_work_order)
 
 	def validate(self):
-		self.set("batches", [])
 		self.validate_production_item()
 		if self.bom_no:
 			validate_bom_no(self.production_item, self.bom_no)
@@ -281,10 +281,12 @@
 			"make_serial_no_batch_from_work_order")): return
 
 		if self.has_batch_no:
-			self.set("batches", [])
 			self.create_batch_for_finished_good()
 
-		args = {"item_code": self.production_item}
+		args = {
+			"item_code": self.production_item,
+			"work_order": self.name
+		}
 
 		if self.has_serial_no:
 			self.make_serial_nos(args)
@@ -305,29 +307,29 @@
 				qty = total_qty
 				total_qty = 0
 
-			batch = make_batch(self.production_item)
-			self.append("batches", {
-				"batch_no": batch,
-				"qty": qty,
-			})
+			make_batch(frappe._dict({
+				"item": self.production_item,
+				"qty_to_produce": qty,
+				"reference_doctype": self.doctype,
+				"reference_name": self.name
+			}))
 
 	def delete_auto_created_batch_and_serial_no(self):
-		if self.serial_no:
-			for d in get_serial_nos(self.serial_no):
-				frappe.delete_doc("Serial No", d)
+		for row in frappe.get_all("Serial No", filters = {"work_order": self.name}):
+			frappe.delete_doc("Serial No", row.name)
+			self.db_set("serial_no", "")
 
-		for row in self.batches:
-			batch_no = row.batch_no
-			row.db_set("batch_no", None)
-			frappe.delete_doc("Batch", batch_no)
+		for row in frappe.get_all("Batch", filters = {"reference_name": self.name}):
+			frappe.delete_doc("Batch", row.name)
 
 	def make_serial_nos(self, args):
 		serial_no_series = frappe.get_cached_value("Item", self.production_item, "serial_no_series")
 		if serial_no_series:
 			self.serial_no = get_auto_serial_nos(serial_no_series, self.qty)
-		elif self.serial_no:
-			args.update({"serial_no": self.serial_no, "actual_qty": self.qty, "batch_no": self.batch_no})
-			self.serial_no = auto_make_serial_nos(args)
+
+		if self.serial_no:
+			args.update({"serial_no": self.serial_no, "actual_qty": self.qty})
+			auto_make_serial_nos(args)
 
 		serial_nos_length = len(get_serial_nos(self.serial_no))
 		if serial_nos_length != self.qty:
@@ -341,6 +343,7 @@
 		plan_days = cint(manufacturing_settings_doc.capacity_planning_for_days) or 30
 
 		for index, row in enumerate(self.operations):
+			if row.skip_job_card: continue
 			qty = self.qty
 			i=0
 			while qty > 0:
@@ -493,7 +496,7 @@
 			select
 				operation, description, workstation, idx,
 				base_hour_rate as hour_rate, time_in_mins,
-				"Pending" as status, parent as bom, batch_size, sequence_id
+				"Pending" as status, parent as bom, batch_size, sequence_id, skip_job_card
 			from
 				`tabBOM Operation`
 			where
@@ -755,14 +758,16 @@
 		bom.set_bom_material_details()
 		return bom
 
-	def update_batch_qty(self):
-		if self.has_batch_no and self.batches:
-			for row in self.batches:
-				qty = frappe.get_all("Stock Entry Detail", fields = ["sum(transfer_qty)"],
-					filters = {"docstatus": 1, "batch_no": row.batch_no, "is_finished_item": 1}, as_list=1)
+	def update_batch_produced_qty(self, stock_entry_doc):
+		if not cint(frappe.db.get_single_value("Manufacturing Settings",
+			"make_serial_no_batch_from_work_order")): return
 
-				if qty:
-					frappe.db.set_value("Work Order Batch", row.name, "produced_qty", flt(qty[0][0]))
+		for row in stock_entry_doc.items:
+			if row.batch_no and (row.is_finished_item or row.is_scrap_item):
+				qty = frappe.get_all("Stock Entry Detail", filters = {"batch_no": row.batch_no},
+					or_conditions= {"is_finished_item": 1, "is_scrap_item": 1}, fields = ["sum(qty)"])[0][0]
+
+				frappe.db.set_value("Batch", row.batch_no, "produced_qty", qty)
 
 @frappe.whitelist()
 @frappe.validate_and_sanitize_search_inputs
diff --git a/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py b/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py
index 87c090f..9aa0715 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py
@@ -4,10 +4,17 @@
 def get_data():
 	return {
 		'fieldname': 'work_order',
+		'non_standard_fieldnames': {
+			'Batch': 'reference_name'
+		},
 		'transactions': [
 			{
 				'label': _('Transactions'),
 				'items': ['Stock Entry', 'Job Card', 'Pick List']
+			},
+			{
+				'label': _('Reference'),
+				'items': ['Serial No', 'Batch']
 			}
 		]
 	}
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/work_order_batch/__init__.py b/erpnext/manufacturing/doctype/work_order_batch/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/manufacturing/doctype/work_order_batch/__init__.py
+++ /dev/null
diff --git a/erpnext/manufacturing/doctype/work_order_batch/work_order_batch.json b/erpnext/manufacturing/doctype/work_order_batch/work_order_batch.json
deleted file mode 100644
index ad667b7..0000000
--- a/erpnext/manufacturing/doctype/work_order_batch/work_order_batch.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
- "actions": [],
- "creation": "2021-01-04 16:42:39.347528",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
-  "batch_no",
-  "qty",
-  "produced_qty"
- ],
- "fields": [
-  {
-   "fieldname": "batch_no",
-   "fieldtype": "Link",
-   "in_list_view": 1,
-   "label": "Batch No",
-   "options": "Batch"
-  },
-  {
-   "fieldname": "qty",
-   "fieldtype": "Float",
-   "in_list_view": 1,
-   "label": "Qty",
-   "non_negative": 1
-  },
-  {
-   "default": "0",
-   "fieldname": "produced_qty",
-   "fieldtype": "Float",
-   "label": "Produced Qty",
-   "no_copy": 1,
-   "print_hide": 1
-  }
- ],
- "index_web_pages_for_search": 1,
- "istable": 1,
- "links": [],
- "modified": "2021-01-05 10:57:07.278399",
- "modified_by": "Administrator",
- "module": "Manufacturing",
- "name": "Work Order Batch",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/work_order_batch/work_order_batch.py b/erpnext/manufacturing/doctype/work_order_batch/work_order_batch.py
deleted file mode 100644
index cf3ec47..0000000
--- a/erpnext/manufacturing/doctype/work_order_batch/work_order_batch.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-# import frappe
-from frappe.model.document import Document
-
-class WorkOrderBatch(Document):
-	pass
diff --git a/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.json b/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.json
index 8c5cde9..b776909 100644
--- a/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.json
+++ b/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.json
@@ -8,8 +8,10 @@
   "details",
   "operation",
   "bom",
-  "sequence_id",
+  "column_break_4",
+  "skip_job_card",
   "description",
+  "sequence_id",
   "col_break1",
   "completed_qty",
   "status",
@@ -195,12 +197,23 @@
    "label": "Sequence ID",
    "print_hide": 1,
    "read_only": 1
+  },
+  {
+   "fieldname": "column_break_4",
+   "fieldtype": "Column Break"
+  },
+  {
+   "allow_on_submit": 1,
+   "default": "0",
+   "fieldname": "skip_job_card",
+   "fieldtype": "Check",
+   "label": "Skip Job Card"
   }
  ],
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2020-10-14 12:58:49.241252",
+ "modified": "2021-01-08 17:42:05.372163",
  "modified_by": "Administrator",
  "module": "Manufacturing",
  "name": "Work Order Operation",
diff --git a/erpnext/stock/doctype/batch/batch.json b/erpnext/stock/doctype/batch/batch.json
index 943cb34..e6d2e13 100644
--- a/erpnext/stock/doctype/batch/batch.json
+++ b/erpnext/stock/doctype/batch/batch.json
@@ -1,4 +1,5 @@
 {
+ "actions": [],
  "allow_import": 1,
  "autoname": "field:batch_id",
  "creation": "2013-03-05 14:50:38",
@@ -25,7 +26,11 @@
   "reference_doctype",
   "reference_name",
   "section_break_7",
-  "description"
+  "description",
+  "manufacturing_section",
+  "qty_to_produce",
+  "column_break_23",
+  "produced_qty"
  ],
  "fields": [
   {
@@ -160,13 +165,35 @@
    "label": "Batch UOM",
    "options": "UOM",
    "read_only": 1
+  },
+  {
+   "fieldname": "manufacturing_section",
+   "fieldtype": "Section Break",
+   "label": "Manufacturing"
+  },
+  {
+   "fieldname": "qty_to_produce",
+   "fieldtype": "Float",
+   "label": "Qty To Produce",
+   "read_only": 1
+  },
+  {
+   "fieldname": "column_break_23",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "produced_qty",
+   "fieldtype": "Float",
+   "label": "Produced Qty",
+   "read_only": 1
   }
  ],
  "icon": "fa fa-archive",
  "idx": 1,
  "image_field": "image",
+ "links": [],
  "max_attachments": 5,
- "modified": "2020-09-18 17:26:09.703215",
+ "modified": "2021-01-07 11:10:09.149170",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Batch",
diff --git a/erpnext/stock/doctype/batch/batch.py b/erpnext/stock/doctype/batch/batch.py
index 07cf08a..bb5ad5c 100644
--- a/erpnext/stock/doctype/batch/batch.py
+++ b/erpnext/stock/doctype/batch/batch.py
@@ -310,9 +310,7 @@
 	frappe.throw(_("There is no batch found against the {0}: {1}")
 		.format(message, serial_no_link))
 
-def make_batch(item_code):
-	if frappe.db.get_value("Item", item_code, "has_batch_no"):
-		doc = frappe.new_doc("Batch")
-		doc.item = item_code
-		doc.save()
-		return doc.name
\ No newline at end of file
+def make_batch(args):
+	if frappe.db.get_value("Item", args.item, "has_batch_no"):
+		args.doctype = "Batch"
+		frappe.get_doc(args).insert().name
\ No newline at end of file
diff --git a/erpnext/stock/doctype/serial_no/serial_no.json b/erpnext/stock/doctype/serial_no/serial_no.json
index 3acf3a9..a3d44af 100644
--- a/erpnext/stock/doctype/serial_no/serial_no.json
+++ b/erpnext/stock/doctype/serial_no/serial_no.json
@@ -57,7 +57,8 @@
   "more_info",
   "serial_no_details",
   "company",
-  "status"
+  "status",
+  "work_order"
  ],
  "fields": [
   {
@@ -422,12 +423,18 @@
    "label": "Status",
    "options": "\nActive\nInactive\nDelivered\nExpired",
    "read_only": 1
+  },
+  {
+   "fieldname": "work_order",
+   "fieldtype": "Link",
+   "label": "Work Order",
+   "options": "Work Order"
   }
  ],
  "icon": "fa fa-barcode",
  "idx": 1,
  "links": [],
- "modified": "2020-07-20 20:50:16.660433",
+ "modified": "2021-01-08 14:31:15.375996",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Serial No",
diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py
index b236f6a..bad7b60 100644
--- a/erpnext/stock/doctype/serial_no/serial_no.py
+++ b/erpnext/stock/doctype/serial_no/serial_no.py
@@ -473,16 +473,13 @@
 		if s.strip()]
 
 def update_args_for_serial_no(serial_no_doc, serial_no, args, is_new=False):
-	serial_no_doc.update({
-		"item_code": args.get("item_code"),
-		"company": args.get("company"),
-		"batch_no": args.get("batch_no"),
-		"via_stock_ledger": args.get("via_stock_ledger") or True,
-		"supplier": args.get("supplier"),
-		"location": args.get("location"),
-		"warehouse": (args.get("warehouse")
-			if args.get("actual_qty", 0) > 0 else None)
-	})
+	for field in ["item_code", "work_order", "company", "batch_no", "supplier", "location"]:
+		if args.get(field):
+			serial_no_doc.set(field, args.get(field))
+
+	serial_no_doc.via_stock_ledger = args.get("via_stock_ledger") or True
+	serial_no_doc.warehouse = (args.get("warehouse")
+		if args.get("actual_qty", 0) > 0 else None)
 
 	if is_new:
 		serial_no_doc.serial_no = serial_no
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 5fde35a..83412c6 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -855,7 +855,7 @@
 				pro_doc.run_method("update_work_order_qty")
 				if self.purpose == "Manufacture":
 					pro_doc.run_method("update_planned_qty")
-					pro_doc.update_batch_qty()
+					pro_doc.update_batch_produced_qty(self)
 
 			if not pro_doc.operations:
 				pro_doc.set_actual_dates()
@@ -1090,14 +1090,21 @@
 			"is_finished_item": 1
 		}
 
-		if self.work_order and self.pro_doc.batches:
+		if self.work_order and self.pro_doc.has_batch_no:
 			self.set_batchwise_finished_goods(args, item)
 		else:
 			self.add_finisged_goods(args, item)
 
 	def set_batchwise_finished_goods(self, args, item):
 		qty = flt(self.fg_completed_qty)
-		for row in self.pro_doc.batches:
+		filters = {"reference_name": self.pro_doc.name,
+			"reference_doctype": self.pro_doc.doctype,
+			"qty_to_produce": (">", 0)
+		}
+
+		fields = ["qty_to_produce as qty", "produced_qty", "name"]
+
+		for row in frappe.get_all("Batch", filters = filters, fields = fields):
 			batch_qty = flt(row.qty) - flt(row.produced_qty)
 			if not batch_qty: continue
 
@@ -1110,7 +1117,7 @@
 
 			qty -= batch_qty
 			args["qty"] = fg_qty
-			args["batch_no"] = row.batch_no
+			args["batch_no"] = row.name
 
 			self.add_finisged_goods(args, item)
 
@@ -1555,7 +1562,7 @@
 
 	def set_serial_no_batch_for_finished_good(self):
 		args = {}
-		if self.pro_doc.serial_no or self.pro_doc.batch_no:
+		if self.pro_doc.serial_no:
 			self.get_serial_nos_for_fg(args)
 
 		for row in self.items: