Merge pull request #24063 from rohitwaghchaure/fixed-job-card-cacncel-flow-develop
fix: don't cancel job card if manufacturing entry has made
This commit is contained in:
commit
b9352b729a
@ -17,6 +17,7 @@ class OverlapError(frappe.ValidationError): pass
|
|||||||
|
|
||||||
class OperationMismatchError(frappe.ValidationError): pass
|
class OperationMismatchError(frappe.ValidationError): pass
|
||||||
class OperationSequenceError(frappe.ValidationError): pass
|
class OperationSequenceError(frappe.ValidationError): pass
|
||||||
|
class JobCardCancelError(frappe.ValidationError): pass
|
||||||
|
|
||||||
class JobCard(Document):
|
class JobCard(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
@ -217,33 +218,49 @@ class JobCard(Document):
|
|||||||
field = "operation_id"
|
field = "operation_id"
|
||||||
data = self.get_current_operation_data()
|
data = self.get_current_operation_data()
|
||||||
if data and len(data) > 0:
|
if data and len(data) > 0:
|
||||||
for_quantity = data[0].completed_qty
|
for_quantity = flt(data[0].completed_qty)
|
||||||
time_in_mins = data[0].time_in_mins
|
time_in_mins = flt(data[0].time_in_mins)
|
||||||
|
|
||||||
if self.get(field):
|
wo = frappe.get_doc('Work Order', self.work_order)
|
||||||
time_data = frappe.db.sql("""
|
if self.operation_id:
|
||||||
|
self.validate_produced_quantity(for_quantity, wo)
|
||||||
|
self.update_work_order_data(for_quantity, time_in_mins, wo)
|
||||||
|
|
||||||
|
def validate_produced_quantity(self, for_quantity, wo):
|
||||||
|
if self.docstatus < 2: return
|
||||||
|
|
||||||
|
if wo.produced_qty > for_quantity:
|
||||||
|
first_part_msg = (_("The {0} {1} is used to calculate the valuation cost for the finished good {2}.")
|
||||||
|
.format(frappe.bold(_("Job Card")), frappe.bold(self.name), frappe.bold(self.production_item)))
|
||||||
|
|
||||||
|
second_part_msg = (_("Kindly cancel the Manufacturing Entries first against the work order {0}.")
|
||||||
|
.format(frappe.bold(get_link_to_form("Work Order", self.work_order))))
|
||||||
|
|
||||||
|
frappe.throw(_("{0} {1}").format(first_part_msg, second_part_msg),
|
||||||
|
JobCardCancelError, title = _("Error"))
|
||||||
|
|
||||||
|
def update_work_order_data(self, for_quantity, time_in_mins, wo):
|
||||||
|
time_data = frappe.db.sql("""
|
||||||
SELECT
|
SELECT
|
||||||
min(from_time) as start_time, max(to_time) as end_time
|
min(from_time) as start_time, max(to_time) as end_time
|
||||||
FROM `tabJob Card` jc, `tabJob Card Time Log` jctl
|
FROM `tabJob Card` jc, `tabJob Card Time Log` jctl
|
||||||
WHERE
|
WHERE
|
||||||
jctl.parent = jc.name and jc.work_order = %s
|
jctl.parent = jc.name and jc.work_order = %s
|
||||||
and jc.{0} = %s and jc.docstatus = 1
|
and jc.operation_id = %s and jc.docstatus = 1
|
||||||
""".format(field), (self.work_order, self.get(field)), as_dict=1)
|
""", (self.work_order, self.operation_id), as_dict=1)
|
||||||
|
|
||||||
wo = frappe.get_doc('Work Order', self.work_order)
|
for data in wo.operations:
|
||||||
|
if data.get("name") == self.operation_id:
|
||||||
|
data.completed_qty = for_quantity
|
||||||
|
data.actual_operation_time = time_in_mins
|
||||||
|
data.actual_start_time = time_data[0].start_time if time_data else None
|
||||||
|
data.actual_end_time = time_data[0].end_time if time_data else None
|
||||||
|
|
||||||
for data in wo.operations:
|
wo.flags.ignore_validate_update_after_submit = True
|
||||||
if data.get("name") == self.get(field):
|
wo.update_operation_status()
|
||||||
data.completed_qty = for_quantity
|
wo.calculate_operating_cost()
|
||||||
data.actual_operation_time = time_in_mins
|
wo.set_actual_dates()
|
||||||
data.actual_start_time = time_data[0].start_time if time_data else None
|
wo.save()
|
||||||
data.actual_end_time = time_data[0].end_time if time_data else None
|
|
||||||
|
|
||||||
wo.flags.ignore_validate_update_after_submit = True
|
|
||||||
wo.update_operation_status()
|
|
||||||
wo.calculate_operating_cost()
|
|
||||||
wo.set_actual_dates()
|
|
||||||
wo.save()
|
|
||||||
|
|
||||||
def get_current_operation_data(self):
|
def get_current_operation_data(self):
|
||||||
return frappe.get_all('Job Card',
|
return frappe.get_all('Job Card',
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import unittest
|
import unittest
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.utils import flt, time_diff_in_hours, now, add_months, cint, today
|
from frappe.utils import flt, now, add_months, cint, today, add_to_date
|
||||||
from erpnext.manufacturing.doctype.work_order.work_order import (make_stock_entry,
|
from erpnext.manufacturing.doctype.work_order.work_order import (make_stock_entry,
|
||||||
ItemHasVariantError, stop_unstop, StockOverProductionError, OverProductionError, CapacityError)
|
ItemHasVariantError, stop_unstop, StockOverProductionError, OverProductionError, CapacityError)
|
||||||
from erpnext.stock.doctype.stock_entry import test_stock_entry
|
from erpnext.stock.doctype.stock_entry import test_stock_entry
|
||||||
@ -14,6 +14,7 @@ from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_orde
|
|||||||
from erpnext.stock.doctype.item.test_item import make_item
|
from erpnext.stock.doctype.item.test_item import make_item
|
||||||
from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
|
from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
|
||||||
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
|
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
|
||||||
|
from erpnext.manufacturing.doctype.job_card.job_card import JobCardCancelError
|
||||||
|
|
||||||
class TestWorkOrder(unittest.TestCase):
|
class TestWorkOrder(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -369,21 +370,49 @@ class TestWorkOrder(unittest.TestCase):
|
|||||||
self.assertEqual(ste.total_additional_costs, 1000)
|
self.assertEqual(ste.total_additional_costs, 1000)
|
||||||
|
|
||||||
def test_job_card(self):
|
def test_job_card(self):
|
||||||
|
stock_entries = []
|
||||||
data = frappe.get_cached_value('BOM',
|
data = frappe.get_cached_value('BOM',
|
||||||
{'docstatus': 1, 'with_operations': 1, 'company': '_Test Company'}, ['name', 'item'])
|
{'docstatus': 1, 'with_operations': 1, 'company': '_Test Company'}, ['name', 'item'])
|
||||||
|
|
||||||
if data:
|
bom, bom_item = data
|
||||||
frappe.db.set_value("Manufacturing Settings",
|
|
||||||
None, "disable_capacity_planning", 0)
|
|
||||||
|
|
||||||
bom, bom_item = data
|
bom_doc = frappe.get_doc('BOM', bom)
|
||||||
|
work_order = make_wo_order_test_record(item=bom_item, qty=1,
|
||||||
|
bom_no=bom, source_warehouse="_Test Warehouse - _TC")
|
||||||
|
|
||||||
bom_doc = frappe.get_doc('BOM', bom)
|
for row in work_order.required_items:
|
||||||
work_order = make_wo_order_test_record(item=bom_item, qty=1, bom_no=bom)
|
stock_entry_doc = test_stock_entry.make_stock_entry(item_code=row.item_code,
|
||||||
self.assertTrue(work_order.planned_end_date)
|
target="_Test Warehouse - _TC", qty=row.required_qty, basic_rate=100)
|
||||||
|
stock_entries.append(stock_entry_doc)
|
||||||
|
|
||||||
job_cards = frappe.get_all('Job Card', filters = {'work_order': work_order.name})
|
ste = frappe.get_doc(make_stock_entry(work_order.name, "Material Transfer for Manufacture", 1))
|
||||||
self.assertEqual(len(job_cards), len(bom_doc.operations))
|
ste.submit()
|
||||||
|
stock_entries.append(ste)
|
||||||
|
|
||||||
|
job_cards = frappe.get_all('Job Card', filters = {'work_order': work_order.name})
|
||||||
|
self.assertEqual(len(job_cards), len(bom_doc.operations))
|
||||||
|
|
||||||
|
for i, job_card in enumerate(job_cards):
|
||||||
|
doc = frappe.get_doc("Job Card", job_card)
|
||||||
|
doc.append("time_logs", {
|
||||||
|
"from_time": now(),
|
||||||
|
"hours": i,
|
||||||
|
"to_time": add_to_date(now(), i),
|
||||||
|
"completed_qty": doc.for_quantity
|
||||||
|
})
|
||||||
|
doc.submit()
|
||||||
|
|
||||||
|
ste1 = frappe.get_doc(make_stock_entry(work_order.name, "Manufacture", 1))
|
||||||
|
ste1.submit()
|
||||||
|
stock_entries.append(ste1)
|
||||||
|
|
||||||
|
for job_card in job_cards:
|
||||||
|
doc = frappe.get_doc("Job Card", job_card)
|
||||||
|
self.assertRaises(JobCardCancelError, doc.cancel)
|
||||||
|
|
||||||
|
stock_entries.reverse()
|
||||||
|
for stock_entry in stock_entries:
|
||||||
|
stock_entry.cancel()
|
||||||
|
|
||||||
def test_capcity_planning(self):
|
def test_capcity_planning(self):
|
||||||
frappe.db.set_value("Manufacturing Settings", None, {
|
frappe.db.set_value("Manufacturing Settings", None, {
|
||||||
@ -509,7 +538,6 @@ class TestWorkOrder(unittest.TestCase):
|
|||||||
ste1.submit()
|
ste1.submit()
|
||||||
ste_cancel_list.append(ste1)
|
ste_cancel_list.append(ste1)
|
||||||
|
|
||||||
print(wo_order.name)
|
|
||||||
ste3 = frappe.get_doc(make_stock_entry(wo_order.name, "Material Consumption for Manufacture", 2))
|
ste3 = frappe.get_doc(make_stock_entry(wo_order.name, "Material Consumption for Manufacture", 2))
|
||||||
self.assertEquals(ste3.fg_completed_qty, 2)
|
self.assertEquals(ste3.fg_completed_qty, 2)
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user