diff --git a/InvenTree/InvenTree/models.py b/InvenTree/InvenTree/models.py
index 61adfe8e4b..41ade9f1c6 100644
--- a/InvenTree/InvenTree/models.py
+++ b/InvenTree/InvenTree/models.py
@@ -731,7 +731,7 @@ class InvenTreeBarcodeMixin(models.Model):
 
         return cls.objects.filter(barcode_hash=barcode_hash).first()
 
-    def assign_barcode(self, barcode_hash=None, barcode_data=None, raise_error=True):
+    def assign_barcode(self, barcode_hash=None, barcode_data=None, raise_error=True, save=True):
         """Assign an external (third-party) barcode to this object."""
 
         # Must provide either barcode_hash or barcode_data
@@ -754,7 +754,8 @@ class InvenTreeBarcodeMixin(models.Model):
 
         self.barcode_hash = barcode_hash
 
-        self.save()
+        if save:
+            self.save()
 
         return True
 
diff --git a/InvenTree/InvenTree/static/css/inventree.css b/InvenTree/InvenTree/static/css/inventree.css
index cd9b5747d3..c5bc9ea58e 100644
--- a/InvenTree/InvenTree/static/css/inventree.css
+++ b/InvenTree/InvenTree/static/css/inventree.css
@@ -784,6 +784,12 @@ input[type="submit"] {
 
 .alert-block {
     display: block;
+    padding: 0.75rem;
+}
+
+.alert-small {
+    padding: 0.35rem;
+    font-size: 75%;
 }
 
 .navbar .btn {
diff --git a/InvenTree/order/models.py b/InvenTree/order/models.py
index 3ec7c82b72..617aa92678 100644
--- a/InvenTree/order/models.py
+++ b/InvenTree/order/models.py
@@ -549,11 +549,11 @@ class PurchaseOrder(TotalPriceMixin, Order):
         notes = kwargs.get('notes', '')
 
         # Extract optional barcode field
-        barcode_hash = kwargs.get('barcode', None)
+        barcode = kwargs.get('barcode', None)
 
         # Prevent null values for barcode
-        if barcode_hash is None:
-            barcode_hash = ''
+        if barcode is None:
+            barcode = ''
 
         if self.status != PurchaseOrderStatus.PLACED:
             raise ValidationError(
@@ -600,10 +600,16 @@ class PurchaseOrder(TotalPriceMixin, Order):
                     status=status,
                     batch=batch_code,
                     serial=sn,
-                    purchase_price=unit_purchase_price,
-                    barcode_hash=barcode_hash
+                    purchase_price=unit_purchase_price
                 )
 
+                # Assign the provided barcode
+                if barcode:
+                    item.assign_barcode(
+                        barcode_data=barcode,
+                        save=False
+                    )
+
                 item.save(add_note=False)
 
                 tracking_info = {
diff --git a/InvenTree/order/serializers.py b/InvenTree/order/serializers.py
index 9f188c2fd9..9624394943 100644
--- a/InvenTree/order/serializers.py
+++ b/InvenTree/order/serializers.py
@@ -19,7 +19,8 @@ import stock.models
 import stock.serializers
 from company.serializers import (CompanyBriefSerializer, ContactSerializer,
                                  SupplierPartSerializer)
-from InvenTree.helpers import extract_serial_numbers, normalize, str2bool
+from InvenTree.helpers import (extract_serial_numbers, hash_barcode, normalize,
+                               str2bool)
 from InvenTree.serializers import (InvenTreeAttachmentSerializer,
                                    InvenTreeCurrencySerializer,
                                    InvenTreeDecimalField,
@@ -505,8 +506,8 @@ class PurchaseOrderLineItemReceiveSerializer(serializers.Serializer):
     )
 
     barcode = serializers.CharField(
-        label=_('Barcode Hash'),
-        help_text=_('Unique identifier field'),
+        label=_('Barcode'),
+        help_text=_('Scanned barcode'),
         default='',
         required=False,
         allow_null=True,
@@ -519,7 +520,9 @@ class PurchaseOrderLineItemReceiveSerializer(serializers.Serializer):
         if not barcode or barcode.strip() == '':
             return None
 
-        if stock.models.StockItem.objects.filter(barcode_hash=barcode).exists():
+        barcode_hash = hash_barcode(barcode)
+
+        if stock.models.StockItem.lookup_barcode(barcode_hash) is not None:
             raise ValidationError(_('Barcode is already in use'))
 
         return barcode
diff --git a/InvenTree/order/test_api.py b/InvenTree/order/test_api.py
index 98bfe8f840..7b990c9639 100644
--- a/InvenTree/order/test_api.py
+++ b/InvenTree/order/test_api.py
@@ -837,8 +837,7 @@ class PurchaseOrderReceiveTest(OrderTest):
         """
         # Set stock item barcode
         item = StockItem.objects.get(pk=1)
-        item.barcode_hash = 'MY-BARCODE-HASH'
-        item.save()
+        item.assign_barcode(barcode_data='MY-BARCODE-HASH')
 
         response = self.post(
             self.url,
@@ -956,8 +955,8 @@ class PurchaseOrderReceiveTest(OrderTest):
         self.assertEqual(stock_2.last().location.pk, 2)
 
         # Barcodes should have been assigned to the stock items
-        self.assertTrue(StockItem.objects.filter(barcode_hash='MY-UNIQUE-BARCODE-123').exists())
-        self.assertTrue(StockItem.objects.filter(barcode_hash='MY-UNIQUE-BARCODE-456').exists())
+        self.assertTrue(StockItem.objects.filter(barcode_data='MY-UNIQUE-BARCODE-123').exists())
+        self.assertTrue(StockItem.objects.filter(barcode_data='MY-UNIQUE-BARCODE-456').exists())
 
     def test_batch_code(self):
         """Test that we can supply a 'batch code' when receiving items."""
diff --git a/InvenTree/templates/js/translated/barcode.js b/InvenTree/templates/js/translated/barcode.js
index c8213e41da..71b1d26376 100644
--- a/InvenTree/templates/js/translated/barcode.js
+++ b/InvenTree/templates/js/translated/barcode.js
@@ -146,7 +146,7 @@ function makeNotesField(options={}) {
  */
 function postBarcodeData(barcode_data, options={}) {
 
-    var modal = options.modal || '#modal-form';
+    var modal = options.modal;
 
     var url = options.url || '{% url "api-barcode-scan" %}';
 
@@ -166,11 +166,14 @@ function postBarcodeData(barcode_data, options={}) {
                 switch (xhr.status || 0) {
                 case 400:
                     // No match for barcode, most likely
-                    console.log(xhr);
-
-                    data = xhr.responseJSON || {};
-                    showBarcodeMessage(modal, data.error || '{% trans "Server error" %}');
 
+                    if (options.onError400) {
+                        options.onError400(xhr.responseJSON, options);
+                    } else {
+                        console.log(xhr);
+                        data = xhr.responseJSON || {};
+                        showBarcodeMessage(modal, data.error || '{% trans "Server error" %}');
+                    }
                     break;
                 default:
                     // Any other error code means something went wrong
@@ -187,7 +190,7 @@ function postBarcodeData(barcode_data, options={}) {
 
                     if ('success' in response) {
                         if (options.onScan) {
-                            options.onScan(response);
+                            options.onScan(response, options);
                         }
                     } else if ('error' in response) {
                         showBarcodeMessage(
@@ -258,7 +261,7 @@ function enableBarcodeInput(modal, enabled=true) {
  */
 function getBarcodeData(modal) {
 
-    modal = modal || '#modal-form';
+    modal = modal || createNewModal();
 
     var el = $(modal + ' #barcode');
 
@@ -276,7 +279,9 @@ function getBarcodeData(modal) {
  */
 function barcodeDialog(title, options={}) {
 
-    var modal = '#modal-form';
+    var modal = createNewModal();
+
+    options.modal = modal;
 
     function sendBarcode() {
         var barcode = getBarcodeData(modal);
@@ -396,26 +401,33 @@ function barcodeDialog(title, options={}) {
 * Perform a barcode scan,
 * and (potentially) redirect the browser
 */
-function barcodeScanDialog() {
+function barcodeScanDialog(options={}) {
 
-    var modal = '#modal-form';
+    let modal = options.modal || createNewModal();
+    let title = options.title || '{% trans "Scan Barcode" %}';
 
     barcodeDialog(
-        '{% trans "Scan Barcode" %}',
+        title,
         {
             onScan: function(response) {
 
-                var url = response.url;
-
-                if (url) {
-                    $(modal).modal('hide');
-                    window.location.href = url;
+                // Pass the response to the calling function
+                if (options.onScan) {
+                    options.onScan(response);
                 } else {
-                    showBarcodeMessage(
-                        modal,
-                        '{% trans "No URL in response" %}',
-                        'warning'
-                    );
+
+                    let url = response.url;
+
+                    if (url) {
+                        $(modal).modal('hide');
+                        window.location.href = url;
+                    } else {
+                        showBarcodeMessage(
+                            modal,
+                            '{% trans "No URL in response" %}',
+                            'warning'
+                        );
+                    }
                 }
             }
         },
@@ -428,7 +440,8 @@ function barcodeScanDialog() {
  */
 function linkBarcodeDialog(data, options={}) {
 
-    var modal = '#modal-form';
+    var modal = options.modal || createNewModal();
+    options.modal = modal;
 
     barcodeDialog(
         options.title,
@@ -481,7 +494,8 @@ function unlinkBarcode(data, options={}) {
  */
 function barcodeCheckInStockItems(location_id, options={}) {
 
-    var modal = '#modal-form';
+    var modal = options.modal || createNewModal();
+    options.modal = modal;
 
     // List of items we are going to checkin
     var items = [];
@@ -672,7 +686,9 @@ function barcodeCheckInStockItems(location_id, options={}) {
  */
 function barcodeCheckInStockLocations(location_id, options={}) {
 
-    var modal = '#modal-form';
+    var modal = options.modal || createNewModal();
+    options.modal = modal;
+
     var header = '';
 
     barcodeDialog(
@@ -725,7 +741,8 @@ function barcodeCheckInStockLocations(location_id, options={}) {
  */
 function scanItemsIntoLocation(item_list, options={}) {
 
-    var modal = options.modal || '#modal-form';
+    var modal = options.modal || createNewModal();
+    options.modal = modal;
 
     var stock_location = null;
 
diff --git a/InvenTree/templates/js/translated/helpers.js b/InvenTree/templates/js/translated/helpers.js
index e400e33707..04b50d5cbd 100644
--- a/InvenTree/templates/js/translated/helpers.js
+++ b/InvenTree/templates/js/translated/helpers.js
@@ -210,7 +210,13 @@ function makeIconButton(icon, cls, pk, title, options={}) {
 
     var html = '';
 
-    var extraProps = '';
+    var extraProps = options.extra || '';
+
+    var style = '';
+
+    if (options.hidden) {
+        style += `display: none;`;
+    }
 
     if (options.disabled) {
         extraProps += `disabled='true' `;
@@ -220,7 +226,7 @@ function makeIconButton(icon, cls, pk, title, options={}) {
         extraProps += `data-bs-toggle='collapse' href='#${options.collapseTarget}'`;
     }
 
-    html += `<button pk='${pk}' id='${id}' class='${classes}' title='${title}' ${extraProps}>`;
+    html += `<button pk='${pk}' id='${id}' class='${classes}' title='${title}' ${extraProps} style='${style}'>`;
     html += `<span class='fas ${icon}'></span>`;
     html += `</button>`;
 
diff --git a/InvenTree/templates/js/translated/purchase_order.js b/InvenTree/templates/js/translated/purchase_order.js
index 660c8491a6..77156d9a3e 100644
--- a/InvenTree/templates/js/translated/purchase_order.js
+++ b/InvenTree/templates/js/translated/purchase_order.js
@@ -1010,19 +1010,6 @@ function receivePurchaseOrderItems(order_id, line_items, options={}) {
             quantity = 0;
         }
 
-        // Prepend toggles to the quantity input
-        var toggle_batch = `
-            <span class='input-group-text' title='{% trans "Add batch code" %}' data-bs-toggle='collapse' href='#div-batch-${pk}'>
-                <span class='fas fa-layer-group'></span>
-            </span>
-        `;
-
-        var toggle_serials = `
-            <span class='input-group-text' title='{% trans "Add serial numbers" %}' data-bs-toggle='collapse' href='#div-serials-${pk}'>
-                <span class='fas fa-hashtag'></span>
-            </span>
-        `;
-
         var units = line_item.part_detail.units || '';
         var pack_size = line_item.supplier_part_detail.pack_size || 1;
         var pack_size_div = '';
@@ -1031,7 +1018,7 @@ function receivePurchaseOrderItems(order_id, line_items, options={}) {
 
         if (pack_size != 1) {
             pack_size_div = `
-            <div class='alert alert-block alert-info'>
+            <div class='alert alert-small alert-block alert-info'>
                 {% trans "Pack Quantity" %}: ${pack_size} ${units}<br>
                 {% trans "Received Quantity" %}: <span class='pack_received_quantity' id='items_received_quantity_${pk}'>${received}</span> ${units}
             </div>`;
@@ -1060,7 +1047,20 @@ function receivePurchaseOrderItems(order_id, line_items, options={}) {
                 required: false,
                 label: '{% trans "Batch Code" %}',
                 help_text: '{% trans "Enter batch code for incoming stock items" %}',
-                prefixRaw: toggle_batch,
+                icon: 'fa-layer-group',
+            },
+            {
+                hideLabels: true,
+            }
+        );
+
+        // Hidden barcode input
+        var barcode_input = constructField(
+            `items_barcode_${pk}`,
+            {
+                type: 'string',
+                required: 'false',
+                hidden: 'true'
             }
         );
 
@@ -1071,16 +1071,14 @@ function receivePurchaseOrderItems(order_id, line_items, options={}) {
                 required: false,
                 label: '{% trans "Serial Numbers" %}',
                 help_text: '{% trans "Enter serial numbers for incoming stock items" %}',
-                prefixRaw: toggle_serials,
+                icon: 'fa-hashtag',
+            },
+            {
+                hideLabels: true,
             }
         );
 
-        // Hidden inputs below the "quantity" field
-        var quantity_input_group = `${quantity_input}${pack_size_div}<div class='collapse' id='div-batch-${pk}'>${batch_input}</div>`;
-
-        if (line_item.part_detail.trackable) {
-            quantity_input_group += `<div class='collapse' id='div-serials-${pk}'>${sn_input}</div>`;
-        }
+        var quantity_input_group = `${quantity_input}${pack_size_div}`;
 
         // Construct list of StockItem status codes
         var choices = [];
@@ -1098,6 +1096,7 @@ function receivePurchaseOrderItems(order_id, line_items, options={}) {
                 type: 'related field',
                 label: '{% trans "Location" %}',
                 required: false,
+                icon: 'fa-sitemap',
             },
             {
                 hideLabels: true,
@@ -1121,13 +1120,22 @@ function receivePurchaseOrderItems(order_id, line_items, options={}) {
         // Button to remove the row
         let buttons = '';
 
+        if (global_settings.BARCODE_ENABLE) {
+            buttons += makeIconButton('fa-qrcode', 'button-row-add-barcode', pk, '{% trans "Add barcode" %}');
+            buttons += makeIconButton('fa-unlink icon-red', 'button-row-remove-barcode', pk, '{% trans "Remove barcode" %}', {hidden: true});
+        }
+
+        buttons += makeIconButton('fa-sitemap', 'button-row-add-location', pk, '{% trans "Specify location" %}', {
+            collapseTarget: `row-destination-${pk}`
+        });
+
         buttons += makeIconButton(
             'fa-layer-group',
             'button-row-add-batch',
             pk,
             '{% trans "Add batch code" %}',
             {
-                collapseTarget: `div-batch-${pk}`
+                collapseTarget: `row-batch-${pk}`
             }
         );
 
@@ -1138,7 +1146,7 @@ function receivePurchaseOrderItems(order_id, line_items, options={}) {
                 pk,
                 '{% trans "Add serial numbers" %}',
                 {
-                    collapseTarget: `div-serials-${pk}`,
+                    collapseTarget: `row-serials-${pk}`,
                 }
             );
         }
@@ -1149,6 +1157,8 @@ function receivePurchaseOrderItems(order_id, line_items, options={}) {
 
         buttons = wrapButtons(buttons);
 
+        let progress = makeProgressBar(line_item.received, line_item.quantity);
+
         var html = `
         <tr id='receive_row_${pk}' class='stock-receive-row'>
             <td id='part_${pk}'>
@@ -1157,11 +1167,8 @@ function receivePurchaseOrderItems(order_id, line_items, options={}) {
             <td id='sku_${pk}'>
                 ${line_item.supplier_part_detail.SKU}
             </td>
-            <td id='on_order_${pk}'>
-                ${line_item.quantity}
-            </td>
             <td id='received_${pk}'>
-                ${line_item.received}
+                ${progress}
             </td>
             <td id='quantity_${pk}'>
                 ${quantity_input_group}
@@ -1169,13 +1176,31 @@ function receivePurchaseOrderItems(order_id, line_items, options={}) {
             <td id='status_${pk}'>
                 ${status_input}
             </td>
-            <td id='desination_${pk}'>
-                ${destination_input}
-            </td>
             <td id='actions_${pk}'>
+                ${barcode_input}
                 ${buttons}
             </td>
-        </tr>`;
+        </tr>
+        <!-- Hidden rows for extra data entry -->
+        <tr id='row-destination-${pk}' class='collapse'>
+            <td colspan='2'></td>
+            <th>{% trans "Location" %}</th>
+            <td colspan='2'>${destination_input}</td>
+            <td></td>
+        </tr>
+        <tr id='row-batch-${pk}' class='collapse'>
+            <td colspan='2'></td>
+            <th>{% trans "Batch" %}</th>
+            <td colspan='2'>${batch_input}</td>
+            <td></td>
+        </tr>
+        <tr id='row-serials-${pk}' class='collapse'>
+            <td colspan='2'></td>
+            <th>{% trans "Serials" %}</th>
+            <td colspan=2'>${sn_input}</td>
+            <td></td>
+        </tr>
+        `;
 
         return html;
     }
@@ -1192,16 +1217,14 @@ function receivePurchaseOrderItems(order_id, line_items, options={}) {
 
     // Add table
     html += `
-    <table class='table table-striped table-condensed' id='order-receive-table'>
+    <table class='table table-condensed' id='order-receive-table'>
         <thead>
             <tr>
                 <th>{% trans "Part" %}</th>
                 <th>{% trans "Order Code" %}</th>
-                <th>{% trans "Ordered" %}</th>
                 <th>{% trans "Received" %}</th>
                 <th style='min-width: 50px;'>{% trans "Quantity to Receive" %}</th>
                 <th style='min-width: 150px;'>{% trans "Status" %}</th>
-                <th style='min-width: 300px;'>{% trans "Destination" %}</th>
                 <th></th>
             </tr>
         </thead>
@@ -1284,6 +1307,44 @@ function receivePurchaseOrderItems(order_id, line_items, options={}) {
                 }
             });
 
+            // Add callbacks to add barcode
+            if (global_settings.BARCODE_ENABLE) {
+                $(opts.modal).find('.button-row-add-barcode').click(function() {
+                    var btn = $(this);
+                    let pk = btn.attr('pk');
+
+                    // Scan to see if the barcode matches an existing StockItem
+                    barcodeDialog('{% trans "Scan Item Barcode" %}', {
+                        details: '{% trans "Scan barcode on incoming item (must not match any existing stock items)" %}',
+                        onScan: function(response, barcode_options) {
+                            // A 'success' result means that the barcode matches something existing in the database
+                            showBarcodeMessage(barcode_options.modal, '{% trans "Barcode matches existing item" %}');
+                        },
+                        onError400: function(response, barcode_options) {
+                            if (response.barcode_data && response.barcode_hash) {
+                                // Success! Hide the modal and update the value
+                                $(barcode_options.modal).modal('hide');
+
+                                btn.hide();
+                                $(opts.modal).find(`#button-row-remove-barcode-${pk}`).show();
+                                updateFieldValue(`items_barcode_${pk}`, response.barcode_data, {}, opts);
+                            } else {
+                                showBarcodeMessage(barcode_options.modal, '{% trans "Invalid barcode data" %}');
+                            }
+                        }
+                    });
+                });
+
+                $(opts.modal).find('.button-row-remove-barcode').click(function() {
+                    var btn = $(this);
+                    let pk = btn.attr('pk');
+
+                    btn.hide();
+                    $(opts.modal).find(`#button-row-add-barcode-${pk}`).show();
+                    updateFieldValue(`items_barcode_${pk}`, '', {}, opts);
+                });
+            }
+
             // Add callbacks to remove rows
             $(opts.modal).find('.button-row-remove').click(function() {
                 var pk = $(this).attr('pk');
@@ -1304,10 +1365,9 @@ function receivePurchaseOrderItems(order_id, line_items, options={}) {
 
                 var pk = item.pk;
 
+                // Extract data for each line
                 var quantity = getFormFieldValue(`items_quantity_${pk}`, {}, opts);
-
                 var status = getFormFieldValue(`items_status_${pk}`, {}, opts);
-
                 var location = getFormFieldValue(`items_location_${pk}`, {}, opts);
 
                 if (quantity != null) {
@@ -1319,6 +1379,10 @@ function receivePurchaseOrderItems(order_id, line_items, options={}) {
                         location: location,
                     };
 
+                    if (global_settings.BARCODE_ENABLE) {
+                        line.barcode = getFormFieldValue(`items_barcode_${pk}`, {}, opts);
+                    }
+
                     if (getFormFieldElement(`items_batch_code_${pk}`).exists()) {
                         line.batch_code = getFormFieldValue(`items_batch_code_${pk}`);
                     }