batch item distribution by oldest, serial no check

This commit is contained in:
pratu16x7 2017-05-18 11:46:09 +05:30
parent 60944e3397
commit e4e00d2215
3 changed files with 227 additions and 155 deletions

View File

@ -14,6 +14,7 @@
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -39,12 +40,13 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -76,6 +78,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -105,6 +108,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -136,6 +140,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -164,6 +169,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -194,6 +200,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -223,6 +230,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -253,6 +261,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -281,6 +290,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -311,6 +321,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -341,6 +352,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -369,6 +381,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -412,8 +425,8 @@
"issingle": 0,
"istable": 0,
"max_attachments": 5,
"modified": "2017-04-20 03:22:19.888058",
"modified_by": "Administrator",
"modified": "2017-05-21 21:00:11.096038",
"modified_by": "prateeksha@erpnext.com",
"module": "Stock",
"name": "Batch",
"owner": "harshada@webnotestech.com",

View File

@ -66,13 +66,14 @@ def get_batch_qty(batch_no=None, warehouse=None, item_code=None):
return out
@frappe.whitelist()
def get_oldest_batch_qty(item_code, warehouse):
def get_batches_by_oldest(item_code, warehouse):
'''Returns the oldest batch and qty for the given item_code and warehouse'''
batches = get_batch_qty(item_code = item_code, warehouse = warehouse)
oldest_date = min([frappe.get_value('Batch', batch.batch_no, 'expiry_date') for batch in batches])
for batch in batches:
if (frappe.get_value('Batch', batch.batch_no, 'expiry_date') == oldest_date):
return batch
batches_dates = [[batch, frappe.get_value('Batch', batch.batch_no, 'expiry_date')] for batch in batches]
batches_dates.sort(key=lambda tup: tup[1])
sorted_batches = [tup[0] for tup in batches_dates]
return sorted_batches
@frappe.whitelist()
def split_batch(batch_no, item_code, warehouse, qty, new_batch_id = None):
@ -132,10 +133,4 @@ def get_batch_no(item_code, warehouse, qty):
frappe.msgprint(_('Please select a Batch for Item {0}. Unable to find a single batch that fulfills this requirement').format(frappe.bold(item_code)))
if throw: raise UnableToSelectBatchError
# oldest_expiry_date = min([batch.expiry_date for batch in batches])
# for batch in batches:
# if batch.expiry_date == oldest_expiry_date:
# batch_no = batch.batch_no
return batch_no

View File

