Manufacturing process

Hi Hiousi,

The community is working together to enhance the manufacturing module. We will involve you in those discussions and you can influence the evolution of the manufacturing module.

Thanks

Jay

thank you @jayram. Note that I’m not from production, not a manufacturing specialist. I count on the software to help me adopt best practices. Tell me how I can participate.

For now, my idea was to move boxes of BOM items to the Work in Progress warehouse. I was thinking that a production order will simply pick in the WIP warehouse without asking to make a new Stock transfer for manufacture. Because the items are already available in the WIP to manufacture. But it does not work. The production order always makes a new material transfert.

If no one say I do bad, I must conclude that the problem is the design of the production order. @jayram when does the work to enchange the module will start?

I suppose a menu to submit by ticking documents in their list can be a great click saver, and a way to not wait for an improved manufacturing module.

How can we do that? a custom script? Can you give some directions?

@tara_antonius hey Anton, I’m testing your approach. I like it, it is smart.

1/ your first step, manual stock entry, transfer from RAW to WIP is quick if you transfer more items than you actualy need to serve pending orders. I mean, if you need 1x item A for an order, transfer a box with 100x item A (it is what we do in real life). Add all the production floor needs to that stock entry, or ask the production guys to register a stock tranfer when they pick up a box of materials.

2/ “mini production process” is a good idea. it saves lot of time. Only one stock entry for each item manufactured, avoiding the production order step. (idea: make this entry from a barcode scanner thru API?). DO not forget to set d source warehouse to WIP as your BOM may have RAW in it. if I could add multiples BOM to the REPACK entry it would be great!

I’m loosing the ability to have a report with a list of products to manufacture, and the link to the reference order. I can accomodate with that for now (I print the order on a real paper, sorry for the planet).

Waiting to take part of the work to improve the manufacturing module.

Hi Hiousi,

Would you please send me the Export of your Manufacturing entries for a day? Please include the BoM details as well if you can. I can send you my E-Mail ID if you don’t want to post it here.

The reason I’m asking is that I can almost visualise what your problem areas are, but looking at the data would make it easier for me to come up with a solution.

I have a feeling that everybody that is into any type of manufacturing will need a more elegant solution for managing this process.

Thanks

Jay

1 Like

@JayRam can not upload CSV here. Give me your email please.

jram at epochconsulting.in

@hiousi, hey glad to hear that,

it is not a normal production process but i think you can ease your problem with a lot of docs to submit.

I think STE document in ERPNEXT is really the “swis army knife of Inventory Process” as with STE you can have multiple WIP warehouse and do manual transfer of material from RM - Semi FG - FG in Simple Manufacturing process.

1/ barcode scanner is usually plug and play, you can use it directly on your computer to scan your barcode in item.
in STE document its also posible to input item needed from barcode scanner. we use that for material transfer, issue and receipt. you can use custom script so that the barcode column can be shown in editable grid or in V 7.1 you can already design the flexible editable grid.

  1. Multiple BOM in the repack it would be a great idea. I think i can use that too.
    but it would be nice if we can have prod order that we sort based on the similar items or BOM so we can have it on stock entry - manufacture.

  2. to link to your sales order, you can make customization in the STE and Sales to link the document to the Sales order.

  3. I think the idea of putting all similar item together for production is also a good idea, that would make less production order created and as also in the real condition, the same item would be processed at the same time

I like idea from @hiousi and @Ben_Cornwell_Mott

I think in the production planning tool there should be an addition/checklist so that we can choose to “create production order” process that you can “group production orders with item based on the same BOM or Item_code”. that would produce better manufacturing queue.

Thanks
Anton

1 Like

@tara_antonius you CAN make a STE of type “manufacture” without a production order (in the form production order is not mandatory)

My first custom script!
A button to help to fill quickly a Stock Entry with the @tara_antonius method of “mini production process”

