fix: Job Card excess transfer behaviour

- Block excess transfer of items if not allowed in settings
- Behaviour made consistent with js behaviour (button disappears if not pending and not allowed in settings)
- Test for same case
This commit is contained in:
marination 2022-05-17 17:39:45 +05:30
parent 28fe4f3d54
commit e07ce6efe0
3 changed files with 73 additions and 13 deletions

View File

@ -42,6 +42,10 @@ class JobCardCancelError(frappe.ValidationError):
pass
class JobCardOverTransferError(frappe.ValidationError):
pass
class JobCard(Document):
def onload(self):
excess_transfer = frappe.db.get_single_value(
@ -522,23 +526,50 @@ class JobCard(Document):
},
)
def set_transferred_qty_in_job_card(self, ste_doc):
def set_transferred_qty_in_job_card_item(self, ste_doc):
from frappe.query_builder.functions import Sum
def _validate_over_transfer(row, transferred_qty):
"Block over transfer of items if not allowed in settings."
allow_excess = frappe.db.get_single_value("Manufacturing Settings", "job_card_excess_transfer")
required_qty = frappe.db.get_value("Job Card Item", row.job_card_item, "required_qty")
is_excess = flt(transferred_qty) > flt(required_qty)
if is_excess and not allow_excess:
frappe.throw(
_(
"Row #{0}: Cannot transfer more than Required Qty {1} for Item {2} against Job Card {3}"
).format(
row.idx, frappe.bold(required_qty), frappe.bold(row.item_code), ste_doc.job_card
),
title=_("Excess Transfer"),
exc=JobCardOverTransferError,
)
for row in ste_doc.items:
if not row.job_card_item:
continue
qty = frappe.db.sql(
""" SELECT SUM(qty) from `tabStock Entry Detail` sed, `tabStock Entry` se
WHERE sed.job_card_item = %s and se.docstatus = 1 and sed.parent = se.name and
se.purpose = 'Material Transfer for Manufacture'
""",
(row.job_card_item),
)[0][0]
sed = frappe.qb.DocType("Stock Entry Detail")
se = frappe.qb.DocType("Stock Entry")
transferred_qty = (
frappe.qb.from_(sed)
.join(se)
.on(sed.parent == se.name)
.select(Sum(sed.qty))
.where(
(sed.job_card_item == row.job_card_item)
& (se.docstatus == 1)
& (se.purpose == "Material Transfer for Manufacture")
)
).run()[0][0]
frappe.db.set_value("Job Card Item", row.job_card_item, "transferred_qty", flt(qty))
_validate_over_transfer(row, transferred_qty)
frappe.db.set_value("Job Card Item", row.job_card_item, "transferred_qty", flt(transferred_qty))
def set_transferred_qty(self, update_status=False):
"Set total FG Qty for which RM was transferred."
"Set total FG Qty in Job Card for which RM was transferred."
if not self.items:
self.transferred_qty = self.for_quantity if self.docstatus == 1 else 0

View File

@ -2,10 +2,14 @@
# See license.txt
import frappe
from frappe.tests.utils import FrappeTestCase
from frappe.tests.utils import FrappeTestCase, change_settings
from frappe.utils import random_string
from erpnext.manufacturing.doctype.job_card.job_card import OperationMismatchError, OverlapError
from erpnext.manufacturing.doctype.job_card.job_card import (
JobCardOverTransferError,
OperationMismatchError,
OverlapError,
)
from erpnext.manufacturing.doctype.job_card.job_card import (
make_stock_entry as make_stock_entry_from_jc,
)
@ -25,6 +29,7 @@ class TestJobCard(FrappeTestCase):
"test_job_card_multiple_materials_transfer",
"test_job_card_excess_material_transfer",
"test_job_card_partial_material_transfer",
"test_job_card_excess_material_transfer_block",
)
if self._testMethodName in tests_that_skip_setup:
@ -165,6 +170,7 @@ class TestJobCard(FrappeTestCase):
# transfer was made for 2 fg qty in first transfer Stock Entry
self.assertEqual(transfer_entry_2.fg_completed_qty, 0)
@change_settings("Manufacturing Settings", {"job_card_excess_transfer": 1})
def test_job_card_excess_material_transfer(self):
"Test transferring more than required RM against Job Card."
make_stock_entry(item_code="_Test Item", target="Stores - _TC", qty=25, basic_rate=100)
@ -208,6 +214,29 @@ class TestJobCard(FrappeTestCase):
# JC is Completed with excess transfer
self.assertEqual(job_card.status, "Completed")
@change_settings("Manufacturing Settings", {"job_card_excess_transfer": 0})
def test_job_card_excess_material_transfer_block(self):
make_stock_entry(item_code="_Test Item", target="Stores - _TC", qty=25, basic_rate=100)
make_stock_entry(
item_code="_Test Item Home Desktop Manufactured", target="Stores - _TC", qty=15, basic_rate=100
)
job_card_name = frappe.db.get_value("Job Card", {"work_order": self.work_order.name})
# fully transfer both RMs
transfer_entry_1 = make_stock_entry_from_jc(job_card_name)
transfer_entry_1.insert()
transfer_entry_1.submit()
# transfer extra qty of both RM due to previously damaged RM
transfer_entry_2 = make_stock_entry_from_jc(job_card_name)
# deliberately change 'For Quantity'
transfer_entry_2.fg_completed_qty = 1
transfer_entry_2.items[0].qty = 5
transfer_entry_2.items[1].qty = 3
transfer_entry_2.insert()
self.assertRaises(JobCardOverTransferError, transfer_entry_2.submit)
def test_job_card_partial_material_transfer(self):
"Test partial material transfer against Job Card"

View File

@ -1141,7 +1141,7 @@ class StockEntry(StockController):
if self.job_card:
job_doc = frappe.get_doc("Job Card", self.job_card)
job_doc.set_transferred_qty(update_status=True)
job_doc.set_transferred_qty_in_job_card(self)
job_doc.set_transferred_qty_in_job_card_item(self)
if self.work_order:
pro_doc = frappe.get_doc("Work Order", self.work_order)