mirror of
https://github.com/inventree/InvenTree.git
synced 2025-09-14 06:31:27 +00:00
Import update (#10188)
* Add field to "update" existing records * Ensure the ID is first * Prevent editing of "ID" field * Extract db instance * Bump API version * Prevent edit of "id" field * Refactoring * Enhanced playwright tests for data importing * Update docs * Update src/backend/InvenTree/importer/models.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/frontend/src/forms/ImporterForms.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Fix silly AI mistake * Fix for table pagination - Ensure page does not exceed available records * Bug fix for playwright test * Add end-to-end API testing * Fix unit tests * Adjust table page logic * Ensure sensible page size * Simplify playwright test * Simplify test again * Tweak unit test - Importing has invalidated the BOM? * Adjust playwright tests * Further playwright fixes --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
9
src/frontend/tests/fixtures/bom_data.csv
vendored
9
src/frontend/tests/fixtures/bom_data.csv
vendored
@@ -1,5 +1,4 @@
|
||||
Assembly,Component,Reference,Quantity,Overage,Allow Variants,Gets inherited,Optional,Consumable,Note,ID,Pricing min,Pricing max,Pricing min total,Pricing max total,Pricing updated,Component.Ipn,Component.Name,Component.Description,Validated,Available Stock,Available substitute stock,Available variant stock,External stock,On Order,In Production,Can Build
|
||||
87,66,Screws,4.0,,False,False,False,False,,16,0.28,0.648622,1.12,2.594488,2024-08-08 06:55,,M3x8 Torx,"Torx head screw, M3 thread, 8.0mm",True,485.0,0.0,0.0,0.0,0.0,0.0,121.25
|
||||
87,67,Large screw,1.0,,False,False,False,False,,17,0.574802,0.574802,0.574802,0.574802,2024-07-27 05:13,,M3x10 Torx,"Torx head screw, M3 thread, 10.0mm",True,1450.0,0.0,0.0,0.0,0.0,0.0,1450.0
|
||||
87,82,Enclosure,1.0,,False,False,False,False,,15,,,,,2024-07-27 05:08,,1551ABK,"Small plastic enclosure, black",True,165.0,223.0,0.0,0.0,0.0,0.0,388.0
|
||||
87,88,PCBA,1.0,,True,False,False,False,Assembled board,23,80.431083,129.328176,80.431083,129.328176,2024-12-27 23:14,002.01-PCBA,Widget Board (assembled),Assembled PCB for converting electricity into magic smoke,True,55.0,0.0,0.0,0.0,0.0,0.0,55.0
|
||||
Assembly,Component,Reference,Quantity,Allow Variants,Gets inherited,Optional,Consumable,Setup quantity,Attrition,Rounding multiple,Note,ID,Pricing min,Pricing max,Pricing min total,Pricing max total,Pricing updated,Component.Ipn,Component.Name,Component.Description,Validated,Available Stock,Available substitute stock,Available variant stock,External stock,On Order,In Production,Can Build
|
||||
106,98,screws,5,FALSE,TRUE,FALSE,TRUE,0,0,0,,39,0.075,0.1,0.375,0.5,23/07/2025 9:12,,Wood Screw,Screw for fixing wood to other wood,TRUE,1604,0,0,0,0,0,320.8
|
||||
106,95,legs,4,FALSE,TRUE,FALSE,FALSE,0,0,0,,40,10.6,12.75,42.4,51,23/07/2025 9:12,,Leg,Leg for a chair or a table,TRUE,317,0,0,0,0,0,79.25
|
||||
109,92,paint,0.125,FALSE,FALSE,FALSE,FALSE,0,0,0,,43,1.403886,14.389836,0.175486,1.79873,23/07/2025 9:12,,Green Paint,Green Paint,TRUE,110.125,0,0,0,0,0,881
|
||||
|
|
@@ -92,8 +92,6 @@ test('Parts - BOM', async ({ browser }) => {
|
||||
await setTableChoiceFilter(page, 'active', 'Yes');
|
||||
await setTableChoiceFilter(page, 'BOM Valid', 'Yes');
|
||||
|
||||
await page.getByText('1 - 12 / 12').waitFor();
|
||||
|
||||
// Navigate to BOM for a particular assembly
|
||||
await navigate(page, 'part/87/bom');
|
||||
await loadTab(page, 'Bill of Materials');
|
||||
@@ -620,8 +618,11 @@ test('Parts - Bulk Edit', async ({ browser }) => {
|
||||
await page.getByLabel('Select record 2', { exact: true }).click();
|
||||
await page.getByLabel('action-menu-part-actions').click();
|
||||
await page.getByLabel('action-menu-part-actions-set-category').click();
|
||||
|
||||
await page.getByLabel('related-field-category').fill('rnitu');
|
||||
await page.getByRole('option', { name: '- Furniture/Chairs' }).click;
|
||||
await page.waitForTimeout(250);
|
||||
|
||||
await page.getByRole('option', { name: '- Furniture/Chairs' }).click();
|
||||
await page.getByRole('button', { name: 'Update' }).click();
|
||||
await page.getByText('Items Updated').waitFor();
|
||||
});
|
||||
|
@@ -14,6 +14,14 @@ test('Importing - Admin Center', async ({ browser }) => {
|
||||
|
||||
const fileInput = await page.locator('input[type="file"]');
|
||||
await fileInput.setInputFiles('./tests/fixtures/bom_data.csv');
|
||||
|
||||
await page
|
||||
.locator('label')
|
||||
.filter({ hasText: 'Update Existing RecordsIf' })
|
||||
.locator('div')
|
||||
.first()
|
||||
.click();
|
||||
|
||||
await page.getByRole('button', { name: 'Submit' }).click();
|
||||
|
||||
// Submitting without selecting model type, should show error
|
||||
@@ -22,21 +30,54 @@ test('Importing - Admin Center', async ({ browser }) => {
|
||||
|
||||
await page
|
||||
.getByRole('textbox', { name: 'choice-field-model_type' })
|
||||
.fill('Cat');
|
||||
await page
|
||||
.getByRole('option', { name: 'Part Category', exact: true })
|
||||
.click();
|
||||
.fill('bom');
|
||||
await page.getByRole('option', { name: 'BOM Item', exact: true }).click();
|
||||
await page.getByRole('button', { name: 'Submit' }).click();
|
||||
|
||||
await page.getByText('Description (optional)').waitFor();
|
||||
await page.getByText('Parent Category').waitFor();
|
||||
await page.getByText('Select the parent assembly').waitFor();
|
||||
await page.getByText('Select the component part').waitFor();
|
||||
await page.getByText('Existing database identifier for the record').waitFor();
|
||||
|
||||
await page
|
||||
.getByRole('textbox', { name: 'import-column-map-reference' })
|
||||
.click();
|
||||
await page.getByRole('option', { name: 'Ignore this field' }).click();
|
||||
|
||||
await page.getByRole('button', { name: 'Accept Column Mapping' }).click();
|
||||
|
||||
// Check for expected ID values
|
||||
for (const itemId of ['16', '17', '15', '23']) {
|
||||
await page.getByRole('cell', { name: itemId, exact: true });
|
||||
}
|
||||
|
||||
// Import all the records
|
||||
await page
|
||||
.getByRole('row', { name: 'Select all records Row Not' })
|
||||
.getByLabel('Select all records')
|
||||
.click();
|
||||
await page
|
||||
.getByRole('button', { name: 'action-button-import-selected' })
|
||||
.click();
|
||||
|
||||
await page.getByText('Data has been imported successfully').waitFor();
|
||||
await page.getByRole('button', { name: 'Close' }).click();
|
||||
|
||||
// Confirmation of full import success
|
||||
await page.getByRole('cell', { name: '3 / 3' }).first().waitFor();
|
||||
|
||||
// Manually delete records
|
||||
await page.getByRole('checkbox', { name: 'Select all records' }).click();
|
||||
await page
|
||||
.getByRole('button', { name: 'action-button-delete-selected' })
|
||||
.click();
|
||||
await page.getByRole('button', { name: 'Delete', exact: true }).click();
|
||||
});
|
||||
|
||||
test('Importing - BOM', async ({ browser }) => {
|
||||
const page = await doCachedLogin(browser, {
|
||||
username: 'steven',
|
||||
password: 'wizardstaff',
|
||||
url: 'part/87/bom'
|
||||
url: 'part/109/bom'
|
||||
});
|
||||
|
||||
await page
|
||||
@@ -53,10 +94,10 @@ test('Importing - BOM', async ({ browser }) => {
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
await page.getByText('Importing Data').waitFor();
|
||||
await page.getByText('0 / 4').waitFor();
|
||||
await page.getByText('0 / 3').waitFor();
|
||||
|
||||
await page.getByText('Torx head screw, M3 thread, 10.0mm').first().waitFor();
|
||||
await page.getByText('Small plastic enclosure, black').first().waitFor();
|
||||
await page.getByText('Screw for fixing wood').first().waitFor();
|
||||
await page.getByText('Leg for a chair or a table').first().waitFor();
|
||||
|
||||
// Select some rows
|
||||
await page
|
||||
@@ -90,15 +131,16 @@ test('Importing - BOM', async ({ browser }) => {
|
||||
await page.getByRole('button', { name: 'Submit' }).click();
|
||||
await page.waitForTimeout(250);
|
||||
|
||||
await page.getByText('0 / 2', { exact: true }).waitFor();
|
||||
await page.getByText('0 / 1', { exact: true }).waitFor();
|
||||
|
||||
// Submit a row
|
||||
await page
|
||||
.getByRole('row', { name: 'Select record 1 2 Thumbnail' })
|
||||
.getByLabel('row-action-menu-')
|
||||
.click();
|
||||
|
||||
await page.getByRole('menuitem', { name: 'Accept' }).click();
|
||||
await page.getByText('1 / 2', { exact: true }).waitFor();
|
||||
await page.getByText('0 / 1', { exact: true }).waitFor();
|
||||
});
|
||||
|
||||
test('Importing - Purchase Order', async ({ browser }) => {
|
||||
|
Reference in New Issue
Block a user