refactor(job_card): move mapping functions to mapper.py

This commit is contained in:
Nabin Hait
2026-05-29 13:20:50 +05:30
parent 0a4fa5e35e
commit 341fad04c9
2 changed files with 193 additions and 180 deletions

View File

@@ -8,7 +8,6 @@ from typing import Any
import frappe
from frappe import _, bold
from frappe.model.document import Document
from frappe.model.mapper import get_mapped_doc
from frappe.query_builder import Criterion
from frappe.query_builder.functions import IfNull, Max, Min, Sum
from frappe.utils import (
@@ -37,6 +36,8 @@ from erpnext.subcontracting.doctype.subcontracting_bom.subcontracting_bom import
get_subcontracting_boms_for_finished_goods,
)
from .mapper import make_corrective_job_card, make_material_request, make_stock_entry, make_subcontracting_po
class OverlapError(frappe.ValidationError):
pass
@@ -1547,49 +1548,6 @@ class JobCard(Document):
return ste.stock_entry.as_dict()
@frappe.whitelist()
def make_subcontracting_po(source_name: str, target_doc: Document | str | None = None):
def set_missing_values(source, target):
_item_details = get_subcontracting_boms_for_finished_goods(source.finished_good)
pending_qty = source.for_quantity - source.manufactured_qty
service_item_qty = flt(_item_details.service_item_qty) or 1.0
fg_item_qty = flt(_item_details.finished_good_qty) or 1.0
target.is_subcontracted = 1
target.supplier_warehouse = source.wip_warehouse
target.append(
"items",
{
"item_code": _item_details.service_item,
"fg_item": source.finished_good,
"uom": _item_details.service_item_uom,
"stock_uom": _item_details.service_item_uom,
"conversion_factor": _item_details.conversion_factor or 1,
"item_name": _item_details.service_item,
"qty": pending_qty * service_item_qty / fg_item_qty,
"fg_item_qty": pending_qty,
"job_card": source.name,
"bom": source.semi_fg_bom,
"warehouse": source.target_warehouse,
},
)
doclist = get_mapped_doc(
"Job Card",
source_name,
{
"Job Card": {
"doctype": "Purchase Order",
},
},
target_doc,
set_missing_values,
)
return doclist
@frappe.whitelist()
def make_time_log(kwargs: str | dict):
if isinstance(kwargs, str):
@@ -1633,105 +1591,6 @@ def get_operations(doctype: str, txt: str, searchfield: str, start: int, page_le
)
@frappe.whitelist()
def make_material_request(source_name: str, target_doc: Document | str | None = None):
def update_item(obj, target, source_parent):
target.warehouse = source_parent.wip_warehouse
def set_missing_values(source, target):
target.material_request_type = "Material Transfer"
doclist = get_mapped_doc(
"Job Card",
source_name,
{
"Job Card": {
"doctype": "Material Request",
"field_map": {
"name": "job_card",
},
},
"Job Card Item": {
"doctype": "Material Request Item",
"field_map": {"required_qty": "qty", "uom": "stock_uom", "name": "job_card_item"},
"postprocess": update_item,
},
},
target_doc,
set_missing_values,
)
return doclist
@frappe.whitelist()
def make_stock_entry(source_name: str, target_doc: Document | str | None = None):
def update_item(source, target, source_parent):
target.t_warehouse = source_parent.wip_warehouse
if not target.conversion_factor:
target.conversion_factor = 1
pending_rm_qty = flt(source.required_qty) - flt(source.transferred_qty)
if pending_rm_qty > 0:
target.qty = pending_rm_qty
def set_missing_values(source, target):
if source.finished_good and not source.target_warehouse:
frappe.throw(_("Please set the Target Warehouse in the Job Card"))
if not source.skip_material_transfer or source.backflush_from_wip_warehouse:
if not source.wip_warehouse:
frappe.throw(_("Please set the WIP Warehouse in the Job Card"))
target.purpose = "Material Transfer for Manufacture"
target.from_bom = 1
if source.semi_fg_bom:
target.bom_no = source.semi_fg_bom
# avoid negative 'For Quantity'
pending_fg_qty = flt(source.get("for_quantity", 0)) - flt(source.get("transferred_qty", 0))
target.fg_completed_qty = pending_fg_qty if pending_fg_qty > 0 else 0
target.set_missing_values()
target.set_stock_entry_type()
wo_allows_alternate_item = frappe.db.get_value(
"Work Order", target.work_order, "allow_alternative_item"
)
for item in target.items:
item.allow_alternative_item = int(
wo_allows_alternate_item
and frappe.get_cached_value("Item", item.item_code, "allow_alternative_item")
)
doclist = get_mapped_doc(
"Job Card",
source_name,
{
"Job Card": {
"doctype": "Stock Entry",
"field_map": {"name": "job_card", "for_quantity": "fg_completed_qty"},
},
"Job Card Item": {
"doctype": "Stock Entry Detail",
"field_map": {
"source_warehouse": "s_warehouse",
"required_qty": "qty",
"name": "job_card_item",
},
"postprocess": update_item,
"condition": lambda doc: doc.required_qty > 0,
},
},
target_doc,
set_missing_values,
)
return doclist
def time_diff_in_minutes(string_ed_date, string_st_date):
return time_diff(string_ed_date, string_st_date).total_seconds() / 60
@@ -1782,40 +1641,3 @@ def get_job_details(start: Any, end: Any, filters: str | dict | None = None):
events.append(job_card_data)
return events
@frappe.whitelist()
def make_corrective_job_card(
source_name: str,
operation: str | None = None,
for_operation: str | None = None,
target_doc: Document | str | None = None,
):
def set_missing_values(source, target):
target.is_corrective_job_card = 1
target.operation = operation
target.for_operation = for_operation
target.set("time_logs", [])
target.set("employee", [])
target.set("items", [])
target.set("sub_operations", [])
target.set_sub_operations()
target.get_required_items()
doclist = get_mapped_doc(
"Job Card",
source_name,
{
"Job Card": {
"doctype": "Job Card",
"field_map": {
"name": "for_job_card",
},
}
},
target_doc,
set_missing_values,
)
return doclist