@ -76,7 +76,7 @@ frappe.ui.form.on('Stock Entry', {
frm.fields_dict.items.grid.refresh();
frm.cscript.toggle_related_fields(frm.doc);
},
validate: function(frm) {
after_save: function(frm) {
erpnext.select_batch_and_serial_no(frm);
},
company: function(frm) {
@ -547,6 +547,63 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
});
erpnext.select_batch_and_serial_no = (frm) => {
let get_warehouse = (item) => {
return cstr(item.s_warehouse) ? cstr(item.s_warehouse) : cstr(item.t_warehouse);
}
let show_modal_with_oldest_batch = (item, item_code, total_qty, warehouse, has_batch) => {
frappe.call({
method: 'erpnext.stock.doctype.batch.batch.get_batches_by_oldest',
args: {
warehouse: warehouse,
item_code: item_code
},
callback: (r) => {
if (r.message) {
batch_rows_by_oldest = [];
if(cstr(item.s_warehouse)) {
qty = total_qty;
for(var i = 0; i < r.message.length; i++) {
batch_row = {name: 'batch 1'};
batch_row.batch_no = r.message[i].batch_no;
batch_row.available_qty = r.message[i].qty;
if (parseInt(qty) <= parseInt(r.message[i].qty)) {
batch_row.selected_qty = qty;
batch_rows_by_oldest.push(batch_row);
break;
} else {
batch_row.selected_qty = r.message[i].qty;
qty -= r.message[i].qty;
batch_rows_by_oldest.push(batch_row);
}
}
}
erpnext.show_batch_serial_modal(frm, item, item_code, total_qty, warehouse, has_batch, batch_rows_by_oldest);
}
}
});
}
frm.doc.items.forEach(function(d) {
if(d.has_batch_no && !d.batch_no) {
show_modal_with_oldest_batch(d, d.item_code, d.qty, get_warehouse(d), 1);
} else if(d.has_serial_no && !d.serial_no) {
erpnext.show_batch_serial_modal(frm, d, d.item_code, d.qty, get_warehouse(d), 0);
}
});
}
erpnext.show_batch_serial_modal = (frm, item, item_code, qty, warehouse, has_batch, oldest = undefined) => {
let data = oldest ? oldest : []
let title = "";
let fields = [
{fieldname: 'item_code', read_only: 1, fieldtype:'Link', options: 'Item',
label: __('Item Code'), 'default': item_code},
{fieldtype:'Column Break'},
{fieldname: 'qty', read_only: 1, fieldtype:'Float', label: __('Qty'), 'default': qty},
];
let set_available_qty = (item_code, batch_no, warehouse, field) => {
frappe.call({
@ -565,26 +622,10 @@ erpnext.select_batch_and_serial_no = (frm) => {
});
}
let get_warehouse = (i) => {
// console.log("i", i);
// console.log("cstr(i.s_warehouse) || cstr(i.t_warehouse)", cstr(i.s_warehouse) || cstr(i.t_warehouse));
return cstr(i.s_warehouse) ? cstr(i.s_warehouse) : cstr(i.t_warehouse);
}
// console.log("available_qty", get_available_qty("_Test FG Item", 'tfi', 'Stores - A'));
// get_warehouse();
let show_modal = (item, item_code, qty, warehouse, has_batch, has_serial, oldest = undefined) => {
let data = oldest ? [oldest] : []
let fields = [
{fieldname: 'item_code', read_only: 1, fieldtype:'Link', options: 'Item',
label: __('Item Code'), 'default': item_code},
{fieldtype:'Column Break'},
{fieldname: 'qty', fieldtype:'Float', label: __('Qty'), 'default': qty},
{fieldtype:'Section Break'}
];
if(has_batch) {
fields.push(
title = __("Select Batch Numbers");
fields = fields.concat([
{fieldtype:'Section Break', label: __('Batch No')},
{fieldname: 'batches', fieldtype: 'Table',
fields: [
{fieldtype:'Link', fieldname:'batch_no', options: 'Batch',
@ -600,38 +641,70 @@ erpnext.select_batch_and_serial_no = (frm) => {
get_data: function() {
return this.data;
},
bind_events: function(grid) {
on_setup: function(grid) {
var me = this;
grid.wrapper.on('change', 'input[data-fieldname="batch_no"]', function(e) {
let $row = $(this).closest('.grid-row');
let name = $row.attr('data-name');
let row = grid.grid_rows_by_docname[name];
// console.log("bind changed: ", $(this), name, row.doc.batch_no, row.doc.idx);
// console.log(grid.grid_rows_by_docname);
row.on_grid_fields[2].set_value('0');
row.on_grid_fields[2].$input.trigger('change');
set_available_qty(item_code, row.doc.batch_no, warehouse, row.on_grid_fields[1]);
});
}
});
}
if(has_serial) {
fields.push(
{fieldname: 'serial_no', fieldtype: 'Small Text', label: __('Serial No')}
)
]);
} else {
title = __("Select Serial Numbers");
fields = fields.concat([
{fieldtype: 'Section Break', label: __('Serial No')},
{
fieldtype: 'Link', fieldname: 'serial_no_select', options: 'Serial No',
label: __('Select'),
get_query: function(doc) {
return { filters: {item_code: item_code}};
}
},
{fieldtype: 'Column Break'},
{fieldname: 'serial_no', fieldtype: 'Small Text'}
])
}
let dialog = new frappe.ui.Dialog({
title: __("Select Batches"),
title: title,
fields: fields
});
let serial_no_link = dialog.fields_dict.serial_no_select;
if(serial_no_link) {
serial_no_link.$input.on('change', function(e) {
let serial_no_list = dialog.fields_dict.serial_no;
if(serial_no_link.get_value()) {
let new_line = '\n';
if(!serial_no_list.get_value()) {
new_line = '';
}
serial_no_list.set_value(serial_no_list.get_value() + new_line + serial_no_link.get_value());
serial_no_link.$input.val('');
serial_no_link.set_value('');
}
});
}
item_temp = {};
Object.assign(item_temp, item);
delete item_temp['batch_no'];
delete item_temp['qty'];
delete item_temp['idx'];
let validate_dialog_values = () => {
var values = dialog.get_values();
let validate_batch_dialog = (values) => {
var sum = 0;
values.batches.map((batch) => {
sum += parseInt(batch.selected_qty);
if(batch.batch_no && batch.selected_qty) {
if (parseInt(batch.selected_qty) > parseInt(batch.available_qty)) {
if(parseInt(batch.selected_qty) > parseInt(batch.available_qty)
&& cstr(item.s_warehouse)) {
frappe.throw(__("Cannot select more than the available qty"));
return false;
}
@ -647,16 +720,26 @@ erpnext.select_batch_and_serial_no = (frm) => {
});
// validate total_qty
if(sum > values.qty) {
frappe.confirm(__(`Total of selected quantities is greater than the previously
set item quantity. Update?`), function(){
return true;
});
} else if (sum < values.qty){
frappe.confirm(__(`Total of selected quantities is less than the previously
set item quantity. Update?`), function(){
return true;
});
} else {
return true;
}
dialog.set_primary_action(__('Get Items'), function() {
if (!validate_dialog_values()) {
return;
}
let set_batched_items = () => {
var values = dialog.get_values();
if(!validate_batch_dialog(values)) {
return;
}
values.batches.map((batch, i) => {
if(i === 0) {
@ -664,64 +747,45 @@ erpnext.select_batch_and_serial_no = (frm) => {
item.qty = batch.selected_qty;
console.log("item", item, frm.doc.items);
} else {
var row = frappe.model.add_child(frm.doc, "Stock Entry Detail", "items");
var row = frm.add_child("items");
Object.assign(row, item_temp);
row.idx = i+1;
console.log("item", item_temp);
row.item_code = item_temp.item_code;
row.batch_no = batch.batch_no;
row.qty = batch.selected_qty;
console.log("row", row, frm.doc.items);
}
refresh_field("items");
});
}
let validate_serial_no_dialog = (values) => {
var serial_nos = values.serial_no || '';
if (!serial_nos || !serial_nos.replace(/\s/g, '').length) {
frappe.throw(__("Please enter serial numbers"));
return false;
}
return true;
}
let set_serialized_items = () => {
var values = dialog.get_values();
if (!validate_serial_no_dialog(values)) {
return;
}
item.serial_no = values.serial_no;
}
dialog.set_primary_action(__('Get Items'), function() {
if(has_batch) {
set_batched_items();
} else {
set_serialized_items();
}
refresh_field("items");
dialog.hide();
})
dialog.show();
}
// show_modal("_Test FG Item", 10, 'Stores - A', 1, 0);
let show_modal_with_oldest_batch = (item, item_code, qty, warehouse, has_batch, has_serial_no) => {
frappe.call({
method: 'erpnext.stock.doctype.batch.batch.get_oldest_batch_qty',
args: {
warehouse: warehouse,
item_code: item_code
},
callback: (r) => {
if (r.message) {
oldest = {name: 'batch 1'};
oldest.batch_no = r.message.batch_no;
oldest.available_qty = r.message.qty;
// if required overall qty is less than available qty in oldest batch, preselect
if (parseInt(qty) < parseInt(r.message.qty)) {
oldest.selected_qty = qty;
}
show_modal(item, item_code, qty, warehouse, has_batch, has_serial_no, oldest);
}
}
});
}
frm.doc.items.forEach(function(d){
if(d.has_batch_no && !d.batch_no) {
console.log("item code, ");
}
});
frm.doc.items.forEach(function(d) {
if(d.has_batch_no && !d.batch_no) {
// console.log(d.item_code, get_warehouse(d));
show_modal_with_oldest_batch(d, d.item_code, d.qty, get_warehouse(d), 1, 0);
// show_modal(d, d.item_code, d.qty, get_warehouse(d), 1, 0 , oldest);
}
if(d.has_serial_no && !d.serial_no) {
show_modal(d, d.item_code, d.qty, get_warehouse(d), 0, 1);
}
});
}