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?
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
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.