fix: skip job card

This commit is contained in:
Rohit Waghchaure 2021-01-05 15:55:09 +05:30
parent 6e81489095
commit fcab53b238
14 changed files with 132 additions and 129 deletions

View File

@ -11,6 +11,7 @@
"workstation", "workstation",
"description", "description",
"col_break1", "col_break1",
"skip_job_card",
"hour_rate", "hour_rate",
"time_in_mins", "time_in_mins",
"operating_cost", "operating_cost",
@ -117,13 +118,20 @@
"fieldname": "sequence_id", "fieldname": "sequence_id",
"fieldtype": "Int", "fieldtype": "Int",
"label": "Sequence ID" "label": "Sequence ID"
},
{
"allow_on_submit": 1,
"default": "0",
"fieldname": "skip_job_card",
"fieldtype": "Check",
"label": "Skip Job Card"
} }
], ],
"idx": 1, "idx": 1,
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2020-12-14 15:01:33.142869", "modified": "2021-01-05 14:29:11.887888",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Manufacturing", "module": "Manufacturing",
"name": "BOM Operation", "name": "BOM Operation",

View File

@ -242,13 +242,15 @@ frappe.ui.form.on("Work Order", {
if(data.completed_qty != frm.doc.qty) { if(data.completed_qty != frm.doc.qty) {
pending_qty = frm.doc.qty - flt(data.completed_qty); pending_qty = frm.doc.qty - flt(data.completed_qty);
dialog.fields_dict.operations.df.data.push({ if (pending_qty && !data.skip_job_card) {
'name': data.name, dialog.fields_dict.operations.df.data.push({
'operation': data.operation, 'name': data.name,
'workstation': data.workstation, 'operation': data.operation,
'qty': pending_qty, 'workstation': data.workstation,
'pending_qty': pending_qty, 'qty': pending_qty,
}); 'pending_qty': pending_qty,
});
}
} }
}); });
dialog.fields_dict.operations.grid.refresh(); dialog.fields_dict.operations.grid.refresh();

View File

@ -27,7 +27,6 @@
"column_break_17", "column_break_17",
"serial_no", "serial_no",
"batch_size", "batch_size",
"batches",
"settings_section", "settings_section",
"allow_alternative_item", "allow_alternative_item",
"use_multi_level_bom", "use_multi_level_bom",
@ -535,14 +534,6 @@
"fieldname": "batch_size", "fieldname": "batch_size",
"fieldtype": "Float", "fieldtype": "Float",
"label": "Batch Size" "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", "icon": "fa fa-cogs",

View File

