2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-06-14 19:15:41 +00:00

Scan item into location

This commit is contained in:
Oliver Walters
2025-04-19 12:06:18 +00:00
parent ae10a3a68e
commit 4e41103178
2 changed files with 66 additions and 12 deletions

View File

@ -5,6 +5,7 @@ import { apiUrl } from '@lib/functions/Api';
import { getDetailUrl } from '@lib/functions/Navigation';
import { t } from '@lingui/core/macro';
import { Box, Divider, Modal } from '@mantine/core';
import { hideNotification, showNotification } from '@mantine/notifications';
import { useCallback, useState } from 'react';
import { type NavigateFunction, useNavigate } from 'react-router-dom';
import { api } from '../../App';
@ -14,8 +15,8 @@ import { StylishText } from '../items/StylishText';
import { BarcodeInput } from './BarcodeInput';
export type BarcodeScanResult = {
success: boolean;
error: string;
success?: string;
error?: string;
};
// Callback function for handling a barcode scan
@ -29,10 +30,12 @@ export default function BarcodeScanDialog({
title,
opened,
callback,
modelType,
onClose
}: Readonly<{
title?: string;
opened: boolean;
modelType?: ModelType;
callback?: BarcodeScanCallback;
onClose: () => void;
}>) {
@ -50,6 +53,7 @@ export default function BarcodeScanDialog({
<ScanInputHandler
navigate={navigate}
onClose={onClose}
modelType={modelType}
callback={callback}
/>
</Box>
@ -59,11 +63,13 @@ export default function BarcodeScanDialog({
export function ScanInputHandler({
callback,
modelType,
onClose,
navigate
}: Readonly<{
callback?: BarcodeScanCallback;
onClose: () => void;
modelType?: ModelType;
navigate: NavigateFunction;
}>) {
const [error, setError] = useState<string>('');
@ -76,6 +82,11 @@ export function ScanInputHandler({
// Find the matching model type
for (const model_type of Object.keys(ModelInformationDict)) {
// If a specific model type is provided, check if it matches
if (modelType && model_type !== modelType) {
continue;
}
if (data[model_type]?.['pk']) {
if (user.hasViewPermission(model_type as ModelType)) {
const url = getDetailUrl(
@ -94,7 +105,7 @@ export function ScanInputHandler({
setError(t`No matching item found`);
}
},
[navigate, onClose, user]
[navigate, onClose, user, modelType]
);
const onScan = useCallback(
@ -114,12 +125,30 @@ export function ScanInputHandler({
const data = response.data ?? {};
if (callback && data.success && response.status === 200) {
const instance = null;
// If the caller is expecting a specific model type, check if it matches
if (modelType) {
const pk: number = data[modelType]?.['pk'];
if (!pk) {
setError(t`Barcode does not match the expected model type`);
return;
}
}
callback(barcode, data)
.then((result: BarcodeScanResult) => {
if (result.success) {
hideNotification('barcode-scan');
showNotification({
id: 'barcode-scan',
title: t`Success`,
message: result.success,
color: 'green'
});
onClose();
} else {
setError(result.error);
setError(result.error ?? t`Failed to handle barcode`);
}
})
.finally(() => {
@ -144,7 +173,7 @@ export function ScanInputHandler({
setProcessing(false);
});
},
[callback, defaultScan]
[callback, defaultScan, modelType, onClose]
);
return <BarcodeInput onScan={onScan} error={error} processing={processing} />;
@ -152,14 +181,16 @@ export function ScanInputHandler({
export function useBarcodeScanDialog({
title,
callback
callback,
modelType
}: Readonly<{
title: string;
modelType?: ModelType;
callback: BarcodeScanCallback;
}>) {
const [opened, setOpened] = useState(false);
const open = useCallback((callback?: BarcodeScanCallback) => {
const open = useCallback(() => {
setOpened(true);
}, []);
@ -168,6 +199,7 @@ export function useBarcodeScanDialog({
title={title}
opened={opened}
callback={callback}
modelType={modelType}
onClose={() => setOpened(false)}
/>
);

View File

@ -2,11 +2,13 @@ import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { ModelType } from '@lib/enums/ModelType';
import { UserRoles } from '@lib/enums/Roles';
import { getDetailUrl } from '@lib/functions/Navigation';
import { apiUrl } from '@lib/index';
import { t } from '@lingui/core/macro';
import { Group, Skeleton, Stack, Text } from '@mantine/core';
import { IconInfoCircle, IconPackages, IconSitemap } from '@tabler/icons-react';
import { useMemo, useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { api } from '../../App';
import { useBarcodeScanDialog } from '../../components/barcodes/BarcodeScanDialog';
import AdminButton from '../../components/buttons/AdminButton';
import { PrintingActions } from '../../components/buttons/PrintingActions';
@ -275,12 +277,32 @@ export default function Stock() {
const scanInStockItems = useBarcodeScanDialog({
title: t`Scan Stock Item`,
modelType: ModelType.stockitem,
callback: async (barcode, response) => {
console.log('response:', response);
return {
success: true,
error: ''
};
const item = response.stockitem.instance;
// Scan the stock item into the current location
return api
.post(apiUrl(ApiEndpoints.stock_transfer), {
location: location.pk,
items: [
{
pk: item.pk,
quantity: item.quantity
}
]
})
.then(() => {
return {
success: t`Scanned stock item into location`
};
})
.catch((error) => {
console.error('Error scanning stock item:', error);
return {
error: t`Error scanning stock item`
};
});
}
});