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..24d49a4 100644
--- a/erpnext/public/js/utils/barcode_scanner.js
+++ b/erpnext/public/js/utils/barcode_scanner.js
@@ -10,6 +10,11 @@
 		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.allow_new_row = opts.allow_new_row;
+		if (this.allow_new_row === undefined || this.allow_new_row === null) {
+			this.allow_new_row = true;
+		}
 
 		this.items_table_name = opts.items_table_name || "items";
 		this.items_table = this.frm.doc[this.items_table_name];
@@ -72,6 +77,15 @@
 		}
 
 		if (!row) {
+			if (!this.allow_new_row) {
+				frappe.show_alert({
+					message: __("Maximum quantity scanned for this barcode."),
+					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.
@@ -182,7 +196,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..ba14753 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.js
+++ b/erpnext/stock/doctype/pick_list/pick_list.js
@@ -158,6 +158,17 @@
 				get_query_filters: get_query_filters
 			});
 		});
+	},
+	scan_barcode: (frm) => {
+		const opts = {
+			frm,
+			items_table_name: 'locations',
+			qty_field: 'picked_qty',
+			max_qty_field: 'qty',
+			allow_new_row: false
+		};
+		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..f32a05a 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.json
+++ b/erpnext/stock/doctype/pick_list/pick_list.json
@@ -17,6 +17,8 @@
   "parent_warehouse",
   "get_item_locations",
   "section_break_6",
+  "scan_barcode",
+  "section_break_15",
   "locations",
   "amended_from",
   "print_settings_section",
@@ -126,11 +128,21 @@
    "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"
   }
  ],
  "is_submittable": 1,
  "links": [],
- "modified": "2022-04-21 07:56:40.646473",
+ "modified": "2022-04-29 13:45:24.401314",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Pick List",
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
+}