frappe.ui.form.on("Stock Entry", "refresh", function(frm){

		frm.add_custom_button(__("Manufacture an Item"), function() {

		frappe.prompt({fieldtype: "Link", label: __("Select Item to manufacture"), fieldname:"item", options: "Item"},
					function(d) {
						if(!d) {
							return;
						}
						frappe.call({
							   'method': 'erpnext.stock.get_item_details.get_default_bom',
							   'args': {
							   		"item_code": cstr(d.item),
							   },
							   callback: function(r) {
							   		if(r.message) {

							   			frm.set_value("purpose", "Manufacture");
							   			frm.set_value("from_bom", true);
							   			frm.set_value("fg_completed_qty", 1);
                                                                            frm.set_value("title", "Manufacture "+ cstr(d.item));
							   			frm.set_value("bom_no", r.message);


										frappe.call({
											method: "erpnext.manufacturing.doctype.production_order.production_order.get_default_warehouse",
											callback: function(r) {
												if(!r.exc) {
													frm.set_value("from_warehouse", r.message.wip_warehouse);
													frm.set_value("to_warehouse", r.message.fg_warehouse);
													frm.call({
														doc: frm.doc,
														method: "get_items",
														callback: function(r) {
															if(!r.exc) refresh_field("items");
														 }                   
													});
												}
											}
										});

							   		} else {
							   			return;
							   		}

							   		
							   		
							   }
						});
		
						return;
					}, __("Select Item"), __("Make"));
		})	
	
});
4 Likes

@hiousi

Great its nice to see you made some improvements on the stock entry “mini production process”
I will try on your script and give you my feedback.

Thanks a lot, Good luck on your way of customizing erpnext.

Best regards
Anton

small improvementsof the button, now ask for quantity and save automatically.

frappe.ui.form.on("Stock Entry", "refresh", function(frm){

		frm.add_custom_button(__("Manufacture an Item"), function() {

			var fields = [];

			var dialog = new frappe.ui.Dialog({
						title: __("Manufacture item"),
						fields: [
							{fieldname: 'item', label: __('Item'), fieldtype: 'Link', options: 'Item'},
							{fieldname: 'qty', label: __('Quantity'), reqd: 1, default: 1, fieldtype: 'Float' },
						]
			});

			dialog.show();

			dialog.set_primary_action(__('Make'), function() {
				var values = dialog.get_values();
				if(!values) {
						return;
				}
				frappe.call({
							   'method': 'erpnext.stock.get_item_details.get_default_bom',
							   'args': {
							   		"item_code": cstr(values.item),
							   },
							   callback: function(r) {
							   		if(r.message) {

							   			frm.set_value("purpose", "Manufacture");
							   			frm.set_value("from_bom", true);
							   			frm.set_value("fg_completed_qty", values.qty);
							   			frm.set_value("bom_no", r.message);
							   			frm.set_value("title", "Manufacture "+ values.qty +" x "+ cstr(values.item));
							   			dialog.hide();
										frappe.call({
											method: "erpnext.manufacturing.doctype.production_order.production_order.get_default_warehouse",
											callback: function(r) {
												if(!r.exc) {
													frm.set_value("from_warehouse", r.message.wip_warehouse);
													frm.set_value("to_warehouse", r.message.fg_warehouse);
													frm.call({
														doc: frm.doc,
														method: "get_items",
														callback: function(r) {
															if(!r.exc) refresh_field("items");
															frm.save();
														 }                   
													});
												}
											}
										});

							   		} else {
							   			return;
							   		}

							   		
							   		
							   }
				});
			});
		});

	
	
});

I would like to build a list of items, taken from an order, filter the list with the ones that need to manufactured (they have BOM + are not already available in finished products stock), and loop trough them to make all of the manufacture stock entries.
Need to learn more. And if you can help :slight_smile:

2 Likes

In the latest version 7.1 the script gives the following error.