View File

@@ -0,0 +1,191 @@
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.model.mapper import get_mapped_doc
from frappe.utils import flt
from erpnext.subcontracting.doctype.subcontracting_bom.subcontracting_bom import (
get_subcontracting_boms_for_finished_goods,
)
@frappe.whitelist()
def make_subcontracting_po(source_name: str, target_doc: Document | str | None = None):
def set_missing_values(source, target):
_item_details = get_subcontracting_boms_for_finished_goods(source.finished_good)
pending_qty = source.for_quantity - source.manufactured_qty
service_item_qty = flt(_item_details.service_item_qty) or 1.0
fg_item_qty = flt(_item_details.finished_good_qty) or 1.0
target.is_subcontracted = 1
target.supplier_warehouse = source.wip_warehouse
target.append(
"items",
{
"item_code": _item_details.service_item,
"fg_item": source.finished_good,
"uom": _item_details.service_item_uom,
"stock_uom": _item_details.service_item_uom,
"conversion_factor": _item_details.conversion_factor or 1,
"item_name": _item_details.service_item,
"qty": pending_qty * service_item_qty / fg_item_qty,
"fg_item_qty": pending_qty,
"job_card": source.name,
"bom": source.semi_fg_bom,
"warehouse": source.target_warehouse,
},
)
doclist = get_mapped_doc(
"Job Card",
source_name,
{
"Job Card": {
"doctype": "Purchase Order",
},
},
target_doc,
set_missing_values,
)
return doclist
@frappe.whitelist()
def make_material_request(source_name: str, target_doc: Document | str | None = None):
def update_item(obj, target, source_parent):
target.warehouse = source_parent.wip_warehouse
def set_missing_values(source, target):
target.material_request_type = "Material Transfer"
doclist = get_mapped_doc(
"Job Card",
source_name,
{
"Job Card": {
"doctype": "Material Request",
"field_map": {
"name": "job_card",
},
},
"Job Card Item": {
"doctype": "Material Request Item",
"field_map": {"required_qty": "qty", "uom": "stock_uom", "name": "job_card_item"},
"postprocess": update_item,
},
},
target_doc,
set_missing_values,
)
return doclist
@frappe.whitelist()
def make_stock_entry(source_name: str, target_doc: Document | str | None = None):
def update_item(source, target, source_parent):
target.t_warehouse = source_parent.wip_warehouse
if not target.conversion_factor:
target.conversion_factor = 1
pending_rm_qty = flt(source.required_qty) - flt(source.transferred_qty)
if pending_rm_qty > 0:
target.qty = pending_rm_qty
def set_missing_values(source, target):
if source.finished_good and not source.target_warehouse:
frappe.throw(_("Please set the Target Warehouse in the Job Card"))
if not source.skip_material_transfer or source.backflush_from_wip_warehouse:
if not source.wip_warehouse:
frappe.throw(_("Please set the WIP Warehouse in the Job Card"))
target.purpose = "Material Transfer for Manufacture"
target.from_bom = 1
if source.semi_fg_bom:
target.bom_no = source.semi_fg_bom
# avoid negative 'For Quantity'
pending_fg_qty = flt(source.get("for_quantity", 0)) - flt(source.get("transferred_qty", 0))
target.fg_completed_qty = pending_fg_qty if pending_fg_qty > 0 else 0
target.set_missing_values()
target.set_stock_entry_type()
wo_allows_alternate_item = frappe.db.get_value(
"Work Order", target.work_order, "allow_alternative_item"
)
for item in target.items:
item.allow_alternative_item = int(
wo_allows_alternate_item
and frappe.get_cached_value("Item", item.item_code, "allow_alternative_item")
)
doclist = get_mapped_doc(
"Job Card",
source_name,
{
"Job Card": {
"doctype": "Stock Entry",
"field_map": {"name": "job_card", "for_quantity": "fg_completed_qty"},
},
"Job Card Item": {
"doctype": "Stock Entry Detail",
"field_map": {
"source_warehouse": "s_warehouse",
"required_qty": "qty",
"name": "job_card_item",
},
"postprocess": update_item,
"condition": lambda doc: doc.required_qty > 0,
},
},
target_doc,
set_missing_values,
)
return doclist
@frappe.whitelist()
def make_corrective_job_card(
source_name: str,
operation: str | None = None,
for_operation: str | None = None,
target_doc: Document | str | None = None,
):
def set_missing_values(source, target):
target.is_corrective_job_card = 1
target.operation = operation
target.for_operation = for_operation
target.set("time_logs", [])
target.set("employee", [])
target.set("items", [])
target.set("sub_operations", [])
target.set_sub_operations()
target.get_required_items()
doclist = get_mapped_doc(
"Job Card",
source_name,
{
"Job Card": {
"doctype": "Job Card",
"field_map": {
"name": "for_job_card",
},
}
},
target_doc,
set_missing_values,
)
return doclist