Stock Entry - Get Items from Purchase Invoice/Material Request: Adding allow_child_item_selection

Hello,

I have a use case where we need to select items from Purchase Invoice/Material Request while creating a new stock entry.

I added the following code in stock_entry.js from the example of Purchase Order>Get Items From>Material Request: https://github.com/frappe/erpnext/blob/develop/erpnext/buying/doctype/purchase_order/purchase_order.js

frm.add_custom_button(
				__("Material Request"),
				function () {
					const allowed_request_types = [
						"Material Transfer",
						"Material Issue",
						"Customer Provided",
					];
					const depends_on_condition = "eval:doc.material_request_type==='Customer Provided'";
					const d = erpnext.utils.map_current_doc({
						method: "erpnext.stock.doctype.material_request.material_request.make_stock_entry",
						source_doctype: "Material Request",
						target: frm,
						date_field: "schedule_date",
						setters: [
							{
								fieldtype: "Select",
								label: __("Purpose"),
								options: allowed_request_types.join("\n"),
								fieldname: "material_request_type",
								default: "Material Transfer",
								mandatory: 1,
								change() {
									if (this.value === "Customer Provided") {
										d.dialog.get_field("customer").set_focus();
									}
								},
							},
							{
								fieldtype: "Link",
								label: __("Customer"),
								options: "Customer",
								fieldname: "customer",
								depends_on: depends_on_condition,
								mandatory_depends_on: depends_on_condition,
							},
						],
						get_query_filters: {
							docstatus: 1,
							material_request_type: ["in", allowed_request_types],
							status: ["not in", ["Transferred", "Issued", "Cancelled", "Stopped"]],
						},
                    	allow_child_item_selection: true,
                    	child_fieldname: "items",
                    	child_columns: ["item_code", "qty", "custom_order_no"]
					});
				},
				__("Get Items From")
			);
		}

It is enabling the item selection option and items as well:

BUT, clicking on Get Items is generating error:

TypeError: make_stock_entry() takes from 1 to 2 positional arguments but 3 were given

Detail Error:

### App Versions

{
	"ecommerce_integrations": "1.17.0",
	"erpnext": "15.10.6",
	"erpnext_telegram_integration": "1.2.0",
	"frappe": "15.11.0",
	"hrms": "16.0.0-dev",
	"payments": "0.0.1",
}

### Route

Form/Stock Entry/new-stock-entry-ecnuwbvpdb
### Traceback

Traceback (most recent call last):
  File "apps/frappe/frappe/app.py", line 110, in application
    response = frappe.api.handle(request)
  File "apps/frappe/frappe/api/__init__.py", line 49, in handle
    data = endpoint(**arguments)
  File "apps/frappe/frappe/api/v1.py", line 36, in handle_rpc_call
    return frappe.handler.handle()
  File "apps/frappe/frappe/handler.py", line 49, in handle
    data = execute_cmd(cmd)
  File "apps/frappe/frappe/handler.py", line 85, in execute_cmd
    return frappe.call(method, **frappe.form_dict)
  File "apps/frappe/frappe/__init__.py", line 1682, in call
    return fn(*args, **newargs)
  File "apps/frappe/frappe/utils/typing_validations.py", line 31, in wrapper
    return func(*args, **kwargs)
  File "apps/frappe/frappe/model/mapper.py", line 53, in map_docs
    target_doc = method(*_args)
  File "apps/frappe/frappe/utils/typing_validations.py", line 31, in wrapper
    return func(*args, **kwargs)
TypeError: make_stock_entry() takes from 1 to 2 positional arguments but 3 were given

### Request Data
{
	"type": "POST",
	"args": {
		"method": "erpnext.stock.doctype.material_request.material_request.make_stock_entry",
		"source_names": "[\"MR-24-928\"]",
		"target_doc": "{\"docstatus\":0,\"doctype\":\"Stock Entry\",\"name\":\"new-stock-entry-ecnuwbvpdb\",\"__islocal\":1,\"__unsaved\":1,\"owner\":\"Administrator\",\"naming_series\":\"\",\"purpose\":\"Material Issue\",\"add_to_transit\":0,\"company\":\"Demo Ltd.\",\"posting_date\":\"2024-04-29\",\"set_posting_time\":0,\"inspection_required\":0,\"apply_putaway_rule\":0,\"from_warehouse\":\"Stores - DEMO\",\"to_warehouse\":\"Work In Progress - DEMO\",\"items\":[],\"from_bom\":0,\"use_multi_level_bom\":1,\"additional_costs\":[],\"letter_head\":\"EC Bottom Signature\",\"is_opening\":\"No\",\"is_return\":0,\"expense_account\":\"Stock Adjustment - ECKPL\",\"total_additional_costs\":0,\"posting_time\":\"19:49:45\",\"address_display\":null,\"purchase_receipt_no\":null,\"supplier_address\":null,\"supplier_name\":null,\"supplier\":null,\"sales_invoice_no\":null,\"delivery_note_no\":null,\"customer_address\":null,\"customer_name\":null,\"customer\":null}",
		"args": "{\"material_request_type\":\"Material Transfer\",\"allow_child_item_selection\":1,\"filtered_children\":[\"aba5db0600\"]}"
	},
	"freeze": true,
	"freeze_message": "Mapping Material Request ...",
	"headers": {},
	"error_handlers": {},
	"url": "/api/method/frappe.model.mapper.map_docs",
	"request_id": null
}

