Merge branch 'develop' into feat-picklist-scan
diff --git a/erpnext/public/js/utils/barcode_scanner.js b/erpnext/public/js/utils/barcode_scanner.js
index f72b85c..51ee680 100644
--- a/erpnext/public/js/utils/barcode_scanner.js
+++ b/erpnext/public/js/utils/barcode_scanner.js
@@ -10,6 +10,9 @@
this.serial_no_field = opts.serial_no_field || "serial_no";
this.batch_no_field = opts.batch_no_field || "batch_no";
this.qty_field = opts.qty_field || "qty";
+ this.max_qty_field = opts.max_qty_field || null;
+ this.dont_allow_new_row = opts.dont_allow_new_row;
+ this.prompt_qty = opts.prompt_qty;
this.items_table_name = opts.items_table_name || "items";
this.items_table = this.frm.doc[this.items_table_name];
@@ -72,6 +75,15 @@
}
if (!row) {
+ if (this.dont_allow_new_row) {
+ frappe.show_alert({
+ message: __("Maximum quantity scanned for item {0}.", [item_code]),
+ indicator: "red"
+ });
+ this.clean_up();
+ return;
+ }
+
// add new row if new item/batch is scanned
row = frappe.model.add_child(this.frm.doc, cur_grid.doctype, this.items_table_name);
// trigger any row add triggers defined on child table.
@@ -83,9 +95,10 @@
return;
}
- this.show_scan_message(row.idx, row.item_code);
this.set_selector_trigger_flag(row, data);
- this.set_item(row, item_code);
+ this.set_item(row, item_code).then(qty => {
+ this.show_scan_message(row.idx, row.item_code, qty);
+ });
this.set_serial_no(row, serial_no);
this.set_batch_no(row, batch_no);
this.set_barcode(row, barcode);
@@ -106,9 +119,23 @@
}
set_item(row, item_code) {
- const item_data = { item_code: item_code };
- item_data[this.qty_field] = (row[this.qty_field] || 0) + 1;
- frappe.model.set_value(row.doctype, row.name, item_data);
+ return new Promise(resolve => {
+ const increment = (value = 1) => {
+ const item_data = {item_code: item_code};
+ item_data[this.qty_field] = Number((row[this.qty_field] || 0)) + Number(value);
+ frappe.model.set_value(row.doctype, row.name, item_data);
+ };
+
+ if (this.prompt_qty) {
+ frappe.prompt(__("Please enter quantity for item {0}", [item_code]), ({value}) => {
+ increment(value);
+ resolve(value);
+ });
+ } else {
+ increment();
+ resolve();
+ }
+ });
}
set_serial_no(row, serial_no) {
@@ -137,12 +164,12 @@
}
}
- show_scan_message(idx, exist = null) {
+ show_scan_message(idx, exist = null, qty = 1) {
// show new row or qty increase toast
if (exist) {
frappe.show_alert(
{
- message: __("Row #{0}: Qty increased by 1", [idx]),
+ message: __("Row #{0}: Qty increased by {1}", [idx, qty]),
indicator: "green",
},
5
@@ -182,7 +209,11 @@
get_row_to_modify_on_scan(item_code) {
// get an existing item row to increment or blank row to modify
- const existing_item_row = this.items_table.find((d) => d.item_code === item_code);
+ const existing_item_row = this.items_table.filter((d) => {
+ const [qty, max_qty] = [d[this.qty_field], d[this.max_qty_field] || null];
+ return d.item_code === item_code && ((max_qty === null) || (qty < max_qty));
+ }).splice(0, 1).pop();
+
return existing_item_row || this.get_existing_blank_row();
}
diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js
index 13b74b5..82663e3 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.js
+++ b/erpnext/stock/doctype/pick_list/pick_list.js
@@ -158,6 +158,18 @@
get_query_filters: get_query_filters
});
});
+ },
+ scan_barcode: (frm) => {
+ const opts = {
+ frm,
+ items_table_name: 'locations',
+ qty_field: 'picked_qty',
+ max_qty_field: 'qty',
+ dont_allow_new_row: true,
+ prompt_qty: frm.doc.prompt_qty
+ };
+ const barcode_scanner = new erpnext.utils.BarcodeScanner(opts);
+ barcode_scanner.process_scan();
}
});
diff --git a/erpnext/stock/doctype/pick_list/pick_list.json b/erpnext/stock/doctype/pick_list/pick_list.json
index e984c08..28cd5df 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.json
+++ b/erpnext/stock/doctype/pick_list/pick_list.json
@@ -17,6 +17,11 @@
"parent_warehouse",
"get_item_locations",
"section_break_6",
+ "scan_barcode",
+ "column_break_13",
+ "scan_mode",
+ "prompt_qty",
+ "section_break_15",
"locations",
"amended_from",
"print_settings_section",
@@ -126,11 +131,38 @@
"fieldtype": "Check",
"label": "Group Same Items",
"print_hide": 1
+ },
+ {
+ "fieldname": "section_break_15",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "scan_barcode",
+ "fieldtype": "Data",
+ "label": "Scan Barcode",
+ "options": "Barcode"
+ },
+ {
+ "fieldname": "column_break_13",
+ "fieldtype": "Column Break"
+ },
+ {
+ "default": "0",
+ "description": "If checked, picked qty won't automatically be fulfilled on submit of pick list.",
+ "fieldname": "scan_mode",
+ "fieldtype": "Check",
+ "label": "Scan Mode"
+ },
+ {
+ "default": "0",
+ "fieldname": "prompt_qty",
+ "fieldtype": "Check",
+ "label": "Prompt Qty"
}
],
"is_submittable": 1,
"links": [],
- "modified": "2022-04-21 07:56:40.646473",
+ "modified": "2022-05-05 09:50:36.252445",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List",
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index 70d2f23..d2e266f 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -41,8 +41,15 @@
def before_submit(self):
update_sales_orders = set()
for item in self.locations:
- # if the user has not entered any picked qty, set it to stock_qty, before submit
- if item.picked_qty == 0:
+ if self.scan_mode and item.picked_qty < item.stock_qty:
+ frappe.throw(
+ _("Row {0} is short by {1} {2}").format(
+ item.idx, item.stock_qty - item.picked_qty, item.stock_uom
+ ),
+ title=_("Pick List Incomplete"),
+ )
+ elif not self.scan_mode and item.picked_qty == 0:
+ # if the user has not entered any picked qty, set it to stock_qty, before submit
item.picked_qty = item.stock_qty
if item.sales_order_item:
diff --git a/erpnext/stock/doctype/pick_list_item/pick_list_item.json b/erpnext/stock/doctype/pick_list_item/pick_list_item.json
index a96ebfc..a6f8c0d 100644
--- a/erpnext/stock/doctype/pick_list_item/pick_list_item.json
+++ b/erpnext/stock/doctype/pick_list_item/pick_list_item.json
@@ -202,4 +202,4 @@
"sort_order": "DESC",
"states": [],
"track_changes": 1
-}
\ No newline at end of file
+}