Merge pull request #17249 from scmmishra/auto-fetch-serial
feat: Auto fetch serial numbers
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index fb4f350..6860d6a 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -58,43 +58,9 @@
.css({"margin-bottom": "10px", "margin-top": "10px"})
.appendTo(grid_row.grid_form.fields_dict.serial_no.$wrapper));
+ var me = this;
$btn.on("click", function() {
- var d = new frappe.ui.Dialog({
- title: __("Add Serial No"),
- fields: [
- {
- "fieldtype": "Link",
- "fieldname": "serial_no",
- "options": "Serial No",
- "label": __("Serial No"),
- "get_query": function () {
- return {
- filters: {
- item_code:grid_row.doc.item_code,
- warehouse:cur_frm.doc.is_return ? null : grid_row.doc.warehouse
- }
- }
- }
- },
- {
- "fieldtype": "Button",
- "fieldname": "add",
- "label": __("Add")
- }
- ]
- });
-
- d.get_input("add").on("click", function() {
- var serial_no = d.get_value("serial_no");
- if(serial_no) {
- var val = (grid_row.doc.serial_no || "").split("\n").concat([serial_no]).join("\n");
- grid_row.grid_form.fields_dict.serial_no.set_model_value(val.trim());
- }
- d.hide();
- return false;
- });
-
- d.show();
+ me.show_serial_batch_selector(grid_row.frm, grid_row.doc);
});
}
});
diff --git a/erpnext/public/js/utils/serial_no_batch_selector.js b/erpnext/public/js/utils/serial_no_batch_selector.js
index b94cdd8..b22d5ca 100644
--- a/erpnext/public/js/utils/serial_no_batch_selector.js
+++ b/erpnext/public/js/utils/serial_no_batch_selector.js
@@ -5,12 +5,11 @@
this.show_dialog = show_dialog;
// frm, item, warehouse_details, has_batch, oldest
let d = this.item;
-
- // Don't show dialog if batch no or serial no already set
- if(d && d.has_batch_no && (!d.batch_no || this.show_dialog)) {
+ if (d && d.has_batch_no && (!d.batch_no || this.show_dialog)) {
this.has_batch = 1;
this.setup();
- } else if(d && d.has_serial_no && (!d.serial_no || this.show_dialog)) {
+ // !(this.show_dialog == false) ensures that show_dialog is implictly true, even when undefined
+ } else if(d && d.has_serial_no && !(this.show_dialog == false)) {
this.has_batch = 0;
this.setup();
}
@@ -68,13 +67,41 @@
{
fieldname: 'qty',
fieldtype:'Float',
- read_only: 1,
+ read_only: me.has_batch,
label: __(me.has_batch ? 'Total Qty' : 'Qty'),
default: 0
},
+ {
+ fieldname: 'auto_fetch_button',
+ fieldtype:'Button',
+ hidden: me.has_batch,
+ label: __('Fetch based on FIFO'),
+ click: () => {
+ let qty = this.dialog.fields_dict.qty.get_value();
+ let numbers = frappe.call({
+ method: "erpnext.stock.doctype.serial_no.serial_no.auto_fetch_serial_number",
+ args: {
+ qty: qty,
+ item_code: me.item_code,
+ warehouse: me.warehouse_details.name
+ }
+ });
+
+ numbers.then((data) => {
+ let auto_fetched_serial_numbers = data.message;
+ let records_length = auto_fetched_serial_numbers.length;
+ if (records_length < qty) {
+ frappe.msgprint(`Fetched only ${records_length} serial numbers.`);
+ }
+ let serial_no_list_field = this.dialog.fields_dict.serial_no;
+ numbers = auto_fetched_serial_numbers.join('\n');
+ serial_no_list_field.set_value(numbers);
+ });
+ }
+ }
];
- if(this.has_batch) {
+ if (this.has_batch) {
title = __("Select Batch Numbers");
fields = fields.concat(this.get_batch_fields());
} else {
@@ -87,6 +114,10 @@
fields: fields
});
+ if (this.item.serial_no) {
+ this.dialog.fields_dict.serial_no.set_value(this.item.serial_no);
+ }
+
this.dialog.set_primary_action(__('Insert'), function() {
me.values = me.dialog.get_values();
if(me.validate()) {
@@ -234,7 +265,7 @@
var me = this;
return [
{fieldtype:'Section Break', label: __('Batches')},
- {fieldname: 'batches', fieldtype: 'Table',
+ {fieldname: 'batches', fieldtype: 'Table', label: __('Batch Entries'),
fields: [
{
fieldtype:'Link',
@@ -343,10 +374,10 @@
var me = this;
this.serial_list = [];
return [
- {fieldtype: 'Section Break', label: __('Serial No')},
+ {fieldtype: 'Section Break', label: __('Serial Numbers')},
{
fieldtype: 'Link', fieldname: 'serial_no_select', options: 'Serial No',
- label: __('Select'),
+ label: __('Select to add Serial Number.'),
get_query: function() {
return { filters: {item_code: me.item_code, warehouse: me.warehouse_details.name}};
},
@@ -383,6 +414,7 @@
{
fieldname: 'serial_no',
fieldtype: 'Small Text',
+ label: __(me.has_batch ? 'Selected Batch Numbers' : 'Selected Serial Numbers'),
onchange: function() {
me.serial_list = this.get_value()
.replace(/\n/g, ' ').match(/\S+/g) || [];
diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py
index cb1d153..c1aef95 100644
--- a/erpnext/stock/doctype/serial_no/serial_no.py
+++ b/erpnext/stock/doctype/serial_no/serial_no.py
@@ -459,3 +459,13 @@
serial_nos = '\n'.join(dn_serial_nos)
return serial_nos
+
+@frappe.whitelist()
+def auto_fetch_serial_number(qty, item_code, warehouse):
+ serial_numbers = frappe.get_list("Serial No", filters={
+ "item_code": item_code,
+ "warehouse": warehouse,
+ "delivery_document_no": "",
+ "sales_invoice": ""
+ }, limit=qty, order_by="creation")
+ return [item['name'] for item in serial_numbers]