### Response Data

{
	"exception": "TypeError: make_stock_entry() takes from 1 to 2 positional arguments but 3 were given",
	"exc_type": "TypeError"
}

Got the same result by adding code in Get Items From Purchase Invoice section.
I will appreciate guidelines to solve it.

Anyone? Will appreciate any guideline. Thanks.

Hey Rapidweb just by curiosity?

Why from PINV/MATREQ → Stock Entry?

Usually, the “Stock Entry” already have “Get Items From → Material Request”

Hello @max_morais_dmm, as you can see that we need child item selection for both PINV/MATREQ which is not available right now. Besides, in MATREQ status, ‘Purchase’ is excluded for unknown reason which is our requirement too.

I found the following code (modified with custom field) in Purchase Order DocType to invoke> Get Items From> Material Request with child item selection:

allow_child_item_selection: true,
child_fieldname: “items”,
child_columns: [“item_code”, “qty”, “custom_order_no”]

While this codes work fine in purchase_order.js when I tried to add the code in stock_entry.js,
it shows the child item selection options with desired custom columns but with the above errors.

Someone pointed that the error: “TypeError: make_stock_entry() takes from 1 to 2 positional arguments but 3 were given” represents the 3 args given: source_names, target_docs and args. I am not adept in Python and looking for guidelines to solve it.

We have a use case where people create a single Project to make some product. Next, they create 5-10 MATREQUESTS for raw materials items of individual categories with ‘Purchase Request’ in material requests.
Later, they want to transfer the ordered and received items for that PROJECT to the floor where the final items are prepared. It is to create a simple workflow for a small manufacturing company and to avoid the complexity of creating BoM and Manufacturing process available in the software.

Now, they need to Get Items From MATREQUEST with item selection ability with custom fields like Project No./Order No. which is not present in the current versions.

Thanks!

@rapidweb why dont use the “Purchase Receipt” so?

MR to Buy → PO → Purchase Receipt → Target Stock
MR to Transfer → STE → Target Stock

Getting things from PO to Stock Entry, will create a big mess in the accounting if you didn’t really know what you are doing in terms of accounting, and how to properly solve those problems!

I really wish you have an experienced accountant support you with those decisions!

Hello @max_morais_dmm, I am not creating stock entries from PO but from the Purchase Receipt after completing the usual cycle:

MR to Buy (for Raw Materials tagged to Individual Sales Order received from the Customer) → PO → Purchase Receipt → Target Stock

Then Transfer the Stock to the WIP warehouse by filtering the items based on the Sales Order. I finally did it for Purchase Receipt (which is similar for MR or PI) with the help of someone experienced and code examples in Material Request for child table filtering.

JS code:

frappe.ui.form.on("Stock Entry", {
  refresh: function (frm) {
    if (frm.doc.docstatus === 0) {
      frm.add_custom_button(
        __("Purchase Receipt"),
        function () {
          erpnext.utils.map_current_doc({
            method:
              "erpnext.stock.doctype.purchase_receipt.purchase_receipt.make_stock_entry",
            source_doctype: "Purchase Receipt",
            target: frm,
            date_field: "posting_date",
            setters: {
              supplier: frm.doc.supplier || undefined,
            },
            get_query_filters: {
              docstatus: 1,
              status: ["not in", ["Closed", "Return Issued"]],
              company: frm.doc.company,
              is_return: 0,
            },
            allow_child_item_selection: true,
            child_fieldname: "items",
            child_columns: ["item_code", "qty", "custom_order_no"],
          });
        },
        __("Get Items From"),
      );
    }
  },
});

Server side Py (Monkey Patch):

@frappe.whitelist()
def make_stock_entry(source_name, target_doc=None, args=None):
	if args is None:
		args = {}
	if isinstance(args, str):
		args = json.loads(args)

	def set_missing_values(source, target):
		target.stock_entry_type = "Material Transfer"
		target.purpose = "Material Transfer for Manufacture"
		target.set_missing_values()

	def select_item(d):
		filtered_items = args.get("filtered_children", [])
		child_filter = d.name in filtered_items if filtered_items else True

		return child_filter

	doclist = get_mapped_doc(
		"Purchase Receipt",
		source_name,
		{
			"Purchase Receipt": {
				"doctype": "Stock Entry",
			},
			"Purchase Receipt Item": {
				"doctype": "Stock Entry Detail",
				"field_map": {
					"warehouse": "s_warehouse",
					"parent": "reference_purchase_receipt",
				},
				"condition": select_item,
			},
		},
		target_doc,
		set_missing_values,
	)

	return doclist

purchase_receipt.make_stock_entry = make_stock_entry

Thanks for your reply and helping others solving many issues.

I have another post regarding not linking all source doctype with this similar issue: Erpnext.utils.map_current_doc

I wonder, if you have any idea and can give advice.