2025-09-23 19:24:22 +02:00
|
|
|
// frontend/src/api/hooks/qualityTemplates.ts
|
|
|
|
|
/**
|
|
|
|
|
* React hooks for Quality Check Template API integration
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
2025-10-30 21:08:07 +01:00
|
|
|
import { showToast } from '../../utils/toast';
|
2025-09-23 19:24:22 +02:00
|
|
|
import { qualityTemplateService } from '../services/qualityTemplates';
|
|
|
|
|
import type {
|
|
|
|
|
QualityCheckTemplate,
|
|
|
|
|
QualityCheckTemplateCreate,
|
|
|
|
|
QualityCheckTemplateUpdate,
|
|
|
|
|
QualityTemplateQueryParams,
|
|
|
|
|
ProcessStage,
|
|
|
|
|
QualityCheckExecutionRequest
|
|
|
|
|
} from '../types/qualityTemplates';
|
|
|
|
|
|
|
|
|
|
// Query Keys
|
|
|
|
|
export const qualityTemplateKeys = {
|
|
|
|
|
all: ['qualityTemplates'] as const,
|
|
|
|
|
lists: () => [...qualityTemplateKeys.all, 'list'] as const,
|
|
|
|
|
list: (tenantId: string, params?: QualityTemplateQueryParams) =>
|
|
|
|
|
[...qualityTemplateKeys.lists(), tenantId, params] as const,
|
|
|
|
|
details: () => [...qualityTemplateKeys.all, 'detail'] as const,
|
|
|
|
|
detail: (tenantId: string, templateId: string) =>
|
|
|
|
|
[...qualityTemplateKeys.details(), tenantId, templateId] as const,
|
|
|
|
|
forStage: (tenantId: string, stage: ProcessStage) =>
|
|
|
|
|
[...qualityTemplateKeys.all, 'stage', tenantId, stage] as const,
|
|
|
|
|
forRecipe: (tenantId: string, recipeId: string) =>
|
|
|
|
|
[...qualityTemplateKeys.all, 'recipe', tenantId, recipeId] as const,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Hook to fetch quality check templates
|
|
|
|
|
*/
|
|
|
|
|
export function useQualityTemplates(
|
|
|
|
|
tenantId: string,
|
|
|
|
|
params?: QualityTemplateQueryParams,
|
|
|
|
|
options?: { enabled?: boolean }
|
|
|
|
|
) {
|
|
|
|
|
return useQuery({
|
|
|
|
|
queryKey: qualityTemplateKeys.list(tenantId, params),
|
|
|
|
|
queryFn: () => qualityTemplateService.getTemplates(tenantId, params),
|
|
|
|
|
enabled: !!tenantId && (options?.enabled ?? true),
|
|
|
|
|
staleTime: 5 * 60 * 1000, // 5 minutes
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Hook to fetch a specific quality check template
|
|
|
|
|
*/
|
|
|
|
|
export function useQualityTemplate(
|
|
|
|
|
tenantId: string,
|
|
|
|
|
templateId: string,
|
|
|
|
|
options?: { enabled?: boolean }
|
|
|
|
|
) {
|
|
|
|
|
return useQuery({
|
|
|
|
|
queryKey: qualityTemplateKeys.detail(tenantId, templateId),
|
|
|
|
|
queryFn: () => qualityTemplateService.getTemplate(tenantId, templateId),
|
|
|
|
|
enabled: !!tenantId && !!templateId && (options?.enabled ?? true),
|
|
|
|
|
staleTime: 10 * 60 * 1000, // 10 minutes
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Hook to fetch templates for a specific process stage
|
|
|
|
|
*/
|
|
|
|
|
export function useQualityTemplatesForStage(
|
|
|
|
|
tenantId: string,
|
|
|
|
|
stage: ProcessStage,
|
|
|
|
|
isActive: boolean = true,
|
|
|
|
|
options?: { enabled?: boolean }
|
|
|
|
|
) {
|
|
|
|
|
return useQuery({
|
|
|
|
|
queryKey: qualityTemplateKeys.forStage(tenantId, stage),
|
|
|
|
|
queryFn: () => qualityTemplateService.getTemplatesForStage(tenantId, stage, isActive),
|
|
|
|
|
enabled: !!tenantId && !!stage && (options?.enabled ?? true),
|
|
|
|
|
staleTime: 5 * 60 * 1000, // 5 minutes
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Hook to fetch templates organized by stages for recipe configuration
|
|
|
|
|
*/
|
|
|
|
|
export function useQualityTemplatesForRecipe(
|
|
|
|
|
tenantId: string,
|
|
|
|
|
recipeId: string,
|
|
|
|
|
options?: { enabled?: boolean }
|
|
|
|
|
) {
|
|
|
|
|
return useQuery({
|
|
|
|
|
queryKey: qualityTemplateKeys.forRecipe(tenantId, recipeId),
|
|
|
|
|
queryFn: () => qualityTemplateService.getTemplatesForRecipe(tenantId, recipeId),
|
|
|
|
|
enabled: !!tenantId && !!recipeId && (options?.enabled ?? true),
|
|
|
|
|
staleTime: 10 * 60 * 1000, // 10 minutes
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Hook to create a quality check template
|
|
|
|
|
*/
|
|
|
|
|
export function useCreateQualityTemplate(tenantId: string) {
|
|
|
|
|
const queryClient = useQueryClient();
|
|
|
|
|
|
|
|
|
|
return useMutation({
|
|
|
|
|
mutationFn: (templateData: QualityCheckTemplateCreate) =>
|
|
|
|
|
qualityTemplateService.createTemplate(tenantId, templateData),
|
|
|
|
|
onSuccess: (newTemplate) => {
|
|
|
|
|
// Invalidate and refetch quality template lists
|
|
|
|
|
queryClient.invalidateQueries({ queryKey: qualityTemplateKeys.lists() });
|
|
|
|
|
|
|
|
|
|
// Add to cache
|
|
|
|
|
queryClient.setQueryData(
|
|
|
|
|
qualityTemplateKeys.detail(tenantId, newTemplate.id),
|
|
|
|
|
newTemplate
|
|
|
|
|
);
|
|
|
|
|
|
2025-10-30 21:08:07 +01:00
|
|
|
showToast.success('Plantilla de calidad creada exitosamente');
|
2025-09-23 19:24:22 +02:00
|
|
|
},
|
|
|
|
|
onError: (error: any) => {
|
|
|
|
|
console.error('Error creating quality template:', error);
|
2025-10-30 21:08:07 +01:00
|
|
|
showToast.error(error.response?.data?.detail || 'Error al crear la plantilla de calidad');
|
2025-09-23 19:24:22 +02:00
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Hook to update a quality check template
|
|
|
|
|
*/
|
|
|
|
|
export function useUpdateQualityTemplate(tenantId: string) {
|
|
|
|
|
const queryClient = useQueryClient();
|
|
|
|
|
|
|
|
|
|
return useMutation({
|
|
|
|
|
mutationFn: ({ templateId, templateData }: {
|
|
|
|
|
templateId: string;
|
|
|
|
|
templateData: QualityCheckTemplateUpdate;
|
|
|
|
|
}) => qualityTemplateService.updateTemplate(tenantId, templateId, templateData),
|
|
|
|
|
onSuccess: (updatedTemplate, { templateId }) => {
|
|
|
|
|
// Update cached data
|
|
|
|
|
queryClient.setQueryData(
|
|
|
|
|
qualityTemplateKeys.detail(tenantId, templateId),
|
|
|
|
|
updatedTemplate
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Invalidate lists to refresh
|
|
|
|
|
queryClient.invalidateQueries({ queryKey: qualityTemplateKeys.lists() });
|
|
|
|
|
|
2025-10-30 21:08:07 +01:00
|
|
|
showToast.success('Plantilla de calidad actualizada exitosamente');
|
2025-09-23 19:24:22 +02:00
|
|
|
},
|
|
|
|
|
onError: (error: any) => {
|
|
|
|
|
console.error('Error updating quality template:', error);
|
2025-10-30 21:08:07 +01:00
|
|
|
showToast.error(error.response?.data?.detail || 'Error al actualizar la plantilla de calidad');
|
2025-09-23 19:24:22 +02:00
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Hook to delete a quality check template
|
|
|
|
|
*/
|
|
|
|
|
export function useDeleteQualityTemplate(tenantId: string) {
|
|
|
|
|
const queryClient = useQueryClient();
|
|
|
|
|
|
|
|
|
|
return useMutation({
|
|
|
|
|
mutationFn: (templateId: string) =>
|
|
|
|
|
qualityTemplateService.deleteTemplate(tenantId, templateId),
|
|
|
|
|
onSuccess: (_, templateId) => {
|
|
|
|
|
// Remove from cache
|
|
|
|
|
queryClient.removeQueries({
|
|
|
|
|
queryKey: qualityTemplateKeys.detail(tenantId, templateId)
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Invalidate lists to refresh
|
|
|
|
|
queryClient.invalidateQueries({ queryKey: qualityTemplateKeys.lists() });
|
|
|
|
|
|
2025-10-30 21:08:07 +01:00
|
|
|
showToast.success('Plantilla de calidad eliminada exitosamente');
|
2025-09-23 19:24:22 +02:00
|
|
|
},
|
|
|
|
|
onError: (error: any) => {
|
|
|
|
|
console.error('Error deleting quality template:', error);
|
2025-10-30 21:08:07 +01:00
|
|
|
showToast.error(error.response?.data?.detail || 'Error al eliminar la plantilla de calidad');
|
2025-09-23 19:24:22 +02:00
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Hook to duplicate a quality check template
|
|
|
|
|
*/
|
|
|
|
|
export function useDuplicateQualityTemplate(tenantId: string) {
|
|
|
|
|
const queryClient = useQueryClient();
|
|
|
|
|
|
|
|
|
|
return useMutation({
|
|
|
|
|
mutationFn: (templateId: string) =>
|
|
|
|
|
qualityTemplateService.duplicateTemplate(tenantId, templateId),
|
|
|
|
|
onSuccess: (duplicatedTemplate) => {
|
|
|
|
|
// Add to cache
|
|
|
|
|
queryClient.setQueryData(
|
|
|
|
|
qualityTemplateKeys.detail(tenantId, duplicatedTemplate.id),
|
|
|
|
|
duplicatedTemplate
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Invalidate lists to refresh
|
|
|
|
|
queryClient.invalidateQueries({ queryKey: qualityTemplateKeys.lists() });
|
|
|
|
|
|
2025-10-30 21:08:07 +01:00
|
|
|
showToast.success('Plantilla de calidad duplicada exitosamente');
|
2025-09-23 19:24:22 +02:00
|
|
|
},
|
|
|
|
|
onError: (error: any) => {
|
|
|
|
|
console.error('Error duplicating quality template:', error);
|
2025-10-30 21:08:07 +01:00
|
|
|
showToast.error(error.response?.data?.detail || 'Error al duplicar la plantilla de calidad');
|
2025-09-23 19:24:22 +02:00
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Hook to execute a quality check
|
|
|
|
|
*/
|
|
|
|
|
export function useExecuteQualityCheck(tenantId: string) {
|
|
|
|
|
const queryClient = useQueryClient();
|
|
|
|
|
|
|
|
|
|
return useMutation({
|
|
|
|
|
mutationFn: (executionData: QualityCheckExecutionRequest) =>
|
|
|
|
|
qualityTemplateService.executeQualityCheck(tenantId, executionData),
|
|
|
|
|
onSuccess: (result, executionData) => {
|
|
|
|
|
// Invalidate production batch data to refresh status
|
|
|
|
|
queryClient.invalidateQueries({
|
|
|
|
|
queryKey: ['production', 'batches', tenantId]
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Invalidate quality check history
|
|
|
|
|
queryClient.invalidateQueries({
|
|
|
|
|
queryKey: ['qualityChecks', tenantId, executionData.batch_id]
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const message = result.overall_pass
|
|
|
|
|
? 'Control de calidad completado exitosamente'
|
|
|
|
|
: 'Control de calidad completado con observaciones';
|
|
|
|
|
|
|
|
|
|
if (result.overall_pass) {
|
2025-10-30 21:08:07 +01:00
|
|
|
showToast.success(message);
|
2025-09-23 19:24:22 +02:00
|
|
|
} else {
|
2025-10-30 21:08:07 +01:00
|
|
|
showToast.error(message);
|
2025-09-23 19:24:22 +02:00
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
onError: (error: any) => {
|
|
|
|
|
console.error('Error executing quality check:', error);
|
2025-10-30 21:08:07 +01:00
|
|
|
showToast.error(error.response?.data?.detail || 'Error al ejecutar el control de calidad');
|
2025-09-23 19:24:22 +02:00
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Hook to get default templates for a product category
|
|
|
|
|
*/
|
|
|
|
|
export function useDefaultQualityTemplates(
|
|
|
|
|
tenantId: string,
|
|
|
|
|
productCategory: string,
|
|
|
|
|
options?: { enabled?: boolean }
|
|
|
|
|
) {
|
|
|
|
|
return useQuery({
|
|
|
|
|
queryKey: [...qualityTemplateKeys.all, 'defaults', tenantId, productCategory],
|
|
|
|
|
queryFn: () => qualityTemplateService.getDefaultTemplates(tenantId, productCategory),
|
|
|
|
|
enabled: !!tenantId && !!productCategory && (options?.enabled ?? true),
|
|
|
|
|
staleTime: 15 * 60 * 1000, // 15 minutes
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Hook to validate template configuration
|
|
|
|
|
*/
|
|
|
|
|
export function useValidateQualityTemplate(tenantId: string) {
|
|
|
|
|
return useMutation({
|
|
|
|
|
mutationFn: (templateData: Partial<QualityCheckTemplateCreate | QualityCheckTemplateUpdate>) =>
|
|
|
|
|
qualityTemplateService.validateTemplate(tenantId, templateData),
|
|
|
|
|
onError: (error: any) => {
|
|
|
|
|
console.error('Error validating quality template:', error);
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|