mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-20 13:39:18 +00:00
refactor: backport old subcontracting code
This commit is contained in:
@@ -24,7 +24,8 @@ frappe.ui.form.on('Subcontracting Order', {
|
||||
return {
|
||||
filters: {
|
||||
docstatus: 1,
|
||||
is_subcontracted: 1
|
||||
is_subcontracted: 1,
|
||||
is_old_subcontracting_flow: 0
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -115,10 +116,14 @@ frappe.ui.form.on('Subcontracting Order', {
|
||||
if (sco_rm_details && sco_rm_details.length) {
|
||||
frm.add_custom_button(__('Return of Components'), () => {
|
||||
frm.call({
|
||||
method: 'erpnext.subcontracting.doctype.subcontracting_order.subcontracting_order.get_materials_from_supplier',
|
||||
method: 'erpnext.controllers.subcontracting_controller.get_materials_from_supplier',
|
||||
freeze: true,
|
||||
freeze_message: __('Creating Stock Entry'),
|
||||
args: { subcontracting_order: frm.doc.name, sco_rm_details: sco_rm_details },
|
||||
args: {
|
||||
subcontract_order: frm.doc.name,
|
||||
rm_details: sco_rm_details,
|
||||
order_doctype: cur_frm.doc.doctype
|
||||
},
|
||||
callback: function (r) {
|
||||
if (r && r.message) {
|
||||
const doc = frappe.model.sync(r.message);
|
||||
@@ -306,10 +311,11 @@ erpnext.buying.SubcontractingOrderController = class SubcontractingOrderControll
|
||||
|
||||
make_rm_stock_entry(rm_items) {
|
||||
frappe.call({
|
||||
method: 'erpnext.subcontracting.doctype.subcontracting_order.subcontracting_order.make_rm_stock_entry',
|
||||
method: 'erpnext.controllers.subcontracting_controller.make_rm_stock_entry',
|
||||
args: {
|
||||
subcontracting_order: cur_frm.doc.name,
|
||||
rm_items: rm_items
|
||||
subcontract_order: cur_frm.doc.name,
|
||||
rm_items: rm_items,
|
||||
order_doctype: cur_frm.doc.doctype
|
||||
},
|
||||
callback: (r) => {
|
||||
var doclist = frappe.model.sync(r.message);
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
import json
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.model.mapper import get_mapped_doc
|
||||
@@ -42,6 +40,9 @@ class SubcontractingOrder(SubcontractingController):
|
||||
if not po.is_subcontracted:
|
||||
frappe.throw(_("Please select a valid Purchase Order that is configured for Subcontracting."))
|
||||
|
||||
if po.is_old_subcontracting_flow:
|
||||
frappe.throw(_("Please select a valid Purchase Order that has Service Items."))
|
||||
|
||||
if po.docstatus != 1:
|
||||
msg = f"Please submit Purchase Order {po.name} before proceeding."
|
||||
frappe.throw(_(msg))
|
||||
@@ -227,143 +228,6 @@ def get_mapped_subcontracting_receipt(source_name, target_doc=None):
|
||||
return target_doc
|
||||
|
||||
|
||||
def get_item_details(items):
|
||||
item = frappe.qb.DocType("Item")
|
||||
item_list = (
|
||||
frappe.qb.from_(item)
|
||||
.select(item.item_code, item.description, item.allow_alternative_item)
|
||||
.where(item.name.isin(items))
|
||||
.run(as_dict=True)
|
||||
)
|
||||
|
||||
item_details = {}
|
||||
for item in item_list:
|
||||
item_details[item.item_code] = item
|
||||
|
||||
return item_details
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_rm_stock_entry(subcontracting_order, rm_items):
|
||||
rm_items_list = rm_items
|
||||
|
||||
if isinstance(rm_items, str):
|
||||
rm_items_list = json.loads(rm_items)
|
||||
elif not rm_items:
|
||||
frappe.throw(_("No Items available for transfer"))
|
||||
|
||||
if rm_items_list:
|
||||
fg_items = list(set(item["item_code"] for item in rm_items_list))
|
||||
else:
|
||||
frappe.throw(_("No Items selected for transfer"))
|
||||
|
||||
if subcontracting_order:
|
||||
subcontracting_order = frappe.get_doc("Subcontracting Order", subcontracting_order)
|
||||
|
||||
if fg_items:
|
||||
items = tuple(set(item["rm_item_code"] for item in rm_items_list))
|
||||
item_wh = get_item_details(items)
|
||||
|
||||
stock_entry = frappe.new_doc("Stock Entry")
|
||||
stock_entry.purpose = "Send to Subcontractor"
|
||||
stock_entry.subcontracting_order = subcontracting_order.name
|
||||
stock_entry.supplier = subcontracting_order.supplier
|
||||
stock_entry.supplier_name = subcontracting_order.supplier_name
|
||||
stock_entry.supplier_address = subcontracting_order.supplier_address
|
||||
stock_entry.address_display = subcontracting_order.address_display
|
||||
stock_entry.company = subcontracting_order.company
|
||||
stock_entry.to_warehouse = subcontracting_order.supplier_warehouse
|
||||
stock_entry.set_stock_entry_type()
|
||||
|
||||
for item_code in fg_items:
|
||||
for rm_item_data in rm_items_list:
|
||||
if rm_item_data["item_code"] == item_code:
|
||||
rm_item_code = rm_item_data["rm_item_code"]
|
||||
items_dict = {
|
||||
rm_item_code: {
|
||||
"sco_rm_detail": rm_item_data.get("name"),
|
||||
"item_name": rm_item_data["item_name"],
|
||||
"description": item_wh.get(rm_item_code, {}).get("description", ""),
|
||||
"qty": rm_item_data["qty"],
|
||||
"from_warehouse": rm_item_data["warehouse"],
|
||||
"stock_uom": rm_item_data["stock_uom"],
|
||||
"serial_no": rm_item_data.get("serial_no"),
|
||||
"batch_no": rm_item_data.get("batch_no"),
|
||||
"main_item_code": rm_item_data["item_code"],
|
||||
"allow_alternative_item": item_wh.get(rm_item_code, {}).get("allow_alternative_item"),
|
||||
}
|
||||
}
|
||||
stock_entry.add_to_stock_entry_detail(items_dict)
|
||||
return stock_entry.as_dict()
|
||||
else:
|
||||
frappe.throw(_("No Items selected for transfer"))
|
||||
return subcontracting_order.name
|
||||
|
||||
|
||||
def add_items_in_ste(ste_doc, row, qty, sco_rm_details, batch_no=None):
|
||||
item = ste_doc.append("items", row.item_details)
|
||||
|
||||
sco_rm_detail = list(set(row.sco_rm_details).intersection(sco_rm_details))
|
||||
item.update(
|
||||
{
|
||||
"qty": qty,
|
||||
"batch_no": batch_no,
|
||||
"basic_rate": row.item_details["rate"],
|
||||
"sco_rm_detail": sco_rm_detail[0] if sco_rm_detail else "",
|
||||
"s_warehouse": row.item_details["t_warehouse"],
|
||||
"t_warehouse": row.item_details["s_warehouse"],
|
||||
"item_code": row.item_details["rm_item_code"],
|
||||
"subcontracted_item": row.item_details["main_item_code"],
|
||||
"serial_no": "\n".join(row.serial_no) if row.serial_no else "",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def make_return_stock_entry_for_subcontract(available_materials, sco_doc, sco_rm_details):
|
||||
ste_doc = frappe.new_doc("Stock Entry")
|
||||
ste_doc.purpose = "Material Transfer"
|
||||
|
||||
ste_doc.subcontracting_order = sco_doc.name
|
||||
ste_doc.company = sco_doc.company
|
||||
ste_doc.is_return = 1
|
||||
|
||||
for key, value in available_materials.items():
|
||||
if not value.qty:
|
||||
continue
|
||||
|
||||
if value.batch_no:
|
||||
for batch_no, qty in value.batch_no.items():
|
||||
if qty > 0:
|
||||
add_items_in_ste(ste_doc, value, value.qty, sco_rm_details, batch_no)
|
||||
else:
|
||||
add_items_in_ste(ste_doc, value, value.qty, sco_rm_details)
|
||||
|
||||
ste_doc.set_stock_entry_type()
|
||||
ste_doc.calculate_rate_and_amount()
|
||||
|
||||
return ste_doc
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_materials_from_supplier(subcontracting_order, sco_rm_details):
|
||||
if isinstance(sco_rm_details, str):
|
||||
sco_rm_details = json.loads(sco_rm_details)
|
||||
|
||||
doc = frappe.get_cached_doc("Subcontracting Order", subcontracting_order)
|
||||
doc.initialized_fields()
|
||||
doc.subcontracting_orders = [doc.name]
|
||||
doc.get_available_materials()
|
||||
|
||||
if not doc.available_materials:
|
||||
frappe.throw(
|
||||
_("Materials are already received against the Subcontracting Order {0}").format(
|
||||
subcontracting_order
|
||||
)
|
||||
)
|
||||
|
||||
return make_return_stock_entry_for_subcontract(doc.available_materials, doc, sco_rm_details)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def update_subcontracting_order_status(sco):
|
||||
if isinstance(sco, str):
|
||||
|
||||
@@ -7,6 +7,7 @@ import frappe
|
||||
from frappe.tests.utils import FrappeTestCase
|
||||
|
||||
from erpnext.buying.doctype.purchase_order.purchase_order import get_mapped_subcontracting_order
|
||||
from erpnext.controllers.subcontracting_controller import make_rm_stock_entry
|
||||
from erpnext.controllers.tests.test_subcontracting_controller import (
|
||||
get_rm_items,
|
||||
get_subcontracting_order,
|
||||
@@ -22,7 +23,6 @@ from erpnext.controllers.tests.test_subcontracting_controller import (
|
||||
from erpnext.stock.doctype.item.test_item import make_item
|
||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
|
||||
from erpnext.subcontracting.doctype.subcontracting_order.subcontracting_order import (
|
||||
make_rm_stock_entry,
|
||||
make_subcontracting_receipt,
|
||||
)
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import cint, flt, getdate, nowdate
|
||||
from frappe.utils import cint, getdate, nowdate
|
||||
|
||||
from erpnext.controllers.subcontracting_controller import SubcontractingController
|
||||
|
||||
@@ -78,7 +78,7 @@ class SubcontractingReceipt(SubcontractingController):
|
||||
self.update_status_updater_args()
|
||||
self.update_prevdoc_status()
|
||||
self.set_subcontracting_order_status()
|
||||
self.set_consumed_qty_in_sco()
|
||||
self.set_consumed_qty_in_subcontract_order()
|
||||
self.update_stock_ledger()
|
||||
|
||||
from erpnext.stock.doctype.serial_no.serial_no import update_serial_nos_after_submit
|
||||
@@ -97,7 +97,7 @@ class SubcontractingReceipt(SubcontractingController):
|
||||
self.make_gl_entries_on_cancel()
|
||||
self.repost_future_sle_and_gle()
|
||||
self.delete_auto_created_batches()
|
||||
self.set_consumed_qty_in_sco()
|
||||
self.set_consumed_qty_in_subcontract_order()
|
||||
self.set_subcontracting_order_status()
|
||||
self.update_status()
|
||||
|
||||
@@ -162,17 +162,6 @@ class SubcontractingReceipt(SubcontractingController):
|
||||
if not item.expense_account:
|
||||
item.expense_account = expense_account
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_current_stock(self):
|
||||
for item in self.get("supplied_items"):
|
||||
if self.supplier_warehouse:
|
||||
actual_qty = frappe.db.get_value(
|
||||
"Bin",
|
||||
{"item_code": item.rm_item_code, "warehouse": self.supplier_warehouse},
|
||||
"actual_qty",
|
||||
)
|
||||
item.current_stock = flt(actual_qty) or 0
|
||||
|
||||
def update_status(self, status=None, update_modified=False):
|
||||
if self.docstatus >= 1 and not status:
|
||||
if self.docstatus == 1:
|
||||
|
||||
@@ -119,7 +119,7 @@ class TestSubcontractingReceipt(FrappeTestCase):
|
||||
receive more than the required qty in the SCO.
|
||||
Expected Result: Error Raised for Over Receipt against SCO.
|
||||
"""
|
||||
from erpnext.subcontracting.doctype.subcontracting_order.subcontracting_order import (
|
||||
from erpnext.controllers.subcontracting_controller import (
|
||||
make_rm_stock_entry as make_subcontract_transfer_entry,
|
||||
)
|
||||
from erpnext.subcontracting.doctype.subcontracting_order.subcontracting_order import (
|
||||
@@ -188,8 +188,8 @@ class TestSubcontractingReceipt(FrappeTestCase):
|
||||
self.assertRaises(frappe.ValidationError, scr2.submit)
|
||||
|
||||
def test_subcontracted_scr_for_multi_transfer_batches(self):
|
||||
from erpnext.controllers.subcontracting_controller import make_rm_stock_entry
|
||||
from erpnext.subcontracting.doctype.subcontracting_order.subcontracting_order import (
|
||||
make_rm_stock_entry,
|
||||
make_subcontracting_receipt,
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user