mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-13 02:01:21 +00:00
Merge pull request #51305 from mihir-kandoi/gh45824
This commit is contained in:
@@ -460,6 +460,119 @@ frappe.ui.form.on("Subcontracting Order", {
|
||||
});
|
||||
},
|
||||
|
||||
make_subcontracting_receipt(this_obj) {
|
||||
const doc = this_obj.frm.doc;
|
||||
const has_overtransferred_items = doc.supplied_items.some((item) => {
|
||||
return item.supplied_qty > item.required_qty;
|
||||
});
|
||||
const backflush_based_on = doc.__onload.backflush_based_on;
|
||||
if (has_overtransferred_items && backflush_based_on === "BOM") {
|
||||
const raw_data = doc.supplied_items.map((item) => {
|
||||
const row = doc.items.find((i) => i.name === item.reference_name);
|
||||
const qty = flt(row.qty) - flt(row.received_qty);
|
||||
return {
|
||||
__checked: 1,
|
||||
item_code: row.item_code,
|
||||
warehouse: row.warehouse,
|
||||
bom_no: row.bom,
|
||||
required_by: row.schedule_date,
|
||||
qty: qty > 0 ? qty : null,
|
||||
subcontracting_order_item: row.name,
|
||||
};
|
||||
});
|
||||
const item_names_list = [];
|
||||
const data = [];
|
||||
raw_data.forEach((d) => {
|
||||
if (!item_names_list.includes(d.subcontracting_order_item)) {
|
||||
item_names_list.push(d.subcontracting_order_item);
|
||||
data.push(d);
|
||||
}
|
||||
});
|
||||
|
||||
const dialog = new frappe.ui.Dialog({
|
||||
title: __("Select Items"),
|
||||
size: "extra-large",
|
||||
fields: [
|
||||
{
|
||||
fieldname: "items",
|
||||
fieldtype: "Table",
|
||||
reqd: 1,
|
||||
label: __("Select Items to Receive"),
|
||||
cannot_add_rows: true,
|
||||
fields: [
|
||||
{
|
||||
fieldtype: "Link",
|
||||
fieldname: "item_code",
|
||||
reqd: 1,
|
||||
options: "Item",
|
||||
label: __("Item Code"),
|
||||
in_list_view: 1,
|
||||
read_only: 1,
|
||||
},
|
||||
{
|
||||
fieldtype: "Link",
|
||||
fieldname: "warehouse",
|
||||
options: "Warehouse",
|
||||
label: __("Warehouse"),
|
||||
in_list_view: 1,
|
||||
read_only: 1,
|
||||
reqd: 1,
|
||||
},
|
||||
{
|
||||
fieldtype: "Link",
|
||||
fieldname: "bom_no",
|
||||
options: "BOM",
|
||||
label: __("BOM"),
|
||||
in_list_view: 1,
|
||||
read_only: 1,
|
||||
reqd: 1,
|
||||
},
|
||||
{
|
||||
fieldtype: "Date",
|
||||
fieldname: "required_by",
|
||||
label: __("Required By"),
|
||||
in_list_view: 1,
|
||||
read_only: 1,
|
||||
reqd: 1,
|
||||
},
|
||||
{
|
||||
fieldtype: "Float",
|
||||
fieldname: "qty",
|
||||
reqd: 1,
|
||||
label: __("Qty to Receive"),
|
||||
in_list_view: 1,
|
||||
},
|
||||
{
|
||||
fieldtype: "Data",
|
||||
fieldname: "subcontracting_order_item",
|
||||
reqd: 1,
|
||||
label: __("Subcontracting Order Item"),
|
||||
hidden: 1,
|
||||
read_only: 1,
|
||||
in_list_view: 0,
|
||||
},
|
||||
],
|
||||
data: data,
|
||||
},
|
||||
],
|
||||
primary_action_label: __("Proceed"),
|
||||
primary_action: () => {
|
||||
const values = dialog.fields_dict["items"].grid
|
||||
.get_selected_children()
|
||||
.map((i) => ({ name: i.subcontracting_order_item, qty: i.qty }));
|
||||
if (values.some((i) => !i.qty || i.qty == 0)) {
|
||||
frappe.throw(__("Quantity is mandatory for the selected items."));
|
||||
} else {
|
||||
this_obj.make_subcontracting_receipt(values);
|
||||
}
|
||||
},
|
||||
});
|
||||
dialog.show();
|
||||
} else {
|
||||
this_obj.make_subcontracting_receipt();
|
||||
}
|
||||
},
|
||||
|
||||
company: function (frm) {
|
||||
erpnext.utils.set_letter_head(frm);
|
||||
},
|
||||
@@ -524,11 +637,11 @@ erpnext.buying.SubcontractingOrderController = class SubcontractingOrderControll
|
||||
var me = this;
|
||||
|
||||
if (doc.docstatus == 1) {
|
||||
if (!["Closed", "Completed"].includes(doc.status)) {
|
||||
if (flt(doc.per_received) < 100) {
|
||||
if (doc.status != "Closed") {
|
||||
if (flt(doc.per_received) < 100 + doc.__onload.over_delivery_receipt_allowance) {
|
||||
this.frm.add_custom_button(
|
||||
__("Subcontracting Receipt"),
|
||||
this.make_subcontracting_receipt,
|
||||
() => this.frm.events.make_subcontracting_receipt(this),
|
||||
__("Create")
|
||||
);
|
||||
if (me.has_unsupplied_items()) {
|
||||
@@ -576,10 +689,12 @@ erpnext.buying.SubcontractingOrderController = class SubcontractingOrderControll
|
||||
});
|
||||
}
|
||||
|
||||
make_subcontracting_receipt() {
|
||||
make_subcontracting_receipt(items) {
|
||||
frappe.model.open_mapped_doc({
|
||||
method: "erpnext.subcontracting.doctype.subcontracting_order.subcontracting_order.make_subcontracting_receipt",
|
||||
frm: cur_frm,
|
||||
args: { items: items || [] },
|
||||
freeze: true,
|
||||
freeze_message: __("Creating Subcontracting Receipt ..."),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -110,6 +110,14 @@ class SubcontractingOrder(SubcontractingController):
|
||||
"over_transfer_allowance",
|
||||
frappe.db.get_single_value("Buying Settings", "over_transfer_allowance"),
|
||||
)
|
||||
self.set_onload(
|
||||
"over_delivery_receipt_allowance",
|
||||
frappe.get_single_value("Stock Settings", "over_delivery_receipt_allowance"),
|
||||
)
|
||||
self.set_onload(
|
||||
"backflush_based_on",
|
||||
frappe.get_single_value("Buying Settings", "backflush_raw_materials_of_subcontract_based_on"),
|
||||
)
|
||||
|
||||
if self.reserve_stock:
|
||||
if self.has_unreserved_stock():
|
||||
@@ -464,16 +472,18 @@ class SubcontractingOrder(SubcontractingController):
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_subcontracting_receipt(source_name, target_doc=None):
|
||||
return get_mapped_subcontracting_receipt(source_name, target_doc)
|
||||
items = frappe.flags.args.get("items") if frappe.flags.args else None
|
||||
return get_mapped_subcontracting_receipt(source_name, target_doc, items=items)
|
||||
|
||||
|
||||
def get_mapped_subcontracting_receipt(source_name, target_doc=None):
|
||||
def get_mapped_subcontracting_receipt(source_name, target_doc=None, items=None):
|
||||
def update_item(source, target, source_parent):
|
||||
target.purchase_order = source_parent.purchase_order
|
||||
target.purchase_order_item = source.purchase_order_item
|
||||
target.qty = flt(source.qty) - flt(source.received_qty)
|
||||
target.qty = items.get(source.name) or (flt(source.qty) - flt(source.received_qty))
|
||||
target.amount = (flt(source.qty) - flt(source.received_qty)) * flt(source.rate)
|
||||
|
||||
items = {item["name"]: item["qty"] for item in items} if items else {}
|
||||
target_doc = get_mapped_doc(
|
||||
"Subcontracting Order",
|
||||
source_name,
|
||||
@@ -496,7 +506,9 @@ def get_mapped_subcontracting_receipt(source_name, target_doc=None):
|
||||
"bom": "bom",
|
||||
},
|
||||
"postprocess": update_item,
|
||||
"condition": lambda doc: abs(doc.received_qty) < abs(doc.qty),
|
||||
"condition": lambda doc: abs(doc.received_qty) < abs(doc.qty)
|
||||
if not items
|
||||
else doc.name in items,
|
||||
},
|
||||
},
|
||||
target_doc,
|
||||
|
||||
@@ -1890,6 +1890,36 @@ class TestSubcontractingReceipt(IntegrationTestCase):
|
||||
|
||||
self.assertRaises(BOMQuantityError, scr.submit)
|
||||
|
||||
@IntegrationTestCase.change_settings("Buying Settings", {"over_transfer_allowance": 20})
|
||||
@IntegrationTestCase.change_settings("Stock Settings", {"over_delivery_receipt_allowance": 20})
|
||||
def test_over_receipt(self):
|
||||
from erpnext.controllers.subcontracting_controller import make_rm_stock_entry
|
||||
|
||||
set_backflush_based_on("BOM")
|
||||
|
||||
sco = get_subcontracting_order()
|
||||
rm_items = get_rm_items(sco.supplied_items)
|
||||
itemwise_details = make_stock_in_entry(rm_items=rm_items)
|
||||
make_stock_transfer_entry(
|
||||
sco_no=sco.name,
|
||||
rm_items=rm_items,
|
||||
itemwise_details=copy.deepcopy(itemwise_details),
|
||||
)
|
||||
|
||||
rm_items[0]["qty"] = 2
|
||||
itemwise_details = make_stock_in_entry(rm_items=rm_items)
|
||||
ste_dict = make_rm_stock_entry(sco.name)
|
||||
doc = frappe.get_doc(ste_dict)
|
||||
self.assertEqual(doc.items[0].qty, 0)
|
||||
doc.items[0].qty = 2
|
||||
doc.submit()
|
||||
|
||||
frappe.flags["args"] = {"items": [{"name": sco.items[0].name, "qty": 2}]}
|
||||
scr = make_subcontracting_receipt(sco.name)
|
||||
self.assertEqual(scr.items[0].qty, 2)
|
||||
scr.submit()
|
||||
frappe.flags["args"].pop("items", None)
|
||||
|
||||
|
||||
def make_return_subcontracting_receipt(**args):
|
||||
args = frappe._dict(args)
|
||||
|
||||
Reference in New Issue
Block a user