@ -27,6 +27,7 @@ class CapacityError(frappe.ValidationError): pass
class StockOverProductionError(frappe.ValidationError): pass class StockOverProductionError(frappe.ValidationError): pass
class OperationTooLongError(frappe.ValidationError): pass class OperationTooLongError(frappe.ValidationError): pass
class ItemHasVariantError(frappe.ValidationError): pass class ItemHasVariantError(frappe.ValidationError): pass
class SerialNoQtyError(frappe.ValidationError): pass
from six import string_types from six import string_types
@ -42,7 +43,6 @@ class WorkOrder(Document):
self.set_onload("overproduction_percentage", ms.overproduction_percentage_for_work_order) self.set_onload("overproduction_percentage", ms.overproduction_percentage_for_work_order)
def validate(self): def validate(self):
self.set("batches", [])
self.validate_production_item() self.validate_production_item()
if self.bom_no: if self.bom_no:
validate_bom_no(self.production_item, self.bom_no) validate_bom_no(self.production_item, self.bom_no)
@ -281,10 +281,12 @@ class WorkOrder(Document):
"make_serial_no_batch_from_work_order")): return "make_serial_no_batch_from_work_order")): return
if self.has_batch_no: if self.has_batch_no:
self.set("batches", [])
self.create_batch_for_finished_good() 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: if self.has_serial_no:
self.make_serial_nos(args) self.make_serial_nos(args)
@ -305,29 +307,29 @@ class WorkOrder(Document):
qty = total_qty qty = total_qty
total_qty = 0 total_qty = 0
batch = make_batch(self.production_item) make_batch(frappe._dict({
self.append("batches", { "item": self.production_item,
"batch_no": batch, "qty_to_produce": qty,
"qty": qty, "reference_doctype": self.doctype,
}) "reference_name": self.name
}))
def delete_auto_created_batch_and_serial_no(self): def delete_auto_created_batch_and_serial_no(self):
if self.serial_no: for row in frappe.get_all("Serial No", filters = {"work_order": self.name}):
for d in get_serial_nos(self.serial_no): frappe.delete_doc("Serial No", row.name)
frappe.delete_doc("Serial No", d) self.db_set("serial_no", "")
for row in self.batches: for row in frappe.get_all("Batch", filters = {"reference_name": self.name}):
batch_no = row.batch_no frappe.delete_doc("Batch", row.name)
row.db_set("batch_no", None)
frappe.delete_doc("Batch", batch_no)
def make_serial_nos(self, args): def make_serial_nos(self, args):
serial_no_series = frappe.get_cached_value("Item", self.production_item, "serial_no_series") serial_no_series = frappe.get_cached_value("Item", self.production_item, "serial_no_series")
if serial_no_series: if serial_no_series:
self.serial_no = get_auto_serial_nos(serial_no_series, self.qty) 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}) if self.serial_no:
self.serial_no = auto_make_serial_nos(args) 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)) serial_nos_length = len(get_serial_nos(self.serial_no))
if serial_nos_length != self.qty: if serial_nos_length != self.qty:
@ -341,6 +343,7 @@ class WorkOrder(Document):
plan_days = cint(manufacturing_settings_doc.capacity_planning_for_days) or 30 plan_days = cint(manufacturing_settings_doc.capacity_planning_for_days) or 30
for index, row in enumerate(self.operations): for index, row in enumerate(self.operations):
if row.skip_job_card: continue
qty = self.qty qty = self.qty
i=0 i=0
while qty > 0: while qty > 0:
@ -493,7 +496,7 @@ class WorkOrder(Document):
select select
operation, description, workstation, idx, operation, description, workstation, idx,
base_hour_rate as hour_rate, time_in_mins, 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 from
`tabBOM Operation` `tabBOM Operation`
where where
@ -755,14 +758,16 @@ class WorkOrder(Document):
bom.set_bom_material_details() bom.set_bom_material_details()
return bom return bom
def update_batch_qty(self): def update_batch_produced_qty(self, stock_entry_doc):
if self.has_batch_no and self.batches: if not cint(frappe.db.get_single_value("Manufacturing Settings",
for row in self.batches: "make_serial_no_batch_from_work_order")): return
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)
if qty: for row in stock_entry_doc.items:
frappe.db.set_value("Work Order Batch", row.name, "produced_qty", flt(qty[0][0])) 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.whitelist()
@frappe.validate_and_sanitize_search_inputs @frappe.validate_and_sanitize_search_inputs

View File

@ -4,10 +4,17 @@ from frappe import _
def get_data(): def get_data():
return { return {
'fieldname': 'work_order', 'fieldname': 'work_order',
'non_standard_fieldnames': {
'Batch': 'reference_name'
},
'transactions': [ 'transactions': [
{ {
'label': _('Transactions'), 'label': _('Transactions'),
'items': ['Stock Entry', 'Job Card', 'Pick List'] 'items': ['Stock Entry', 'Job Card', 'Pick List']
},
{
'label': _('Reference'),
'items': ['Serial No', 'Batch']
} }
] ]
} }

View File

@ -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
}

View File

@ -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

View File

@ -8,8 +8,10 @@
"details", "details",
"operation", "operation",
"bom", "bom",
"sequence_id", "column_break_4",
"skip_job_card",
"description", "description",
"sequence_id",
"col_break1", "col_break1",
"completed_qty", "completed_qty",
"status", "status",
@ -195,12 +197,23 @@
"label": "Sequence ID", "label": "Sequence ID",
"print_hide": 1, "print_hide": 1,
"read_only": 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, "index_web_pages_for_search": 1,
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2020-10-14 12:58:49.241252", "modified": "2021-01-08 17:42:05.372163",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Manufacturing", "module": "Manufacturing",
"name": "Work Order Operation", "name": "Work Order Operation",

View File

