feat: Handle Excess/Multiple Item Transfer against Job Card

- Hide MR/Material Transfer buttons in JC if cancelled
- Show MR/Material transfer buttons if pending to transfer or excess transfer allowed
- Renamed ‘Transferred Qty’ to ‘FG Qty from Transferred Raw Materials’ in JC
- Set status to Completed in JC in case of excess transfer too
- During excess transfer against JC, avoid negative ‘For Quantity’. Set to 0 instead
- Job card section and excess transfer allowance checkbox in Manufacturing Settings
- Renamed ’Allow Multiple Material Consumption’ to ‘Allow Continuous Material Consumption’ (fiedname is same)
- Secured denominator variables in `get_transfered_raw_materials` to avoid ZeroDivisionError
This commit is contained in:
marination 2021-09-14 12:33:21 +05:30
parent d743c41b54
commit 9520215e2b
5 changed files with 52 additions and 13 deletions

View File

@ -27,14 +27,21 @@ frappe.ui.form.on('Job Card', {
frappe.flags.pause_job = 0;
frappe.flags.resume_job = 0;
if(!frm.doc.__islocal && frm.doc.items && frm.doc.items.length) {
if (frm.doc.for_quantity != frm.doc.transferred_qty) {
if(!frm.doc.__islocal && frm.doc.items && frm.doc.items.length && frm.doc.docstatus < 2) {
let to_request = frm.doc.for_quantity > frm.doc.transferred_qty;
let excess_transfer_allowed = frm.doc.__onload.job_card_excess_transfer;
if (to_request || excess_transfer_allowed) {
frm.add_custom_button(__("Material Request"), () => {
frm.trigger("make_material_request");
});
}
if (frm.doc.for_quantity != frm.doc.transferred_qty) {
// check if any row has untransferred materials
// in case of multiple items in JC
let to_transfer = frm.doc.items.some((row) => row.transferred_qty < row.required_qty);
if (to_transfer || excess_transfer_allowed) {
frm.add_custom_button(__("Material Transfer"), () => {
frm.trigger("make_stock_entry");
}).addClass("btn-primary");

View File

@ -185,7 +185,7 @@
"default": "0",
"fieldname": "transferred_qty",
"fieldtype": "Float",
"label": "Transferred Qty",
"label": "FG Qty from Transferred Raw Materials",
"read_only": 1
},
{
@ -396,10 +396,11 @@
],
"is_submittable": 1,
"links": [],
"modified": "2021-03-16 15:59:32.766484",
"modified": "2021-09-13 21:34:15.177928",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Job Card",
"naming_rule": "By \"Naming Series\" field",
"owner": "Administrator",
"permissions": [
{

View File

@ -37,6 +37,10 @@ class OperationSequenceError(frappe.ValidationError): pass
class JobCardCancelError(frappe.ValidationError): pass
class JobCard(Document):
def onload(self):
excess_transfer = frappe.db.get_single_value("Manufacturing Settings", "job_card_excess_transfer")
self.set_onload("job_card_excess_transfer", excess_transfer)
def validate(self):
self.validate_time_logs()
self.set_status()
@ -449,6 +453,7 @@ class JobCard(Document):
frappe.db.set_value('Job Card Item', row.job_card_item, 'transferred_qty', flt(qty))
def set_transferred_qty(self, update_status=False):
"Set total FG Qty for which RM was transferred."
if not self.items:
self.transferred_qty = self.for_quantity if self.docstatus == 1 else 0
@ -457,6 +462,7 @@ class JobCard(Document):
return
if self.items:
# sum of 'For Quantity' of Stock Entries against JC
self.transferred_qty = frappe.db.get_value('Stock Entry', {
'job_card': self.name,
'work_order': self.work_order,
@ -500,7 +506,9 @@ class JobCard(Document):
self.status = 'Work In Progress'
if (self.docstatus == 1 and
(self.for_quantity == self.transferred_qty or not self.items)):
(self.for_quantity <= self.transferred_qty or not self.items)):
# consider excess transfer
# completed qty is checked via separate validation
self.status = 'Completed'
if self.status != 'Completed':
@ -618,7 +626,11 @@ def make_stock_entry(source_name, target_doc=None):
def set_missing_values(source, target):
target.purpose = "Material Transfer for Manufacture"
target.from_bom = 1
target.fg_completed_qty = source.get('for_quantity', 0) - source.get('transferred_qty', 0)
# avoid negative 'For Quantity'
pending_fg_qty = source.get('for_quantity', 0) - source.get('transferred_qty', 0)
target.fg_completed_qty = pending_fg_qty if pending_fg_qty > 0 else 0
target.set_transfer_qty()
target.calculate_rate_and_amount()
target.set_missing_values()

View File

@ -25,9 +25,12 @@
"overproduction_percentage_for_sales_order",
"column_break_16",
"overproduction_percentage_for_work_order",
"job_card_section",
"add_corrective_operation_cost_in_finished_good_valuation",
"column_break_24",
"job_card_excess_transfer",
"other_settings_section",
"update_bom_costs_automatically",
"add_corrective_operation_cost_in_finished_good_valuation",
"column_break_23",
"make_serial_no_batch_from_work_order"
],
@ -96,10 +99,10 @@
},
{
"default": "0",
"description": "Allow multiple material consumptions against a Work Order",
"description": "Allow material consumptions without immediately manufacturing finished goods against a Work Order",
"fieldname": "material_consumption",
"fieldtype": "Check",
"label": "Allow Multiple Material Consumption"
"label": "Allow Continuous Material Consumption"
},
{
"default": "0",
@ -175,13 +178,29 @@
"fieldname": "add_corrective_operation_cost_in_finished_good_valuation",
"fieldtype": "Check",
"label": "Add Corrective Operation Cost in Finished Good Valuation"
},
{
"fieldname": "job_card_section",
"fieldtype": "Section Break",
"label": "Job Card"
},
{
"fieldname": "column_break_24",
"fieldtype": "Column Break"
},
{
"default": "0",
"description": "Allow transferring raw materials even after the Required Quantity is fulfilled",
"fieldname": "job_card_excess_transfer",
"fieldtype": "Check",
"label": "Allow Excess Material Transfer"
}
],
"icon": "icon-wrench",
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2021-03-16 15:54:38.967341",
"modified": "2021-09-13 22:09:09.401559",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Manufacturing Settings",

View File

@ -1264,9 +1264,9 @@ class StockEntry(StockController):
po_qty = frappe.db.sql("""select qty, produced_qty, material_transferred_for_manufacturing from
`tabWork Order` where name=%s""", self.work_order, as_dict=1)[0]
manufacturing_qty = flt(po_qty.qty)
manufacturing_qty = flt(po_qty.qty) or 1
produced_qty = flt(po_qty.produced_qty)
trans_qty = flt(po_qty.material_transferred_for_manufacturing)
trans_qty = flt(po_qty.material_transferred_for_manufacturing) or 1
for item in transferred_materials:
qty= item.qty