mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-31 05:05:42 +00:00 
			
		
		
		
	BOM Enhancements (#10042)
* Add "round_up_multiple" field * Adjust field def * Add serializer field * Update frontend * Nullify empty numerical values * Calculate round_up_multiple value * Adjust table rendering * Update API version * Add unit test * Additional unit test * Change name of value * Update BOM docs * Add new fields * Add data migration for new fields * Bug fix for data migration * Adjust API fields * Bump API docs * Update frontend * Remove old 'overage' field * Updated BOM docs * Docs tweak * Fix required quantity calculation * additional unit tests * Tweak BOM table * Enhanced "can_build" serializer * Refactor "can_build" calculations * Code cleanup * Serializer fix * Enhanced rendering * Updated playwright tests * Fix method name * Update API unit test * Refactor 'can_build' calculation - Make it much more efficient - Reduce code duplication * Fix unit test * Adjust serializer type * Update src/backend/InvenTree/part/models.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/backend/InvenTree/part/test_bom_item.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update docs/docs/manufacturing/bom.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update docs/docs/manufacturing/bom.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Adjust unit test * Adjust tests * Tweak requirements * Tweak playwright tests * More playwright fixes --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
		| @@ -234,6 +234,8 @@ test('Build Order - Allocation', async ({ browser }) => { | ||||
|   await page.getByText('Reel Storage').waitFor(); | ||||
|   await page.getByText('R_10K_0805_1%').first().click(); | ||||
|  | ||||
|   await page.reload(); | ||||
|  | ||||
|   // The capacitor stock should be fully allocated | ||||
|   const cell = await page.getByRole('cell', { name: /C_1uF_0805/ }); | ||||
|   const row = await getRowFromCell(cell); | ||||
| @@ -278,7 +280,7 @@ test('Build Order - Allocation', async ({ browser }) => { | ||||
|     { | ||||
|       name: 'Blue Widget', | ||||
|       ipn: 'widget.blue', | ||||
|       available: '39', | ||||
|       available: '129', | ||||
|       required: '5', | ||||
|       allocated: '5' | ||||
|     }, | ||||
| @@ -313,7 +315,7 @@ test('Build Order - Allocation', async ({ browser }) => { | ||||
|  | ||||
|   // Check for expected buttons on Red Widget | ||||
|   const redWidget = await page.getByRole('cell', { name: 'Red Widget' }); | ||||
|   const redRow = await redWidget.locator('xpath=ancestor::tr').first(); | ||||
|   const redRow = await getRowFromCell(redWidget); | ||||
|  | ||||
|   await redRow.getByLabel(/row-action-menu-/i).click(); | ||||
|   await page | ||||
| @@ -426,3 +428,33 @@ test('Build Order - External', async ({ browser }) => { | ||||
|   await page.getByRole('cell', { name: 'PO0017' }).waitFor(); | ||||
|   await page.getByRole('cell', { name: 'PO0018' }).waitFor(); | ||||
| }); | ||||
|  | ||||
| test('Build Order - BOM Quantity', async ({ browser }) => { | ||||
|   // Validate required build order quantities (based on BOM values) | ||||
|  | ||||
|   const page = await doCachedLogin(browser, { url: 'part/81/bom' }); | ||||
|  | ||||
|   // Expected quantity values for the BOM items | ||||
|   await page.getByText('15(+50)').waitFor(); | ||||
|   await page.getByText('10(+100)').waitFor(); | ||||
|  | ||||
|   await loadTab(page, 'Part Details'); | ||||
|  | ||||
|   // Expected "can build" value: 13 | ||||
|   const canBuild = await page | ||||
|     .getByRole('cell', { name: 'Can Build' }) | ||||
|     .locator('div'); | ||||
|   const row = await getRowFromCell(canBuild); | ||||
|   await row.getByText('13').waitFor(); | ||||
|  | ||||
|   await loadTab(page, 'Build Orders'); | ||||
|   await page.getByRole('cell', { name: 'BO0016' }).click(); | ||||
|  | ||||
|   await loadTab(page, 'Required Parts'); | ||||
|  | ||||
|   const line = await page | ||||
|     .getByRole('cell', { name: 'Thumbnail R_10K_0805_1%' }) | ||||
|     .locator('div'); | ||||
|   const row2 = await getRowFromCell(line); | ||||
|   await row2.getByText('1175').waitFor(); | ||||
| }); | ||||
|   | ||||
| @@ -207,15 +207,17 @@ test('Stock - Serialize', async ({ browser }) => { | ||||
|   await page.getByLabel('text-field-serial_numbers').fill('200-250'); | ||||
|  | ||||
|   await page.getByRole('button', { name: 'Submit' }).click(); | ||||
|  | ||||
|   await page | ||||
|     .getByText('Group range 200-250 exceeds allowed quantity') | ||||
|     .getByText('Number of unique serial numbers (51) must match quantity (100)') | ||||
|     .waitFor(); | ||||
|  | ||||
|   await page.getByLabel('text-field-serial_numbers').fill('1, 2, 3'); | ||||
|   await page.waitForTimeout(250); | ||||
|   await page.getByRole('button', { name: 'Submit' }).click(); | ||||
|  | ||||
|   await page | ||||
|     .getByText('Number of unique serial numbers (3) must match quantity (10)') | ||||
|     .getByText('Number of unique serial numbers (3) must match quantity (100)') | ||||
|     .waitFor(); | ||||
|  | ||||
|   await page.getByRole('button', { name: 'Cancel' }).click(); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user