2
0
mirror of https://github.com/inventree/InvenTree.git synced 2026-05-17 23:08:28 +00:00

[UI] Barcode form inputs (#10973)

* Add barcode buttons to related fields

- Only field types which support barcodes

* Add per-user settings for barcode support

* Fill form field with scanned data

* Updated docs

* Fix duplicate setting

* Add playwright tests

* Fix duplicate setting in docs

* Fix broken link

* Fix memo deps

* Fix typo

* Remove setting

* Updated playwright tests

* Improved typing
This commit is contained in:
Oliver
2025-12-07 18:31:32 +11:00
committed by GitHub
parent f4186e73ff
commit ae70c22485
16 changed files with 309 additions and 108 deletions
+53 -11
View File
@@ -1,24 +1,37 @@
import type { Page } from '@playwright/test';
import { test } from '../baseFixtures';
import { doCachedLogin } from '../login';
const scan = async (page, barcode) => {
const scan = async (page: Page, barcode: string) => {
await page.getByLabel('barcode-input-scanner').click();
await page.getByLabel('barcode-scan-keyboard-input').fill(barcode);
await page.getByRole('button', { name: 'Scan', exact: true }).click();
};
test('Scanning - Dialog', async ({ browser }) => {
test('Barcode Scanning - Dialog', async ({ browser }) => {
const page = await doCachedLogin(browser);
await page.getByRole('button', { name: 'Open Barcode Scanner' }).click();
// Attempt scan with invalid data
await page.getByRole('button', { name: 'barcode-scan-button-any' }).click();
await scan(page, 'invalid-barcode-123');
await page.getByText('No match found for barcode').waitFor();
// Attempt scan with "legacy" barcode format
await scan(page, '{"part": 15}');
await page.getByText('Part: R_550R_0805_1%', { exact: true }).waitFor();
await page.getByText('Available:').waitFor();
await page.getByText('Required:').waitFor();
// Attempt scan with "modern" barcode format
await page.getByRole('button', { name: 'barcode-scan-button-any' }).click();
await scan(page, 'INV-BO0010');
await page.getByText('Build Order: BO0010').waitFor();
await page.getByText('Making a high level assembly part').waitFor();
});
test('Scanning - Basic', async ({ browser }) => {
test('Barcode Scanning - Basic', async ({ browser }) => {
const page = await doCachedLogin(browser);
// Navigate to the 'scan' page
@@ -39,7 +52,7 @@ test('Scanning - Basic', async ({ browser }) => {
await page.getByText('No match found for barcode').waitFor();
});
test('Scanning - Part', async ({ browser }) => {
test('Barcode Scanning - Part', async ({ browser }) => {
const page = await doCachedLogin(browser, { url: 'scan/' });
await scan(page, '{"part": 1}');
@@ -49,7 +62,7 @@ test('Scanning - Part', async ({ browser }) => {
await page.getByRole('cell', { name: 'part', exact: true }).waitFor();
});
test('Scanning - Stockitem', async ({ browser }) => {
test('Barcode Scanning - Stockitem', async ({ browser }) => {
const page = await doCachedLogin(browser, { url: 'scan/' });
await scan(page, '{"stockitem": 408}');
@@ -58,7 +71,7 @@ test('Scanning - Stockitem', async ({ browser }) => {
await page.getByRole('cell', { name: 'Quantity: 100' }).waitFor();
});
test('Scanning - StockLocation', async ({ browser }) => {
test('Barcode Scanning - StockLocation', async ({ browser }) => {
const page = await doCachedLogin(browser, { url: 'scan/' });
await scan(page, '{"stocklocation": 3}');
@@ -71,7 +84,7 @@ test('Scanning - StockLocation', async ({ browser }) => {
.waitFor();
});
test('Scanning - SupplierPart', async ({ browser }) => {
test('Barcode Scanning - SupplierPart', async ({ browser }) => {
const page = await doCachedLogin(browser, { url: 'scan/' });
await scan(page, '{"supplierpart": 204}');
@@ -80,7 +93,7 @@ test('Scanning - SupplierPart', async ({ browser }) => {
await page.getByRole('cell', { name: 'supplierpart', exact: true }).waitFor();
});
test('Scanning - PurchaseOrder', async ({ browser }) => {
test('Barcode Scanning - PurchaseOrder', async ({ browser }) => {
const page = await doCachedLogin(browser, { url: 'scan/' });
await scan(page, '{"purchaseorder": 12}');
@@ -92,7 +105,7 @@ test('Scanning - PurchaseOrder', async ({ browser }) => {
.waitFor();
});
test('Scanning - SalesOrder', async ({ browser }) => {
test('Barcode Scanning - SalesOrder', async ({ browser }) => {
const page = await doCachedLogin(browser, { url: 'scan/' });
await scan(page, '{"salesorder": 6}');
@@ -103,7 +116,7 @@ test('Scanning - SalesOrder', async ({ browser }) => {
await page.getByRole('cell', { name: 'salesorder', exact: true }).waitFor();
});
test('Scanning - Build', async ({ browser }) => {
test('Barcode Scanning - Build', async ({ browser }) => {
const page = await doCachedLogin(browser, { url: 'scan/' });
await scan(page, '{"build": 8}');
@@ -112,3 +125,32 @@ test('Scanning - Build', async ({ browser }) => {
await page.getByText('PCBA build').waitFor();
await page.getByRole('cell', { name: 'build', exact: true }).waitFor();
});
test('Barcode Scanning - Forms', async ({ browser }) => {
const page = await doCachedLogin(browser, {
url: '/stock/location/index/stock-items'
});
// Open the "Add Stock Item" form
await page
.getByRole('button', { name: 'action-button-add-stock-item' })
.click();
// Fill out the "part" data
await page.getByRole('button', { name: 'barcode-scan-button-part' }).click();
await page
.getByRole('textbox', { name: 'barcode-scan-keyboard-input' })
.fill('INV-PA99');
await page.getByRole('button', { name: 'Scan', exact: true }).click();
await page.getByText('Red Round Table').waitFor();
// Fill out the "location" data
await page
.getByRole('button', { name: 'barcode-scan-button-stocklocation' })
.click();
await page
.getByRole('textbox', { name: 'barcode-scan-keyboard-input' })
.fill('INV-SL37');
await page.getByRole('button', { name: 'Scan', exact: true }).click();
await page.getByText('Offsite Storage').waitFor();
});