Traceback (most recent call last): File "/home/frappe/frappe-bench/apps/frappe/frappe/app.py", line 55, in application response = frappe.handler.handle() File "/home/frappe/frappe-bench/apps/frappe/frappe/handler.py", line 19, in handle execute_cmd(cmd) File "/home/frappe/frappe-bench/apps/frappe/frappe/handler.py", line 36, in execute_cmd ret = frappe.call(method, **frappe.form_dict) File "/home/frappe/frappe-bench/apps/frappe/frappe/__init__.py", line 890, in call return fn(*args, **newargs) File "/home/frappe/frappe-bench/apps/frappe/frappe/handler.py", line 67, in runserverobj frappe.desk.form.run_method.runserverobj(method, docs=docs, dt=dt, dn=dn, arg=arg, args=args) File "/home/frappe/frappe-bench/apps/frappe/frappe/desk/form/run_method.py", line 35, in runserverobj r = doc.run_method(method) File "/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py", line 654, in run_method out = Document.hook(fn)(self, *args, **kwargs) File "/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py", line 882, in composer return composed(self, method, *args, **kwargs) File "/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py", line 865, in runner add_to_return_value(self, fn(self, *args, **kwargs)) File "/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py", line 648, in fn = lambda self, *args, **kwargs: getattr(self, method)(*args, **kwargs) File "/home/frappe/frappe-bench/apps/erpnext/erpnext/stock/doctype/stock_entry/stock_entry.py", line 581, in get_items self.calculate_rate_and_amount() File "/home/frappe/frappe-bench/apps/erpnext/erpnext/stock/doctype/stock_entry/stock_entry.py", line 247, in calculate_rate_and_amount self.set_basic_rate(force, update_finished_item_rate) File "/home/frappe/frappe-bench/apps/erpnext/erpnext/stock/doctype/stock_entry/stock_entry.py", line 283, in set_basic_rate if not flt(d.basic_rate) and getattr(self, "pro_doc", frappe._dict()).scrap_warehouse == d.t_warehouse: AttributeError: 'NoneType' object has no attribute 'scrap_warehouse'

@reador do you have 7.1.15? I had this error too with 7.1.14. it is fixed now in 7.1.15

1 Like

Thats awesome @hiousi . I was waiting for a long time for this.

1 Like

I would like to build a list of items, taken from an order, filter the list with the ones that need to manufactured (they have BOM + are not already available in finished products stock), and loop trough them to make all of the manufacture stock entries.
Need to learn more. And if you can help :slight_smile:

@hiousi,
I think what you need is already provided with the production planning tool. The tool will check on sales order by project or customer or sales order and will look for item with BOM and if they are not ready then they will either create 1. Production order if product is ready, 2. Material request if raw material not ready.

what we can is maybe to make c.script to move all the result of the Prod Planning tool to STE for our “mini” process instead of following normal workflow for production process. As you know prod planning tool already calculate almost all except it throw to Prod Order and Material Request.
What do you think?

yes @tara_antonius oh yes can be great.

but:

  • The button “get items” get all items, even if there are available in finished product warehouse. We do not need to produce items that are already produced.
  • Production planning tool does not merge items to make production orders. If you have 10 orders, each with 10 item A, the tool will make 10 productions orders.

@tara_antonius Can you help in making a script that:

  • will check stock balance to see if an item is ready and does not need to be “mini manufactured”
  • will merge same items from differents orders in one STE.
  • all with the less clicks possible!

After 1 month using the “mini manufacturing process” I realize that it is far from being perfect. I think it’s a “trick”, and ErpNext is not really designed to work like that.

  • Even if it’s far quicker than the “production planning tool->production order->stock entry” process, my finger is tired of clicking for each lines of each orders… save/submit cycle…
  • there is a major drawback with the stock reports. If you do not use a production order you are unable to know how much of raw materials are “reserved/planned”

argg. So what? is there is some people here that use ErpNext to drive the manufacturing of more than some items per day?

@hiousi

Hi Hiousi,

Thanks for the feedback,
yes its a tiring manual process, we did not do a lot of item production thats why we don’t modify the erpnext for that.
Its just a trick to get the job done with less item to make, when it come to many things to produce i don’t think its that convenient.

