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: