Setting Batch for existing items

We want to assign batch numbers for certain items that already exist and have transactions already. Now, we want to start assigning batch number for future transactions for those items, but system doesn’t allow. Is there a way to circumvent this problem?

Hello,

You cannot set item as a Batch item midway. Please create new Batch Item and create Batch IDs for it.

Hi, I see it as a recurrent request for many years to allow changing the “Has Batch No” after the item creation.
It is very inconvenient to create a new item to change this status as there are so many transactions built on top of a certain item (inventory, accounting, production, sales and purchase records, etc…) and creating a new item would just erase the “history” of it.

Is it absolutely impossible to create a solution for this?

1 Like

Kindly send solution to this query (I have same challenge). [quote=“tecnofoodmx, post:3, topic:16054”]
changing the “Has Batch No” after the item creation.
It is very inconvenient to create a new item to change this status as there are so many transactions built on top of a certain item (inventory, accounting, production, sales and purchase records, etc…)
[/quote]

That depends on your particular business and technical requirements?

For example to map out your problem, start with prospective workarounds like this Enabling batch numbers after making stock entries - #3 by dhananjay

Thanks for your reply @clarkej

But, for our business, that solution would require major administrative efforts and the loss of traceability in termos of purchasing and sales.

A solution which might enable to have batch on existing items would be ideal.

We have the same problem!

Dear All,
i solved this problem easily as below : (Use carefully and only if you know what you are doing)

First create a custom app with any name with a single DocType
then create a button field named convert_non_batch_to_has_batch
Second use the below code for client-side

frappe.ui.form.on('Infinity', {
	refresh: function(frm) {

	},
	convert_non_batch_to_has_batch: function(frm){
		handle_convert_non_batch_to_has_batch(frm);
	}
});


var handle_convert_non_batch_to_has_batch = function(frm){
	frappe.warn('Are you sure you want to proceed?',
				'This is a low level procedure and may harm your data if misused!!',
				() => {
					// action to perform if Continue is selected
					frappe.prompt([
						{
							label: 'Item Group',
							fieldname: 'item_group',
							fieldtype: 'Link',
							options: 'Item Group'
						},
						{
							label: 'Batch Number Series',
							fieldname: 'batch_number_series',
							fieldtype: 'Data'
						}
					], (values) => {
						var group = values.item_group;
						var series = values.batch_number_series;
						frappe.call({
                            method: "ifp.ifp_utils.get_items_without_has_batch_in_item_group",
                            args: {
                                group: group,
								series: series
                            },
                            callback: function(res){
                                if (res && res.message){
									frappe.confirm('Are you sure you want to proceed with ' + res.message +' items in '+ group + ' Group?',
    									() => {
        										// action to perform if Yes is selected
												frappe.call({
													method: "ifp.ifp_utils.handle_convert_non_batch_to_has_batch",
													args: {
														group: group,
														series: series
													},
													callback: function(res){
														if (res && res.message){
															frappe.msgprint('Successfully processed '+ res.message +' Items.');
														}
													}
												});
    									}, () => {
        										// action to perform if No is selected
    									}
									)
								}
							}
						});
					})
				},
				'Continue',
					//true // Sets dialog as minimizable
				)
}

Third use the below code for server-side

from __future__ import unicode_literals
from frappe import publish_progress
import frappe
import json


@frappe.whitelist()
def get_items_without_has_batch_in_item_group(group, series):
    if not group or not series:
        return 0
    counter = 0
    for item in frappe.db.get_list('Item', filters={'item_group': group, 'has_batch_no': 0}, fields=['item_code', 'item_name'], order_by='item_code', as_list=False):
        counter+=1
    return counter

def set_item_batch_properities(item_code, series):
    frappe.db.set_value('Item', item_code, {
        'has_batch_no': 1,
        'create_new_batch': 1,
        'batch_number_series': series
    })

def create_new_batch(item_code):
    batch_no = frappe.get_doc(dict(
	    doctype='Batch',
		item=item_code)).insert().name
    
    return batch_no

def update_stock_ledger(item_code):
    batch_no =''
    size = len(frappe.db.get_list('Stock Ledger Entry', filters={'item_code': item_code}, fields=['name', 'actual_qty', 'qty_after_transaction', 'voucher_type', 'voucher_detail_no', 'voucher_no'], order_by='name', as_list=False))
    if size > 0:
        batch_no = create_new_batch(item_code)
        for entry in frappe.db.get_list('Stock Ledger Entry', filters={'item_code': item_code}, fields=['name', 'actual_qty', 'qty_after_transaction', 'voucher_type', 'voucher_detail_no', 'voucher_no'], order_by='name', as_list=False):
            frappe.db.set_value('Stock Ledger Entry', entry.name, {
                'batch_no': batch_no
            })
            if entry.voucher_type == 'Stock Reconciliation':
                srd = frappe.get_doc('Stock Reconciliation', entry.voucher_no)
                if srd.purpose == 'Opening Stock' and entry.actual_qty == 0:
                    frappe.db.set_value('Stock Ledger Entry', entry.name, {
                        'actual_qty': entry.qty_after_transaction
                })      

         


@frappe.whitelist()
def handle_convert_non_batch_to_has_batch(group, series):
    if not group or not series:
        return 0
    counter = 0
    size = len(frappe.db.get_list('Item', filters={'item_group': group, 'has_batch_no': 0}, fields=['item_code', 'item_name'], order_by='item_code', as_list=False))
    for item in frappe.db.get_list('Item', filters={'item_group': group, 'has_batch_no': 0}, fields=['item_code', 'item_name'], order_by='item_code', as_list=False):
        if counter > -1:
            set_item_batch_properities(item.item_code, series)
            update_stock_ledger(item.item_code)
            counter+=1
            
            progress = counter / size * 100
            frappe.publish_progress(float(counter*100)/size, title = "Processing Items...")
    
    
    return counter
2 Likes

Hi @ahmedfme ,
The above solution will create only one batch for the existing quantity. but I want to update batch numbers for all the inward and outward existing transactions. Is there any way to update that?

Thanks.