mirror of
https://github.com/inventree/InvenTree.git
synced 2026-06-12 03:28:37 +00:00
Offload build output functions: (#11990)
* Offload build output functions: - cancel output - scrap output - complete output Perform these in the background worker, and monitor for progress on the frontend. * Refactor "build cancel" - Offload expensive ops to background worker * Offload build complete task * Remove @atomic decorator from functions - Allows operations to be performed "incrementally" - If one task times out, the next task will get the rest * Bug fix * Bump API version * Fix isInTestMode check * Handle case where task returns immediately * Fix docstring * fix test_api * Tweak order of operations * additional unit testing for further coverage * Adjust unit tests * Offload order completion tasks * Remove bad code * Updated playwright test * Robustify playwright tests * Bump number of allowed queries * Revert "Remove bad code" This reverts commit3a3ac3bdc7. * Revert "Offload order completion tasks" This reverts commit6066dabe43.
This commit is contained in:
@@ -385,7 +385,7 @@ export function useCompleteBuildOutputsForm({
|
||||
title: t`Complete Build Outputs`,
|
||||
fields: buildOutputCompleteFields,
|
||||
onFormSuccess: onFormSuccess,
|
||||
successMessage: t`Build outputs have been completed`,
|
||||
successMessage: null,
|
||||
size: '80%'
|
||||
});
|
||||
}
|
||||
@@ -466,7 +466,7 @@ export function useScrapBuildOutputsForm({
|
||||
),
|
||||
fields: buildOutputScrapFields,
|
||||
onFormSuccess: onFormSuccess,
|
||||
successMessage: t`Build outputs have been scrapped`,
|
||||
successMessage: null,
|
||||
size: '80%'
|
||||
});
|
||||
}
|
||||
@@ -527,7 +527,7 @@ export function useCancelBuildOutputsForm({
|
||||
),
|
||||
fields: buildOutputCancelFields,
|
||||
onFormSuccess: onFormSuccess,
|
||||
successMessage: t`Build outputs have been cancelled`,
|
||||
successMessage: null,
|
||||
size: '80%'
|
||||
});
|
||||
}
|
||||
|
||||
@@ -346,31 +346,80 @@ export default function BuildOutputTable({
|
||||
|
||||
const [selectedOutputs, setSelectedOutputs] = useState<any[]>([]);
|
||||
|
||||
const [completeTaskId, setCompleteTaskId] = useState<string>('');
|
||||
const [scrapTaskId, setScrapTaskId] = useState<string>('');
|
||||
const [deleteTaskId, setDeleteTaskId] = useState<string>('');
|
||||
|
||||
useBackgroundTask({
|
||||
taskId: completeTaskId,
|
||||
message: t`Completing build outputs`,
|
||||
successMessage: t`Build outputs have been completed`,
|
||||
onSuccess: () => {
|
||||
table.refreshTable(true);
|
||||
refreshBuild();
|
||||
}
|
||||
});
|
||||
|
||||
useBackgroundTask({
|
||||
taskId: scrapTaskId,
|
||||
message: t`Scrapping build outputs`,
|
||||
successMessage: t`Build outputs have been scrapped`,
|
||||
onSuccess: () => {
|
||||
table.refreshTable(true);
|
||||
refreshBuild();
|
||||
}
|
||||
});
|
||||
|
||||
useBackgroundTask({
|
||||
taskId: deleteTaskId,
|
||||
message: t`Cancelling build outputs`,
|
||||
successMessage: t`Build outputs have been cancelled`,
|
||||
onSuccess: () => {
|
||||
table.refreshTable(true);
|
||||
refreshBuild();
|
||||
}
|
||||
});
|
||||
|
||||
const completeBuildOutputsForm = useCompleteBuildOutputsForm({
|
||||
build: build,
|
||||
outputs: selectedOutputs,
|
||||
hasTrackedItems: hasTrackedItems,
|
||||
onFormSuccess: () => {
|
||||
table.refreshTable(true);
|
||||
refreshBuild();
|
||||
onFormSuccess: (response: any) => {
|
||||
if (response.task_id) {
|
||||
setCompleteTaskId(response.task_id);
|
||||
} else {
|
||||
// If no task ID is returned, immediately refresh the table and build data
|
||||
table.refreshTable(true);
|
||||
refreshBuild();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const scrapBuildOutputsForm = useScrapBuildOutputsForm({
|
||||
build: build,
|
||||
outputs: selectedOutputs,
|
||||
onFormSuccess: () => {
|
||||
table.refreshTable(true);
|
||||
refreshBuild();
|
||||
onFormSuccess: (response: any) => {
|
||||
if (response.task_id) {
|
||||
setScrapTaskId(response.task_id);
|
||||
} else {
|
||||
// If no task ID is returned, immediately refresh the table and build data
|
||||
table.refreshTable(true);
|
||||
refreshBuild();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const cancelBuildOutputsForm = useCancelBuildOutputsForm({
|
||||
build: build,
|
||||
outputs: selectedOutputs,
|
||||
onFormSuccess: () => {
|
||||
table.refreshTable(true);
|
||||
refreshBuild();
|
||||
onFormSuccess: (response: any) => {
|
||||
if (response.task_id) {
|
||||
setDeleteTaskId(response.task_id);
|
||||
} else {
|
||||
// If no task ID is returned, immediately refresh the table and build data
|
||||
table.refreshTable(true);
|
||||
refreshBuild();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ test('Build Order - Basic Tests', async ({ browser }) => {
|
||||
await clearTableFilters(page);
|
||||
|
||||
// We have now loaded the "Build Order" table. Check for some expected texts
|
||||
await page.getByPlaceholder('Search').fill('7');
|
||||
await page.getByText('On Hold').first().waitFor();
|
||||
await page.getByText('Pending').first().waitFor();
|
||||
|
||||
@@ -60,6 +61,7 @@ test('Build Order - Basic Tests', async ({ browser }) => {
|
||||
await page.getByLabel('breadcrumb-0-manufacturing').click();
|
||||
|
||||
// Load a different build order
|
||||
await page.getByPlaceholder('Search').fill('11');
|
||||
await page.getByRole('cell', { name: 'BO0011' }).click();
|
||||
|
||||
// This build order should be "in production"
|
||||
@@ -654,6 +656,7 @@ test('Build Order - Filters', async ({ browser }) => {
|
||||
// Check for expected pagination text i.e. (1 - 24 / 24)
|
||||
// Note: Due to other concurrent tests, the number of build orders may vary
|
||||
await page.getByText(/1 - \d+ \/ \d+/).waitFor();
|
||||
await page.getByPlaceholder('Search').fill('23');
|
||||
await page.getByRole('cell', { name: 'BO0023' }).waitFor();
|
||||
|
||||
// Toggle 'Outstanding' filter
|
||||
@@ -665,7 +668,7 @@ test('Build Order - Filters', async ({ browser }) => {
|
||||
await page.getByRole('textbox', { name: 'table-search-input' }).fill('');
|
||||
await setTableChoiceFilter(page, 'Outstanding', 'No');
|
||||
|
||||
await page.getByText('1 - 6 / 6').waitFor();
|
||||
await page.getByText(/1 - \d+ \/ \d+/).waitFor();
|
||||
|
||||
await clearTableFilters(page);
|
||||
|
||||
@@ -699,6 +702,40 @@ test('Build Order - Duplicate', async ({ browser }) => {
|
||||
await page.getByRole('tab', { name: 'Build Details' }).click();
|
||||
|
||||
await page.getByText('Pending').first().waitFor();
|
||||
|
||||
// Create a build output
|
||||
await loadTab(page, 'Incomplete Outputs');
|
||||
await page
|
||||
.getByRole('button', { name: 'action-button-add-build-output' })
|
||||
.click();
|
||||
await page
|
||||
.getByRole('textbox', { name: 'text-field-batch_code' })
|
||||
.fill('BATCH-001');
|
||||
await page.getByRole('button', { name: 'Submit' }).click();
|
||||
|
||||
// Cancel (delete) the build output
|
||||
const cell = await page.getByRole('cell', { name: 'BATCH-001' }).first();
|
||||
await clickOnRowMenu(cell);
|
||||
await page.getByRole('menuitem', { name: 'Cancel' }).click();
|
||||
await page.getByRole('button', { name: 'Submit' }).click();
|
||||
|
||||
// no more build outputs
|
||||
await page.getByText('No records found').waitFor();
|
||||
|
||||
// Cancel the build
|
||||
await page.getByRole('button', { name: 'action-menu-build-order-' }).click();
|
||||
await page
|
||||
.getByRole('menuitem', { name: 'action-menu-build-order-actions-cancel' })
|
||||
.click();
|
||||
|
||||
await page
|
||||
.getByRole('switch', { name: 'boolean-field-remove_allocated_stock' })
|
||||
.click();
|
||||
await page
|
||||
.getByRole('switch', { name: 'boolean-field-remove_incomplete_outputs' })
|
||||
.click();
|
||||
await page.getByRole('button', { name: 'Submit' }).click();
|
||||
await page.getByText('Cancelled').first().waitFor();
|
||||
});
|
||||
|
||||
// Tests for external build orders
|
||||
|
||||
Reference in New Issue
Block a user