@ -1,4 +1,5 @@
{ {
"actions": [],
"allow_import": 1, "allow_import": 1,
"autoname": "field:batch_id", "autoname": "field:batch_id",
"creation": "2013-03-05 14:50:38", "creation": "2013-03-05 14:50:38",
@ -25,7 +26,11 @@
"reference_doctype", "reference_doctype",
"reference_name", "reference_name",
"section_break_7", "section_break_7",
"description" "description",
"manufacturing_section",
"qty_to_produce",
"column_break_23",
"produced_qty"
], ],
"fields": [ "fields": [
{ {
@ -160,13 +165,35 @@
"label": "Batch UOM", "label": "Batch UOM",
"options": "UOM", "options": "UOM",
"read_only": 1 "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", "icon": "fa fa-archive",
"idx": 1, "idx": 1,
"image_field": "image", "image_field": "image",
"links": [],
"max_attachments": 5, "max_attachments": 5,
"modified": "2020-09-18 17:26:09.703215", "modified": "2021-01-07 11:10:09.149170",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Batch", "name": "Batch",

View File

@ -310,9 +310,7 @@ def validate_serial_no_with_batch(serial_nos, item_code):
frappe.throw(_("There is no batch found against the {0}: {1}") frappe.throw(_("There is no batch found against the {0}: {1}")
.format(message, serial_no_link)) .format(message, serial_no_link))
def make_batch(item_code): def make_batch(args):
if frappe.db.get_value("Item", item_code, "has_batch_no"): if frappe.db.get_value("Item", args.item, "has_batch_no"):
doc = frappe.new_doc("Batch") args.doctype = "Batch"
doc.item = item_code frappe.get_doc(args).insert().name
doc.save()
return doc.name

View File

@ -57,7 +57,8 @@
"more_info", "more_info",
"serial_no_details", "serial_no_details",
"company", "company",
"status" "status",
"work_order"
], ],
"fields": [ "fields": [
{ {
@ -422,12 +423,18 @@
"label": "Status", "label": "Status",
"options": "\nActive\nInactive\nDelivered\nExpired", "options": "\nActive\nInactive\nDelivered\nExpired",
"read_only": 1 "read_only": 1
},
{
"fieldname": "work_order",
"fieldtype": "Link",
"label": "Work Order",
"options": "Work Order"
} }
], ],
"icon": "fa fa-barcode", "icon": "fa fa-barcode",
"idx": 1, "idx": 1,
"links": [], "links": [],
"modified": "2020-07-20 20:50:16.660433", "modified": "2021-01-08 14:31:15.375996",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Serial No", "name": "Serial No",

View File

@ -473,16 +473,13 @@ def get_serial_nos(serial_no):
if s.strip()] if s.strip()]
def update_args_for_serial_no(serial_no_doc, serial_no, args, is_new=False): def update_args_for_serial_no(serial_no_doc, serial_no, args, is_new=False):
serial_no_doc.update({ for field in ["item_code", "work_order", "company", "batch_no", "supplier", "location"]:
"item_code": args.get("item_code"), if args.get(field):
"company": args.get("company"), serial_no_doc.set(field, args.get(field))
"batch_no": args.get("batch_no"),
"via_stock_ledger": args.get("via_stock_ledger") or True, serial_no_doc.via_stock_ledger = args.get("via_stock_ledger") or True
"supplier": args.get("supplier"), serial_no_doc.warehouse = (args.get("warehouse")
"location": args.get("location"), if args.get("actual_qty", 0) > 0 else None)
"warehouse": (args.get("warehouse")
if args.get("actual_qty", 0) > 0 else None)
})
if is_new: if is_new:
serial_no_doc.serial_no = serial_no serial_no_doc.serial_no = serial_no

View File

@ -855,7 +855,7 @@ class StockEntry(StockController):
pro_doc.run_method("update_work_order_qty") pro_doc.run_method("update_work_order_qty")
if self.purpose == "Manufacture": if self.purpose == "Manufacture":
pro_doc.run_method("update_planned_qty") pro_doc.run_method("update_planned_qty")
pro_doc.update_batch_qty() pro_doc.update_batch_produced_qty(self)
if not pro_doc.operations: if not pro_doc.operations:
pro_doc.set_actual_dates() pro_doc.set_actual_dates()
@ -1090,14 +1090,21 @@ class StockEntry(StockController):
"is_finished_item": 1 "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) self.set_batchwise_finished_goods(args, item)
else: else:
self.add_finisged_goods(args, item) self.add_finisged_goods(args, item)
def set_batchwise_finished_goods(self, args, item): def set_batchwise_finished_goods(self, args, item):
qty = flt(self.fg_completed_qty) 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) batch_qty = flt(row.qty) - flt(row.produced_qty)
if not batch_qty: continue if not batch_qty: continue
@ -1110,7 +1117,7 @@ class StockEntry(StockController):
qty -= batch_qty qty -= batch_qty
args["qty"] = fg_qty args["qty"] = fg_qty
args["batch_no"] = row.batch_no args["batch_no"] = row.name
self.add_finisged_goods(args, item) self.add_finisged_goods(args, item)
@ -1555,7 +1562,7 @@ class StockEntry(StockController):
def set_serial_no_batch_for_finished_good(self): def set_serial_no_batch_for_finished_good(self):
args = {} 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) self.get_serial_nos_for_fg(args)
for row in self.items: for row in self.items: