mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-22 06:29:20 +00:00
refactor: rename subcontracting fields
This commit is contained in:
@@ -406,7 +406,7 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends (
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!doc.items.every((item) => item.qty == item.sco_qty)) {
|
if (!doc.items.every((item) => item.qty == item.subcontracted_quantity)) {
|
||||||
this.frm.add_custom_button(
|
this.frm.add_custom_button(
|
||||||
__("Subcontracting Order"),
|
__("Subcontracting Order"),
|
||||||
() => {
|
() => {
|
||||||
|
|||||||
@@ -922,7 +922,7 @@ def is_po_fully_subcontracted(po_name):
|
|||||||
query = (
|
query = (
|
||||||
frappe.qb.from_(table)
|
frappe.qb.from_(table)
|
||||||
.select(table.name)
|
.select(table.name)
|
||||||
.where((table.parent == po_name) & (table.qty != table.sco_qty))
|
.where((table.parent == po_name) & (table.qty != table.subcontracted_quantity))
|
||||||
)
|
)
|
||||||
return not query.run(as_dict=True)
|
return not query.run(as_dict=True)
|
||||||
|
|
||||||
@@ -977,7 +977,7 @@ def get_mapped_subcontracting_order(source_name, target_doc=None):
|
|||||||
"material_request_item": "material_request_item",
|
"material_request_item": "material_request_item",
|
||||||
},
|
},
|
||||||
"field_no_map": ["qty", "fg_item_qty", "amount"],
|
"field_no_map": ["qty", "fg_item_qty", "amount"],
|
||||||
"condition": lambda item: item.qty != item.sco_qty,
|
"condition": lambda item: item.qty != item.subcontracted_quantity,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
target_doc,
|
target_doc,
|
||||||
|
|||||||
@@ -1097,9 +1097,9 @@ class TestPurchaseOrder(IntegrationTestCase):
|
|||||||
|
|
||||||
# Test - 2: Subcontracted Quantity for the PO Items of each line item should be updated accordingly
|
# Test - 2: Subcontracted Quantity for the PO Items of each line item should be updated accordingly
|
||||||
po.reload()
|
po.reload()
|
||||||
self.assertEqual(po.items[0].sco_qty, 5)
|
self.assertEqual(po.items[0].subcontracted_quantity, 5)
|
||||||
self.assertEqual(po.items[1].sco_qty, 0)
|
self.assertEqual(po.items[1].subcontracted_quantity, 0)
|
||||||
self.assertEqual(po.items[2].sco_qty, 12.5)
|
self.assertEqual(po.items[2].subcontracted_quantity, 12.5)
|
||||||
|
|
||||||
# Test - 3: Amount for both FG Item and its Service Item should be updated correctly based on change in Quantity
|
# Test - 3: Amount for both FG Item and its Service Item should be updated correctly based on change in Quantity
|
||||||
self.assertEqual(sco.items[0].amount, 2000)
|
self.assertEqual(sco.items[0].amount, 2000)
|
||||||
@@ -1135,10 +1135,10 @@ class TestPurchaseOrder(IntegrationTestCase):
|
|||||||
|
|
||||||
# Test - 8: Subcontracted Quantity for each PO Item should be subtracted if SCO gets cancelled
|
# Test - 8: Subcontracted Quantity for each PO Item should be subtracted if SCO gets cancelled
|
||||||
po.reload()
|
po.reload()
|
||||||
self.assertEqual(po.items[2].sco_qty, 25)
|
self.assertEqual(po.items[2].subcontracted_quantity, 25)
|
||||||
sco.cancel()
|
sco.cancel()
|
||||||
po.reload()
|
po.reload()
|
||||||
self.assertEqual(po.items[2].sco_qty, 12.5)
|
self.assertEqual(po.items[2].subcontracted_quantity, 12.5)
|
||||||
|
|
||||||
sco = make_subcontracting_order(po.name)
|
sco = make_subcontracting_order(po.name)
|
||||||
sco.save()
|
sco.save()
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
"quantity_and_rate",
|
"quantity_and_rate",
|
||||||
"qty",
|
"qty",
|
||||||
"stock_uom",
|
"stock_uom",
|
||||||
"sco_qty",
|
"subcontracted_quantity",
|
||||||
"col_break2",
|
"col_break2",
|
||||||
"uom",
|
"uom",
|
||||||
"conversion_factor",
|
"conversion_factor",
|
||||||
@@ -933,7 +933,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 1,
|
"allow_on_submit": 1,
|
||||||
"fieldname": "sco_qty",
|
"fieldname": "subcontracted_quantity",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"label": "Subcontracted Quantity",
|
"label": "Subcontracted Quantity",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
@@ -941,11 +941,12 @@
|
|||||||
"read_only": 1
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"grid_page_length": 50,
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2025-02-18 12:35:04.432636",
|
"modified": "2025-03-02 16:58:26.059601",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Buying",
|
"module": "Buying",
|
||||||
"name": "Purchase Order Item",
|
"name": "Purchase Order Item",
|
||||||
@@ -953,6 +954,7 @@
|
|||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [],
|
"permissions": [],
|
||||||
"quick_entry": 1,
|
"quick_entry": 1,
|
||||||
|
"row_format": "Dynamic",
|
||||||
"search_fields": "item_name",
|
"search_fields": "item_name",
|
||||||
"sort_field": "creation",
|
"sort_field": "creation",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
|
|||||||
@@ -82,10 +82,10 @@ class PurchaseOrderItem(Document):
|
|||||||
sales_order_item: DF.Data | None
|
sales_order_item: DF.Data | None
|
||||||
sales_order_packed_item: DF.Data | None
|
sales_order_packed_item: DF.Data | None
|
||||||
schedule_date: DF.Date
|
schedule_date: DF.Date
|
||||||
sco_qty: DF.Float
|
|
||||||
stock_qty: DF.Float
|
stock_qty: DF.Float
|
||||||
stock_uom: DF.Link
|
stock_uom: DF.Link
|
||||||
stock_uom_rate: DF.Currency
|
stock_uom_rate: DF.Currency
|
||||||
|
subcontracted_quantity: DF.Float
|
||||||
supplier_part_no: DF.Data | None
|
supplier_part_no: DF.Data | None
|
||||||
supplier_quotation: DF.Link | None
|
supplier_quotation: DF.Link | None
|
||||||
supplier_quotation_item: DF.Link | None
|
supplier_quotation_item: DF.Link | None
|
||||||
|
|||||||
@@ -104,18 +104,18 @@ class SubcontractingController(StockController):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
self.doctype == "Subcontracting Order" and not item.sc_conversion_factor
|
self.doctype == "Subcontracting Order" and not item.subcontracting_conversion_factor
|
||||||
): # this condition will only be true if user has recently updated from develop branch
|
): # this condition will only be true if user has recently updated from develop branch
|
||||||
service_item_qty = frappe.get_value(
|
service_item_qty = frappe.get_value(
|
||||||
"Subcontracting Order Service Item",
|
"Subcontracting Order Service Item",
|
||||||
filters={"purchase_order_item": item.purchase_order_item, "parent": self.name},
|
filters={"purchase_order_item": item.purchase_order_item, "parent": self.name},
|
||||||
fieldname=["qty"],
|
fieldname=["qty"],
|
||||||
)
|
)
|
||||||
item.sc_conversion_factor = service_item_qty / item.qty
|
item.subcontracting_conversion_factor = service_item_qty / item.qty
|
||||||
|
|
||||||
if self.doctype not in "Subcontracting Receipt" and item.qty > flt(
|
if self.doctype not in "Subcontracting Receipt" and item.qty > flt(
|
||||||
get_pending_sco_qty(self.purchase_order).get(item.purchase_order_item)
|
get_pending_subcontracted_quantity(self.purchase_order).get(item.purchase_order_item)
|
||||||
/ item.sc_conversion_factor,
|
/ item.subcontracting_conversion_factor,
|
||||||
frappe.get_precision("Purchase Order Item", "qty"),
|
frappe.get_precision("Purchase Order Item", "qty"),
|
||||||
):
|
):
|
||||||
frappe.throw(
|
frappe.throw(
|
||||||
@@ -1138,10 +1138,14 @@ def get_item_details(items):
|
|||||||
return item_details
|
return item_details
|
||||||
|
|
||||||
|
|
||||||
def get_pending_sco_qty(po_name):
|
def get_pending_subcontracted_quantity(po_name):
|
||||||
table = frappe.qb.DocType("Purchase Order Item")
|
table = frappe.qb.DocType("Purchase Order Item")
|
||||||
query = frappe.qb.from_(table).select(table.name, table.qty, table.sco_qty).where(table.parent == po_name)
|
query = (
|
||||||
return {item.name: item.qty - item.sco_qty for item in query.run(as_dict=True)}
|
frappe.qb.from_(table)
|
||||||
|
.select(table.name, table.qty, table.subcontracted_quantity)
|
||||||
|
.where(table.parent == po_name)
|
||||||
|
)
|
||||||
|
return {item.name: item.qty - item.subcontracted_quantity for item in query.run(as_dict=True)}
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
|
|||||||
@@ -1433,7 +1433,7 @@ def add_operations_cost(stock_entry, work_order=None, expense_account=None):
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_max_op_qty():
|
def get_max_operation_quantity():
|
||||||
from frappe.query_builder.functions import Sum
|
from frappe.query_builder.functions import Sum
|
||||||
|
|
||||||
table = frappe.qb.DocType("Job Card")
|
table = frappe.qb.DocType("Job Card")
|
||||||
@@ -1449,7 +1449,7 @@ def add_operations_cost(stock_entry, work_order=None, expense_account=None):
|
|||||||
)
|
)
|
||||||
return min([d.qty for d in query.run(as_dict=True)], default=0)
|
return min([d.qty for d in query.run(as_dict=True)], default=0)
|
||||||
|
|
||||||
def get_utilised_cc():
|
def get_utilised_corrective_cost():
|
||||||
from frappe.query_builder.functions import Sum
|
from frappe.query_builder.functions import Sum
|
||||||
|
|
||||||
table = frappe.qb.DocType("Stock Entry")
|
table = frappe.qb.DocType("Stock Entry")
|
||||||
@@ -1479,15 +1479,15 @@ def add_operations_cost(stock_entry, work_order=None, expense_account=None):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
):
|
):
|
||||||
max_qty = get_max_op_qty() - work_order.produced_qty
|
max_qty = get_max_operation_quantity() - work_order.produced_qty
|
||||||
remaining_cc = work_order.corrective_operation_cost - get_utilised_cc()
|
remaining_corrective_cost = work_order.corrective_operation_cost - get_utilised_corrective_cost()
|
||||||
stock_entry.append(
|
stock_entry.append(
|
||||||
"additional_costs",
|
"additional_costs",
|
||||||
{
|
{
|
||||||
"expense_account": expense_account,
|
"expense_account": expense_account,
|
||||||
"description": "Corrective Operation Cost",
|
"description": "Corrective Operation Cost",
|
||||||
"has_corrective_cost": 1,
|
"has_corrective_cost": 1,
|
||||||
"amount": remaining_cc / max_qty * flt(stock_entry.fg_completed_qty),
|
"amount": remaining_corrective_cost / max_qty * flt(stock_entry.fg_completed_qty),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -260,6 +260,7 @@ erpnext.patches.v14_0.show_loan_management_deprecation_warning
|
|||||||
erpnext.patches.v14_0.clear_reconciliation_values_from_singles
|
erpnext.patches.v14_0.clear_reconciliation_values_from_singles
|
||||||
execute:frappe.rename_doc("Report", "TDS Payable Monthly", "Tax Withholding Details", force=True)
|
execute:frappe.rename_doc("Report", "TDS Payable Monthly", "Tax Withholding Details", force=True)
|
||||||
erpnext.patches.v14_0.update_proprietorship_to_individual
|
erpnext.patches.v14_0.update_proprietorship_to_individual
|
||||||
|
erpnext.patches.v15_0.rename_subcontracting_fields
|
||||||
|
|
||||||
[post_model_sync]
|
[post_model_sync]
|
||||||
erpnext.patches.v15_0.create_asset_depreciation_schedules_from_assets
|
erpnext.patches.v15_0.create_asset_depreciation_schedules_from_assets
|
||||||
|
|||||||
7
erpnext/patches/v15_0/rename_subcontracting_fields.py
Normal file
7
erpnext/patches/v15_0/rename_subcontracting_fields.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import frappe
|
||||||
|
from frappe.model.utils.rename_field import rename_field
|
||||||
|
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
rename_field("Purchase Order Item", "sco_qty", "subcontracted_quantity")
|
||||||
|
rename_field("Subcontracting Order Item", "sc_conversion_factor", "subcontracting_conversion_factor")
|
||||||
@@ -16,14 +16,14 @@ frappe.ui.form.on("Subcontracting Order Item", {
|
|||||||
service_item.doctype,
|
service_item.doctype,
|
||||||
service_item.name,
|
service_item.name,
|
||||||
"qty",
|
"qty",
|
||||||
row.qty * row.sc_conversion_factor
|
row.qty * row.subcontracting_conversion_factor
|
||||||
);
|
);
|
||||||
frappe.model.set_value(service_item.doctype, service_item.name, "fg_item_qty", row.qty);
|
frappe.model.set_value(service_item.doctype, service_item.name, "fg_item_qty", row.qty);
|
||||||
frappe.model.set_value(
|
frappe.model.set_value(
|
||||||
service_item.doctype,
|
service_item.doctype,
|
||||||
service_item.name,
|
service_item.name,
|
||||||
"amount",
|
"amount",
|
||||||
row.qty * row.sc_conversion_factor * service_item.rate
|
row.qty * row.subcontracting_conversion_factor * service_item.rate
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
before_items_remove(frm, cdt, cdn) {
|
before_items_remove(frm, cdt, cdn) {
|
||||||
|
|||||||
@@ -119,12 +119,12 @@ class SubcontractingOrder(SubcontractingController):
|
|||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
self.update_prevdoc_status()
|
self.update_prevdoc_status()
|
||||||
self.update_status()
|
self.update_status()
|
||||||
self.update_sco_qty_in_po()
|
self.update_subcontracted_quantity_in_po()
|
||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
self.update_prevdoc_status()
|
self.update_prevdoc_status()
|
||||||
self.update_status()
|
self.update_status()
|
||||||
self.update_sco_qty_in_po(cancel=True)
|
self.update_subcontracted_quantity_in_po(cancel=True)
|
||||||
|
|
||||||
def validate_purchase_order_for_subcontracting(self):
|
def validate_purchase_order_for_subcontracting(self):
|
||||||
if self.purchase_order:
|
if self.purchase_order:
|
||||||
@@ -162,7 +162,7 @@ class SubcontractingOrder(SubcontractingController):
|
|||||||
item = next(
|
item = next(
|
||||||
item for item in self.items if item.purchase_order_item == service_item.purchase_order_item
|
item for item in self.items if item.purchase_order_item == service_item.purchase_order_item
|
||||||
)
|
)
|
||||||
service_item.qty = item.qty * item.sc_conversion_factor
|
service_item.qty = item.qty * item.subcontracting_conversion_factor
|
||||||
service_item.fg_item_qty = item.qty
|
service_item.fg_item_qty = item.qty
|
||||||
service_item.amount = service_item.qty * service_item.rate
|
service_item.amount = service_item.qty * service_item.rate
|
||||||
|
|
||||||
@@ -250,7 +250,7 @@ class SubcontractingOrder(SubcontractingController):
|
|||||||
item = frappe.get_doc("Item", si.fg_item)
|
item = frappe.get_doc("Item", si.fg_item)
|
||||||
|
|
||||||
po_item = frappe.get_doc("Purchase Order Item", si.purchase_order_item)
|
po_item = frappe.get_doc("Purchase Order Item", si.purchase_order_item)
|
||||||
available_qty = po_item.qty - po_item.sco_qty
|
available_qty = po_item.qty - po_item.subcontracted_quantity
|
||||||
|
|
||||||
if available_qty == 0:
|
if available_qty == 0:
|
||||||
continue
|
continue
|
||||||
@@ -276,7 +276,7 @@ class SubcontractingOrder(SubcontractingController):
|
|||||||
"schedule_date": self.schedule_date,
|
"schedule_date": self.schedule_date,
|
||||||
"description": item.description,
|
"description": item.description,
|
||||||
"qty": si.fg_item_qty,
|
"qty": si.fg_item_qty,
|
||||||
"sc_conversion_factor": conversion_factor,
|
"subcontracting_conversion_factor": conversion_factor,
|
||||||
"stock_uom": item.stock_uom,
|
"stock_uom": item.stock_uom,
|
||||||
"bom": bom,
|
"bom": bom,
|
||||||
"purchase_order_item": si.purchase_order_item,
|
"purchase_order_item": si.purchase_order_item,
|
||||||
@@ -330,10 +330,14 @@ class SubcontractingOrder(SubcontractingController):
|
|||||||
self.update_ordered_qty_for_subcontracting()
|
self.update_ordered_qty_for_subcontracting()
|
||||||
self.update_reserved_qty_for_subcontracting()
|
self.update_reserved_qty_for_subcontracting()
|
||||||
|
|
||||||
def update_sco_qty_in_po(self, cancel=False):
|
def update_subcontracted_quantity_in_po(self, cancel=False):
|
||||||
for service_item in self.service_items:
|
for service_item in self.service_items:
|
||||||
doc = frappe.get_doc("Purchase Order Item", service_item.purchase_order_item)
|
doc = frappe.get_doc("Purchase Order Item", service_item.purchase_order_item)
|
||||||
doc.sco_qty = (doc.sco_qty + service_item.qty) if not cancel else (doc.sco_qty - service_item.qty)
|
doc.subcontracted_quantity = (
|
||||||
|
(doc.subcontracted_quantity + service_item.qty)
|
||||||
|
if not cancel
|
||||||
|
else (doc.subcontracted_quantity - service_item.qty)
|
||||||
|
)
|
||||||
doc.save()
|
doc.save()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@
|
|||||||
"section_break_34",
|
"section_break_34",
|
||||||
"purchase_order_item",
|
"purchase_order_item",
|
||||||
"page_break",
|
"page_break",
|
||||||
"sc_conversion_factor"
|
"subcontracting_conversion_factor"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@@ -403,18 +403,19 @@
|
|||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "sc_conversion_factor",
|
"fieldname": "subcontracting_conversion_factor",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
"label": "SC Conversion Factor",
|
"label": "Subcontracting Conversion Factor",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"grid_page_length": 50,
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2024-12-13 13:35:28.935898",
|
"modified": "2025-03-02 17:05:28.386492",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Subcontracting",
|
"module": "Subcontracting",
|
||||||
"name": "Subcontracting Order Item",
|
"name": "Subcontracting Order Item",
|
||||||
@@ -422,6 +423,7 @@
|
|||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [],
|
"permissions": [],
|
||||||
"quick_entry": 1,
|
"quick_entry": 1,
|
||||||
|
"row_format": "Dynamic",
|
||||||
"search_fields": "item_name",
|
"search_fields": "item_name",
|
||||||
"sort_field": "creation",
|
"sort_field": "creation",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
|
|||||||
@@ -42,10 +42,10 @@ class SubcontractingOrderItem(Document):
|
|||||||
received_qty: DF.Float
|
received_qty: DF.Float
|
||||||
returned_qty: DF.Float
|
returned_qty: DF.Float
|
||||||
rm_cost_per_qty: DF.Currency
|
rm_cost_per_qty: DF.Currency
|
||||||
sc_conversion_factor: DF.Float
|
|
||||||
schedule_date: DF.Date | None
|
schedule_date: DF.Date | None
|
||||||
service_cost_per_qty: DF.Currency
|
service_cost_per_qty: DF.Currency
|
||||||
stock_uom: DF.Link
|
stock_uom: DF.Link
|
||||||
|
subcontracting_conversion_factor: DF.Float
|
||||||
warehouse: DF.Link
|
warehouse: DF.Link
|
||||||
# end: auto-generated types
|
# end: auto-generated types
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user