I sugest is to make modified production planning tool as custom module, and do your material requirement and production planning from there, or we should ask the erpnext team to change that original module to cater your needs of:

  • will check stock balance to see if an item is ready and does not need to be manufacture.
  • will merge same items from differents orders in one STE.
  • all with the less clicks possible!

@komsel2228, bro do you think we can make custom module for the modified production planning tool for a better production process? as you know the production planning tool has some limitations as we discussed above?

Thanks and wish you all have a nice day

Anton

1 Like

Thought I’d add to this as I’m having similar issues. There is a method called get_production_items in the production planner tool that sets up the items to make production orders for. It also combines items that have the same item_code, sales_order and warehouse. To change it to only group items of same item_code you would modify this part. I think it’s fairly useful to be able to filter production orders by sales orders, which is why I haven’t done this.

""" Club similar BOM and item for processing in case of Sales Orders """
			if self.get_items_from == "Material Request":
				item_details.update({
					"qty": d.planned_qty
				})
				item_dict[d.item_code] = item_details

			else:
				item_details.update({
					"qty":flt(item_dict.get(d.item_code,{})
						.get("qty")) + flt(d.planned_qty)
				})
				item_dict[d.item_code] = item_details

You can also check stock balances for each item here. I’m using actual qty at the moment but I believe projected_qty would be more useful. The following finds each item entry that has enough stock balance (in all warehouses) and removes it.

                        remove = []
			for k in item_dict:
				balance_qty = 0


				stock_details = frappe.db.sql("select sum(actual_qty) from `tabBin` where item_code = (%s) group by item_code", item_dict[k]['production_item'])
				if stock_details:
					balance_qty = stock_details[0][0]

				if item_dict[k]['qty'] <= balance_qty:
					remove.append(k)
				else if balance_qty > 0:
					item_dict[k]['qty'] = flt(item_dict[k]['qty']) - flt(balance_qty)

			for k in remove:
				del item_dict[k]

I’m also working to automate the process a bit, but it requires using default values for source warehouse, wip warehouse and fg warehouse.

  1. Production planner tool submits the production orders and makes stock entries to transfer for manufacture as it makes each production order. These entries use a default source warehouse and wip warehouse.

  2. If material is in different warehouses each transfer stock entry has to be checked to choose the right warehouse. Definitely tedious, but if all material has the same default source warehouse this step can be skipped. This step can be automated a bit more by picking a source warehouse that has stock for the raw material item when the entry is created.

  3. Second button that gets all production orders based on criteria in planner (by sales order or material requests) and gets each transfer material for manufacture stock entry linked to it and submits it. Then makes and submits a manufacture stock entry. These entries use the default wip and fg warehouses.

I might have to make submitting the manufacture entry to another button. If a company has multiple wip or fg warehouses, they would need to modify each entry before submitting it.

Hello @Kar_M, I’ve tried to use your code but maybe I misplaced something, can you help me?

        """ Club similar BOM and item for processing in case of Sales Orders """
        if self.get_items_from == "Material Request":
            item_details.update({
                "qty": d.planned_qty
            })
            item_dict[(d.item_code, d.warehouse)] = item_details
        else:
            item_details.update({
                "qty":flt(item_dict.get((d.item_code, d.warehouse),{})
                    .get("qty")) + flt(d.planned_qty)
            })
            item_dict[(d.item_code, d.warehouse)] = item_details
                
        remove = []
        for k in item_dict:
            balance_qty < 0
            
            stock_details = frappe.db.sql("select sum(projected_qty) from `tabBin` where item_code = (%s) group by item_code", item_dict[k]['production_item'])
            if stock_details:
                balance_qty = stock_details[0][0]
            if item_dict[k]['qty'] <= balance_qty:
                remove.append(k)
                    elif balance_qty => 0:
                item_dict[k]['qty'] = flt(item_dict[k]['qty']) - flt(balance_qty)
            
                for k in remove:
                        del item_dict[k]
    return item_dict

I want to group all itens with the same code to one production order if the projected_qty is < 0

I think that the sales orders or the material requests should be stored in a table, to maintain reference like itens in several sales orders.