Add quality template logic
This commit is contained in:
@@ -16,7 +16,7 @@ import type {
|
|||||||
} from '../types/qualityTemplates';
|
} from '../types/qualityTemplates';
|
||||||
|
|
||||||
class QualityTemplateService {
|
class QualityTemplateService {
|
||||||
private readonly baseURL = '/production/api/v1/quality-templates';
|
private readonly baseURL = '/tenants';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new quality check template
|
* Create a new quality check template
|
||||||
@@ -25,10 +25,10 @@ class QualityTemplateService {
|
|||||||
tenantId: string,
|
tenantId: string,
|
||||||
templateData: QualityCheckTemplateCreate
|
templateData: QualityCheckTemplateCreate
|
||||||
): Promise<QualityCheckTemplate> {
|
): Promise<QualityCheckTemplate> {
|
||||||
const response = await apiClient.post(this.baseURL, templateData, {
|
const data = await apiClient.post(`${this.baseURL}/${tenantId}/production/quality-templates`, templateData, {
|
||||||
headers: { 'X-Tenant-ID': tenantId }
|
headers: { 'X-Tenant-ID': tenantId }
|
||||||
});
|
});
|
||||||
return response.data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,11 +38,11 @@ class QualityTemplateService {
|
|||||||
tenantId: string,
|
tenantId: string,
|
||||||
params?: QualityTemplateQueryParams
|
params?: QualityTemplateQueryParams
|
||||||
): Promise<QualityCheckTemplateList> {
|
): Promise<QualityCheckTemplateList> {
|
||||||
const response = await apiClient.get(this.baseURL, {
|
const data = await apiClient.get(`${this.baseURL}/${tenantId}/production/quality-templates`, {
|
||||||
params,
|
params,
|
||||||
headers: { 'X-Tenant-ID': tenantId }
|
headers: { 'X-Tenant-ID': tenantId }
|
||||||
});
|
});
|
||||||
return response.data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -52,10 +52,10 @@ class QualityTemplateService {
|
|||||||
tenantId: string,
|
tenantId: string,
|
||||||
templateId: string
|
templateId: string
|
||||||
): Promise<QualityCheckTemplate> {
|
): Promise<QualityCheckTemplate> {
|
||||||
const response = await apiClient.get(`${this.baseURL}/${templateId}`, {
|
const data = await apiClient.get(`${this.baseURL}/${tenantId}/production/quality-templates/${templateId}`, {
|
||||||
headers: { 'X-Tenant-ID': tenantId }
|
headers: { 'X-Tenant-ID': tenantId }
|
||||||
});
|
});
|
||||||
return response.data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,17 +66,17 @@ class QualityTemplateService {
|
|||||||
templateId: string,
|
templateId: string,
|
||||||
templateData: QualityCheckTemplateUpdate
|
templateData: QualityCheckTemplateUpdate
|
||||||
): Promise<QualityCheckTemplate> {
|
): Promise<QualityCheckTemplate> {
|
||||||
const response = await apiClient.put(`${this.baseURL}/${templateId}`, templateData, {
|
const data = await apiClient.put(`${this.baseURL}/${tenantId}/production/quality-templates/${templateId}`, templateData, {
|
||||||
headers: { 'X-Tenant-ID': tenantId }
|
headers: { 'X-Tenant-ID': tenantId }
|
||||||
});
|
});
|
||||||
return response.data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a quality check template
|
* Delete a quality check template
|
||||||
*/
|
*/
|
||||||
async deleteTemplate(tenantId: string, templateId: string): Promise<void> {
|
async deleteTemplate(tenantId: string, templateId: string): Promise<void> {
|
||||||
await apiClient.delete(`${this.baseURL}/${templateId}`, {
|
await apiClient.delete(`${this.baseURL}/${tenantId}/production/quality-templates/${templateId}`, {
|
||||||
headers: { 'X-Tenant-ID': tenantId }
|
headers: { 'X-Tenant-ID': tenantId }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -89,11 +89,11 @@ class QualityTemplateService {
|
|||||||
stage: ProcessStage,
|
stage: ProcessStage,
|
||||||
isActive: boolean = true
|
isActive: boolean = true
|
||||||
): Promise<QualityCheckTemplateList> {
|
): Promise<QualityCheckTemplateList> {
|
||||||
const response = await apiClient.get(`${this.baseURL}/stages/${stage}`, {
|
const data = await apiClient.get(`${this.baseURL}/${tenantId}/production/quality-templates/stages/${stage}`, {
|
||||||
params: { is_active: isActive },
|
params: { is_active: isActive },
|
||||||
headers: { 'X-Tenant-ID': tenantId }
|
headers: { 'X-Tenant-ID': tenantId }
|
||||||
});
|
});
|
||||||
return response.data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -103,10 +103,10 @@ class QualityTemplateService {
|
|||||||
tenantId: string,
|
tenantId: string,
|
||||||
templateId: string
|
templateId: string
|
||||||
): Promise<QualityCheckTemplate> {
|
): Promise<QualityCheckTemplate> {
|
||||||
const response = await apiClient.post(`${this.baseURL}/${templateId}/duplicate`, {}, {
|
const data = await apiClient.post(`${this.baseURL}/${tenantId}/production/quality-templates/${templateId}/duplicate`, {}, {
|
||||||
headers: { 'X-Tenant-ID': tenantId }
|
headers: { 'X-Tenant-ID': tenantId }
|
||||||
});
|
});
|
||||||
return response.data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -116,10 +116,10 @@ class QualityTemplateService {
|
|||||||
tenantId: string,
|
tenantId: string,
|
||||||
executionData: QualityCheckExecutionRequest
|
executionData: QualityCheckExecutionRequest
|
||||||
): Promise<QualityCheckExecutionResponse> {
|
): Promise<QualityCheckExecutionResponse> {
|
||||||
const response = await apiClient.post('/production/api/v1/quality-checks/execute', executionData, {
|
const data = await apiClient.post(`${this.baseURL}/${tenantId}/production/quality-checks/execute`, executionData, {
|
||||||
headers: { 'X-Tenant-ID': tenantId }
|
headers: { 'X-Tenant-ID': tenantId }
|
||||||
});
|
});
|
||||||
return response.data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -130,11 +130,11 @@ class QualityTemplateService {
|
|||||||
batchId: string,
|
batchId: string,
|
||||||
stage?: ProcessStage
|
stage?: ProcessStage
|
||||||
): Promise<any[]> {
|
): Promise<any[]> {
|
||||||
const response = await apiClient.get('/production/api/v1/quality-checks', {
|
const data = await apiClient.get(`${this.baseURL}/${tenantId}/production/quality-checks`, {
|
||||||
params: { batch_id: batchId, process_stage: stage },
|
params: { batch_id: batchId, process_stage: stage },
|
||||||
headers: { 'X-Tenant-ID': tenantId }
|
headers: { 'X-Tenant-ID': tenantId }
|
||||||
});
|
});
|
||||||
return response.data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -168,15 +168,15 @@ class QualityTemplateService {
|
|||||||
templateData: Partial<QualityCheckTemplateCreate | QualityCheckTemplateUpdate>
|
templateData: Partial<QualityCheckTemplateCreate | QualityCheckTemplateUpdate>
|
||||||
): Promise<{ valid: boolean; errors: string[] }> {
|
): Promise<{ valid: boolean; errors: string[] }> {
|
||||||
try {
|
try {
|
||||||
const response = await apiClient.post(`${this.baseURL}/validate`, templateData, {
|
const data = await apiClient.post(`${this.baseURL}/${tenantId}/production/quality-templates/validate`, templateData, {
|
||||||
headers: { 'X-Tenant-ID': tenantId }
|
headers: { 'X-Tenant-ID': tenantId }
|
||||||
});
|
});
|
||||||
return response.data;
|
return data;
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
if (error.response?.status === 400) {
|
if (error.response?.status === 400) {
|
||||||
return {
|
return {
|
||||||
valid: false,
|
valid: false,
|
||||||
errors: [error.response.data.detail || 'Validation failed']
|
errors: [error.response?.data?.detail || 'Validation failed']
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
throw error;
|
throw error;
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { QualityTemplateManager } from '../../../../components/domain/production';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* QualityTemplatesPage - Page wrapper for the QualityTemplateManager component
|
||||||
|
*
|
||||||
|
* This page provides access to quality template management functionality,
|
||||||
|
* allowing users to create, edit, duplicate, and manage quality control templates
|
||||||
|
* that are used during production processes.
|
||||||
|
*/
|
||||||
|
const QualityTemplatesPage: React.FC = () => {
|
||||||
|
return (
|
||||||
|
<div className="container mx-auto px-4 py-6">
|
||||||
|
<QualityTemplateManager />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default QualityTemplatesPage;
|
||||||
@@ -37,6 +37,7 @@ const OrganizationsPage = React.lazy(() => import('../pages/app/settings/organiz
|
|||||||
// Database pages
|
// Database pages
|
||||||
const DatabasePage = React.lazy(() => import('../pages/app/database/DatabasePage'));
|
const DatabasePage = React.lazy(() => import('../pages/app/database/DatabasePage'));
|
||||||
const ModelsConfigPage = React.lazy(() => import('../pages/app/database/models/ModelsConfigPage'));
|
const ModelsConfigPage = React.lazy(() => import('../pages/app/database/models/ModelsConfigPage'));
|
||||||
|
const QualityTemplatesPage = React.lazy(() => import('../pages/app/database/quality-templates/QualityTemplatesPage'));
|
||||||
|
|
||||||
// Data pages
|
// Data pages
|
||||||
const WeatherPage = React.lazy(() => import('../pages/app/data/weather/WeatherPage'));
|
const WeatherPage = React.lazy(() => import('../pages/app/data/weather/WeatherPage'));
|
||||||
@@ -190,6 +191,16 @@ export const AppRouter: React.FC = () => {
|
|||||||
</ProtectedRoute>
|
</ProtectedRoute>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<Route
|
||||||
|
path="/app/database/quality-templates"
|
||||||
|
element={
|
||||||
|
<ProtectedRoute>
|
||||||
|
<AppShell>
|
||||||
|
<QualityTemplatesPage />
|
||||||
|
</AppShell>
|
||||||
|
</ProtectedRoute>
|
||||||
|
}
|
||||||
|
/>
|
||||||
<Route
|
<Route
|
||||||
path="/app/database/maquinaria"
|
path="/app/database/maquinaria"
|
||||||
element={
|
element={
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ export const ROUTES = {
|
|||||||
SETTINGS_BILLING: '/settings/billing',
|
SETTINGS_BILLING: '/settings/billing',
|
||||||
SETTINGS_BAKERY_CONFIG: '/app/database/bakery-config',
|
SETTINGS_BAKERY_CONFIG: '/app/database/bakery-config',
|
||||||
SETTINGS_TEAM: '/app/database/team',
|
SETTINGS_TEAM: '/app/database/team',
|
||||||
|
QUALITY_TEMPLATES: '/app/database/quality-templates',
|
||||||
|
|
||||||
// Reports
|
// Reports
|
||||||
REPORTS: '/reports',
|
REPORTS: '/reports',
|
||||||
@@ -353,6 +354,17 @@ export const routesConfig: RouteConfig[] = [
|
|||||||
showInNavigation: true,
|
showInNavigation: true,
|
||||||
showInBreadcrumbs: true,
|
showInBreadcrumbs: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/app/database/quality-templates',
|
||||||
|
name: 'QualityTemplates',
|
||||||
|
component: 'QualityTemplatesPage',
|
||||||
|
title: 'Plantillas de Calidad',
|
||||||
|
icon: 'settings',
|
||||||
|
requiresAuth: true,
|
||||||
|
requiredRoles: ROLE_COMBINATIONS.MANAGEMENT_ACCESS,
|
||||||
|
showInNavigation: true,
|
||||||
|
showInBreadcrumbs: true,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ from app.schemas.production import (
|
|||||||
ProductionStatusEnum
|
ProductionStatusEnum
|
||||||
)
|
)
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
from .quality_templates import router as quality_templates_router
|
|
||||||
|
|
||||||
logger = structlog.get_logger()
|
logger = structlog.get_logger()
|
||||||
|
|
||||||
@@ -1099,3 +1098,208 @@ async def get_yield_metrics(
|
|||||||
logger.error("Error getting yield metrics",
|
logger.error("Error getting yield metrics",
|
||||||
error=str(e), tenant_id=str(tenant_id))
|
error=str(e), tenant_id=str(tenant_id))
|
||||||
raise HTTPException(status_code=500, detail="Failed to get yield metrics")
|
raise HTTPException(status_code=500, detail="Failed to get yield metrics")
|
||||||
|
|
||||||
|
|
||||||
|
# ================================================================
|
||||||
|
# QUALITY TEMPLATES ENDPOINTS
|
||||||
|
# ================================================================
|
||||||
|
|
||||||
|
from app.repositories.quality_template_repository import QualityTemplateRepository
|
||||||
|
from app.schemas.quality_templates import (
|
||||||
|
QualityCheckTemplateCreate,
|
||||||
|
QualityCheckTemplateUpdate,
|
||||||
|
QualityCheckTemplateResponse,
|
||||||
|
QualityCheckTemplateList
|
||||||
|
)
|
||||||
|
|
||||||
|
@router.get("/tenants/{tenant_id}/production/quality-templates", response_model=QualityCheckTemplateList)
|
||||||
|
async def get_quality_templates(
|
||||||
|
tenant_id: UUID = Path(...),
|
||||||
|
stage: Optional[str] = Query(None, description="Filter by process stage"),
|
||||||
|
check_type: Optional[str] = Query(None, description="Filter by check type"),
|
||||||
|
is_active: Optional[bool] = Query(True, description="Filter by active status"),
|
||||||
|
skip: int = Query(0, ge=0),
|
||||||
|
limit: int = Query(100, ge=1, le=1000),
|
||||||
|
current_user: dict = Depends(get_current_user_dep),
|
||||||
|
db=Depends(get_db)
|
||||||
|
):
|
||||||
|
"""Get quality check templates for tenant"""
|
||||||
|
try:
|
||||||
|
repo = QualityTemplateRepository(db)
|
||||||
|
|
||||||
|
# Convert stage string to ProcessStage enum if provided
|
||||||
|
stage_enum = None
|
||||||
|
if stage:
|
||||||
|
try:
|
||||||
|
stage_enum = ProcessStage(stage)
|
||||||
|
except ValueError:
|
||||||
|
raise HTTPException(status_code=400, detail=f"Invalid stage: {stage}")
|
||||||
|
|
||||||
|
templates, total = await repo.get_templates_by_tenant(
|
||||||
|
tenant_id=str(tenant_id),
|
||||||
|
stage=stage_enum,
|
||||||
|
check_type=check_type,
|
||||||
|
is_active=is_active,
|
||||||
|
skip=skip,
|
||||||
|
limit=limit
|
||||||
|
)
|
||||||
|
|
||||||
|
return QualityCheckTemplateList(
|
||||||
|
templates=[QualityCheckTemplateResponse.from_orm(t) for t in templates],
|
||||||
|
total=total,
|
||||||
|
skip=skip,
|
||||||
|
limit=limit
|
||||||
|
)
|
||||||
|
|
||||||
|
except HTTPException:
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("Error getting quality templates",
|
||||||
|
error=str(e), tenant_id=str(tenant_id))
|
||||||
|
raise HTTPException(status_code=500, detail="Failed to get quality templates")
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/tenants/{tenant_id}/production/quality-templates", response_model=QualityCheckTemplateResponse)
|
||||||
|
async def create_quality_template(
|
||||||
|
template_data: QualityCheckTemplateCreate,
|
||||||
|
tenant_id: UUID = Path(...),
|
||||||
|
current_user: dict = Depends(get_current_user_dep),
|
||||||
|
db=Depends(get_db)
|
||||||
|
):
|
||||||
|
"""Create a new quality check template"""
|
||||||
|
try:
|
||||||
|
repo = QualityTemplateRepository(db)
|
||||||
|
|
||||||
|
# Add tenant_id to the template data
|
||||||
|
create_data = template_data.dict()
|
||||||
|
create_data['tenant_id'] = str(tenant_id)
|
||||||
|
|
||||||
|
template = await repo.create(create_data)
|
||||||
|
return QualityCheckTemplateResponse.from_orm(template)
|
||||||
|
except ValueError as e:
|
||||||
|
raise HTTPException(status_code=400, detail=str(e))
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("Error creating quality template",
|
||||||
|
error=str(e), tenant_id=str(tenant_id))
|
||||||
|
raise HTTPException(status_code=500, detail="Failed to create quality template")
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/tenants/{tenant_id}/production/quality-templates/{template_id}", response_model=QualityCheckTemplateResponse)
|
||||||
|
async def get_quality_template(
|
||||||
|
tenant_id: UUID = Path(...),
|
||||||
|
template_id: UUID = Path(...),
|
||||||
|
current_user: dict = Depends(get_current_user_dep),
|
||||||
|
db=Depends(get_db)
|
||||||
|
):
|
||||||
|
"""Get a specific quality check template"""
|
||||||
|
try:
|
||||||
|
repo = QualityTemplateRepository(db)
|
||||||
|
template = await repo.get_by_tenant_and_id(str(tenant_id), template_id)
|
||||||
|
if not template:
|
||||||
|
raise HTTPException(status_code=404, detail="Quality template not found")
|
||||||
|
return QualityCheckTemplateResponse.from_orm(template)
|
||||||
|
except HTTPException:
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("Error getting quality template",
|
||||||
|
error=str(e), tenant_id=str(tenant_id), template_id=str(template_id))
|
||||||
|
raise HTTPException(status_code=500, detail="Failed to get quality template")
|
||||||
|
|
||||||
|
|
||||||
|
@router.put("/tenants/{tenant_id}/production/quality-templates/{template_id}", response_model=QualityCheckTemplateResponse)
|
||||||
|
async def update_quality_template(
|
||||||
|
template_data: QualityCheckTemplateUpdate,
|
||||||
|
tenant_id: UUID = Path(...),
|
||||||
|
template_id: UUID = Path(...),
|
||||||
|
current_user: dict = Depends(get_current_user_dep),
|
||||||
|
db=Depends(get_db)
|
||||||
|
):
|
||||||
|
"""Update a quality check template"""
|
||||||
|
try:
|
||||||
|
repo = QualityTemplateRepository(db)
|
||||||
|
# First check if template exists and belongs to tenant
|
||||||
|
existing = await repo.get_by_tenant_and_id(str(tenant_id), template_id)
|
||||||
|
if not existing:
|
||||||
|
raise HTTPException(status_code=404, detail="Quality template not found")
|
||||||
|
|
||||||
|
template = await repo.update(template_id, template_data.dict(exclude_unset=True))
|
||||||
|
return QualityCheckTemplateResponse.from_orm(template)
|
||||||
|
except HTTPException:
|
||||||
|
raise
|
||||||
|
except ValueError as e:
|
||||||
|
raise HTTPException(status_code=400, detail=str(e))
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("Error updating quality template",
|
||||||
|
error=str(e), tenant_id=str(tenant_id), template_id=str(template_id))
|
||||||
|
raise HTTPException(status_code=500, detail="Failed to update quality template")
|
||||||
|
|
||||||
|
|
||||||
|
@router.delete("/tenants/{tenant_id}/production/quality-templates/{template_id}")
|
||||||
|
async def delete_quality_template(
|
||||||
|
tenant_id: UUID = Path(...),
|
||||||
|
template_id: UUID = Path(...),
|
||||||
|
current_user: dict = Depends(get_current_user_dep),
|
||||||
|
db=Depends(get_db)
|
||||||
|
):
|
||||||
|
"""Delete a quality check template"""
|
||||||
|
try:
|
||||||
|
repo = QualityTemplateRepository(db)
|
||||||
|
# First check if template exists and belongs to tenant
|
||||||
|
existing = await repo.get_by_tenant_and_id(str(tenant_id), template_id)
|
||||||
|
if not existing:
|
||||||
|
raise HTTPException(status_code=404, detail="Quality template not found")
|
||||||
|
|
||||||
|
await repo.delete(template_id)
|
||||||
|
return {"message": "Quality template deleted successfully"}
|
||||||
|
except HTTPException:
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("Error deleting quality template",
|
||||||
|
error=str(e), tenant_id=str(tenant_id), template_id=str(template_id))
|
||||||
|
raise HTTPException(status_code=500, detail="Failed to delete quality template")
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/tenants/{tenant_id}/production/quality-templates/{template_id}/duplicate", response_model=QualityCheckTemplateResponse)
|
||||||
|
async def duplicate_quality_template(
|
||||||
|
tenant_id: UUID = Path(...),
|
||||||
|
template_id: UUID = Path(...),
|
||||||
|
current_user: dict = Depends(get_current_user_dep),
|
||||||
|
db=Depends(get_db)
|
||||||
|
):
|
||||||
|
"""Duplicate an existing quality check template"""
|
||||||
|
try:
|
||||||
|
repo = QualityTemplateRepository(db)
|
||||||
|
# Get original template
|
||||||
|
original = await repo.get_by_tenant_and_id(str(tenant_id), template_id)
|
||||||
|
if not original:
|
||||||
|
raise HTTPException(status_code=404, detail="Quality template not found")
|
||||||
|
|
||||||
|
# Create duplicate data
|
||||||
|
duplicate_data = {
|
||||||
|
"tenant_id": original.tenant_id,
|
||||||
|
"name": f"{original.name} (Copy)",
|
||||||
|
"template_code": None, # Will be auto-generated
|
||||||
|
"check_type": original.check_type,
|
||||||
|
"category": original.category,
|
||||||
|
"description": original.description,
|
||||||
|
"instructions": original.instructions,
|
||||||
|
"criteria": original.criteria,
|
||||||
|
"is_required": original.is_required,
|
||||||
|
"is_critical": original.is_critical,
|
||||||
|
"weight": original.weight,
|
||||||
|
"min_value": original.min_value,
|
||||||
|
"max_value": original.max_value,
|
||||||
|
"unit": original.unit,
|
||||||
|
"tolerance_percentage": original.tolerance_percentage,
|
||||||
|
"applicable_stages": original.applicable_stages,
|
||||||
|
"created_by": original.created_by
|
||||||
|
}
|
||||||
|
|
||||||
|
template = await repo.create(duplicate_data)
|
||||||
|
return QualityCheckTemplateResponse.from_orm(template)
|
||||||
|
except HTTPException:
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("Error duplicating quality template",
|
||||||
|
error=str(e), tenant_id=str(tenant_id), template_id=str(template_id))
|
||||||
|
raise HTTPException(status_code=500, detail="Failed to duplicate quality template")
|
||||||
@@ -1,174 +0,0 @@
|
|||||||
# services/production/app/api/quality_templates.py
|
|
||||||
"""
|
|
||||||
Quality Check Template API endpoints for production service
|
|
||||||
"""
|
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException, status, Query
|
|
||||||
from sqlalchemy.orm import Session
|
|
||||||
from typing import List, Optional
|
|
||||||
from uuid import UUID
|
|
||||||
|
|
||||||
from ..core.database import get_db
|
|
||||||
from ..models.production import QualityCheckTemplate, ProcessStage
|
|
||||||
from ..services.quality_template_service import QualityTemplateService
|
|
||||||
from ..schemas.quality_templates import (
|
|
||||||
QualityCheckTemplateCreate,
|
|
||||||
QualityCheckTemplateUpdate,
|
|
||||||
QualityCheckTemplateResponse,
|
|
||||||
QualityCheckTemplateList
|
|
||||||
)
|
|
||||||
from shared.auth.tenant_access import get_current_tenant_id
|
|
||||||
|
|
||||||
router = APIRouter(prefix="/quality-templates", tags=["quality-templates"])
|
|
||||||
|
|
||||||
|
|
||||||
@router.post("", response_model=QualityCheckTemplateResponse, status_code=status.HTTP_201_CREATED)
|
|
||||||
async def create_quality_template(
|
|
||||||
template_data: QualityCheckTemplateCreate,
|
|
||||||
tenant_id: str = Depends(get_current_tenant_id),
|
|
||||||
db: Session = Depends(get_db)
|
|
||||||
):
|
|
||||||
"""Create a new quality check template"""
|
|
||||||
try:
|
|
||||||
service = QualityTemplateService(db)
|
|
||||||
template = await service.create_template(tenant_id, template_data)
|
|
||||||
return QualityCheckTemplateResponse.from_orm(template)
|
|
||||||
except ValueError as e:
|
|
||||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
|
|
||||||
except Exception as e:
|
|
||||||
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("", response_model=QualityCheckTemplateList)
|
|
||||||
async def get_quality_templates(
|
|
||||||
tenant_id: str = Depends(get_current_tenant_id),
|
|
||||||
stage: Optional[ProcessStage] = Query(None, description="Filter by process stage"),
|
|
||||||
check_type: Optional[str] = Query(None, description="Filter by check type"),
|
|
||||||
is_active: Optional[bool] = Query(True, description="Filter by active status"),
|
|
||||||
skip: int = Query(0, ge=0),
|
|
||||||
limit: int = Query(100, ge=1, le=1000),
|
|
||||||
db: Session = Depends(get_db)
|
|
||||||
):
|
|
||||||
"""Get quality check templates for tenant"""
|
|
||||||
try:
|
|
||||||
service = QualityTemplateService(db)
|
|
||||||
templates, total = await service.get_templates(
|
|
||||||
tenant_id=tenant_id,
|
|
||||||
stage=stage,
|
|
||||||
check_type=check_type,
|
|
||||||
is_active=is_active,
|
|
||||||
skip=skip,
|
|
||||||
limit=limit
|
|
||||||
)
|
|
||||||
|
|
||||||
return QualityCheckTemplateList(
|
|
||||||
templates=[QualityCheckTemplateResponse.from_orm(t) for t in templates],
|
|
||||||
total=total,
|
|
||||||
skip=skip,
|
|
||||||
limit=limit
|
|
||||||
)
|
|
||||||
except Exception as e:
|
|
||||||
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/{template_id}", response_model=QualityCheckTemplateResponse)
|
|
||||||
async def get_quality_template(
|
|
||||||
template_id: UUID,
|
|
||||||
tenant_id: str = Depends(get_current_tenant_id),
|
|
||||||
db: Session = Depends(get_db)
|
|
||||||
):
|
|
||||||
"""Get a specific quality check template"""
|
|
||||||
try:
|
|
||||||
service = QualityTemplateService(db)
|
|
||||||
template = await service.get_template(tenant_id, template_id)
|
|
||||||
if not template:
|
|
||||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Template not found")
|
|
||||||
|
|
||||||
return QualityCheckTemplateResponse.from_orm(template)
|
|
||||||
except HTTPException:
|
|
||||||
raise
|
|
||||||
except Exception as e:
|
|
||||||
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
|
|
||||||
|
|
||||||
|
|
||||||
@router.put("/{template_id}", response_model=QualityCheckTemplateResponse)
|
|
||||||
async def update_quality_template(
|
|
||||||
template_id: UUID,
|
|
||||||
template_data: QualityCheckTemplateUpdate,
|
|
||||||
tenant_id: str = Depends(get_current_tenant_id),
|
|
||||||
db: Session = Depends(get_db)
|
|
||||||
):
|
|
||||||
"""Update a quality check template"""
|
|
||||||
try:
|
|
||||||
service = QualityTemplateService(db)
|
|
||||||
template = await service.update_template(tenant_id, template_id, template_data)
|
|
||||||
if not template:
|
|
||||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Template not found")
|
|
||||||
|
|
||||||
return QualityCheckTemplateResponse.from_orm(template)
|
|
||||||
except HTTPException:
|
|
||||||
raise
|
|
||||||
except ValueError as e:
|
|
||||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
|
|
||||||
except Exception as e:
|
|
||||||
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
|
|
||||||
|
|
||||||
|
|
||||||
@router.delete("/{template_id}", status_code=status.HTTP_204_NO_CONTENT)
|
|
||||||
async def delete_quality_template(
|
|
||||||
template_id: UUID,
|
|
||||||
tenant_id: str = Depends(get_current_tenant_id),
|
|
||||||
db: Session = Depends(get_db)
|
|
||||||
):
|
|
||||||
"""Delete a quality check template"""
|
|
||||||
try:
|
|
||||||
service = QualityTemplateService(db)
|
|
||||||
success = await service.delete_template(tenant_id, template_id)
|
|
||||||
if not success:
|
|
||||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Template not found")
|
|
||||||
except HTTPException:
|
|
||||||
raise
|
|
||||||
except Exception as e:
|
|
||||||
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/stages/{stage}", response_model=QualityCheckTemplateList)
|
|
||||||
async def get_templates_for_stage(
|
|
||||||
stage: ProcessStage,
|
|
||||||
tenant_id: str = Depends(get_current_tenant_id),
|
|
||||||
is_active: Optional[bool] = Query(True, description="Filter by active status"),
|
|
||||||
db: Session = Depends(get_db)
|
|
||||||
):
|
|
||||||
"""Get quality check templates applicable to a specific process stage"""
|
|
||||||
try:
|
|
||||||
service = QualityTemplateService(db)
|
|
||||||
templates = await service.get_templates_for_stage(tenant_id, stage, is_active)
|
|
||||||
|
|
||||||
return QualityCheckTemplateList(
|
|
||||||
templates=[QualityCheckTemplateResponse.from_orm(t) for t in templates],
|
|
||||||
total=len(templates),
|
|
||||||
skip=0,
|
|
||||||
limit=len(templates)
|
|
||||||
)
|
|
||||||
except Exception as e:
|
|
||||||
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
|
|
||||||
|
|
||||||
|
|
||||||
@router.post("/{template_id}/duplicate", response_model=QualityCheckTemplateResponse, status_code=status.HTTP_201_CREATED)
|
|
||||||
async def duplicate_quality_template(
|
|
||||||
template_id: UUID,
|
|
||||||
tenant_id: str = Depends(get_current_tenant_id),
|
|
||||||
db: Session = Depends(get_db)
|
|
||||||
):
|
|
||||||
"""Duplicate an existing quality check template"""
|
|
||||||
try:
|
|
||||||
service = QualityTemplateService(db)
|
|
||||||
template = await service.duplicate_template(tenant_id, template_id)
|
|
||||||
if not template:
|
|
||||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Template not found")
|
|
||||||
|
|
||||||
return QualityCheckTemplateResponse.from_orm(template)
|
|
||||||
except HTTPException:
|
|
||||||
raise
|
|
||||||
except Exception as e:
|
|
||||||
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
|
|
||||||
@@ -14,7 +14,6 @@ import structlog
|
|||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
from app.core.database import init_database, get_db_health
|
from app.core.database import init_database, get_db_health
|
||||||
from app.api.production import router as production_router
|
from app.api.production import router as production_router
|
||||||
from app.api.quality_templates import router as quality_templates_router
|
|
||||||
from app.services.production_alert_service import ProductionAlertService
|
from app.services.production_alert_service import ProductionAlertService
|
||||||
|
|
||||||
# Configure logging
|
# Configure logging
|
||||||
@@ -74,7 +73,6 @@ app.add_middleware(
|
|||||||
|
|
||||||
# Include routers
|
# Include routers
|
||||||
app.include_router(production_router, prefix="/api/v1")
|
app.include_router(production_router, prefix="/api/v1")
|
||||||
app.include_router(quality_templates_router, prefix="/api/v1")
|
|
||||||
|
|
||||||
|
|
||||||
@app.get("/health")
|
@app.get("/health")
|
||||||
|
|||||||
@@ -43,6 +43,17 @@ class EquipmentStatus(str, enum.Enum):
|
|||||||
WARNING = "warning"
|
WARNING = "warning"
|
||||||
|
|
||||||
|
|
||||||
|
class ProcessStage(str, enum.Enum):
|
||||||
|
"""Production process stages where quality checks can occur"""
|
||||||
|
MIXING = "mixing"
|
||||||
|
PROOFING = "proofing"
|
||||||
|
SHAPING = "shaping"
|
||||||
|
BAKING = "baking"
|
||||||
|
COOLING = "cooling"
|
||||||
|
PACKAGING = "packaging"
|
||||||
|
FINISHING = "finishing"
|
||||||
|
|
||||||
|
|
||||||
class EquipmentType(str, enum.Enum):
|
class EquipmentType(str, enum.Enum):
|
||||||
"""Equipment type enumeration"""
|
"""Equipment type enumeration"""
|
||||||
OVEN = "oven"
|
OVEN = "oven"
|
||||||
@@ -329,17 +340,6 @@ class ProductionCapacity(Base):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class ProcessStage(str, enum.Enum):
|
|
||||||
"""Production process stages where quality checks can occur"""
|
|
||||||
MIXING = "mixing"
|
|
||||||
PROOFING = "proofing"
|
|
||||||
SHAPING = "shaping"
|
|
||||||
BAKING = "baking"
|
|
||||||
COOLING = "cooling"
|
|
||||||
PACKAGING = "packaging"
|
|
||||||
FINISHING = "finishing"
|
|
||||||
|
|
||||||
|
|
||||||
class QualityCheckTemplate(Base):
|
class QualityCheckTemplate(Base):
|
||||||
"""Quality check templates for tenant-specific quality standards"""
|
"""Quality check templates for tenant-specific quality standards"""
|
||||||
__tablename__ = "quality_check_templates"
|
__tablename__ = "quality_check_templates"
|
||||||
|
|||||||
@@ -0,0 +1,152 @@
|
|||||||
|
"""
|
||||||
|
Quality Template Repository for Production Service
|
||||||
|
"""
|
||||||
|
|
||||||
|
from typing import List, Optional, Tuple
|
||||||
|
from sqlalchemy import and_, or_, func, select
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
from uuid import UUID
|
||||||
|
import structlog
|
||||||
|
|
||||||
|
from .base import ProductionBaseRepository
|
||||||
|
from ..models.production import QualityCheckTemplate, ProcessStage
|
||||||
|
|
||||||
|
logger = structlog.get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class QualityTemplateRepository(ProductionBaseRepository):
|
||||||
|
"""Repository for quality check template operations"""
|
||||||
|
|
||||||
|
def __init__(self, session: AsyncSession):
|
||||||
|
super().__init__(QualityCheckTemplate, session)
|
||||||
|
|
||||||
|
async def get_templates_by_tenant(
|
||||||
|
self,
|
||||||
|
tenant_id: str,
|
||||||
|
stage: Optional[ProcessStage] = None,
|
||||||
|
check_type: Optional[str] = None,
|
||||||
|
is_active: Optional[bool] = True,
|
||||||
|
skip: int = 0,
|
||||||
|
limit: int = 100
|
||||||
|
) -> Tuple[List[QualityCheckTemplate], int]:
|
||||||
|
"""Get quality check templates with filtering and pagination"""
|
||||||
|
|
||||||
|
filters = [QualityCheckTemplate.tenant_id == tenant_id]
|
||||||
|
|
||||||
|
if is_active is not None:
|
||||||
|
filters.append(QualityCheckTemplate.is_active == is_active)
|
||||||
|
|
||||||
|
if check_type:
|
||||||
|
filters.append(QualityCheckTemplate.check_type == check_type)
|
||||||
|
|
||||||
|
if stage:
|
||||||
|
filters.append(
|
||||||
|
or_(
|
||||||
|
func.json_contains(
|
||||||
|
QualityCheckTemplate.applicable_stages,
|
||||||
|
f'"{stage.value}"'
|
||||||
|
),
|
||||||
|
QualityCheckTemplate.applicable_stages.is_(None)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Get total count with SQLAlchemy conditions
|
||||||
|
count_query = select(func.count(QualityCheckTemplate.id)).where(and_(*filters))
|
||||||
|
count_result = await self.session.execute(count_query)
|
||||||
|
total = count_result.scalar()
|
||||||
|
|
||||||
|
# Get templates with ordering
|
||||||
|
query = select(QualityCheckTemplate).where(and_(*filters)).order_by(
|
||||||
|
QualityCheckTemplate.is_critical.desc(),
|
||||||
|
QualityCheckTemplate.is_required.desc(),
|
||||||
|
QualityCheckTemplate.name
|
||||||
|
).offset(skip).limit(limit)
|
||||||
|
|
||||||
|
result = await self.session.execute(query)
|
||||||
|
templates = result.scalars().all()
|
||||||
|
|
||||||
|
return templates, total
|
||||||
|
|
||||||
|
async def get_by_tenant_and_id(
|
||||||
|
self,
|
||||||
|
tenant_id: str,
|
||||||
|
template_id: UUID
|
||||||
|
) -> Optional[QualityCheckTemplate]:
|
||||||
|
"""Get a specific quality check template by tenant and ID"""
|
||||||
|
|
||||||
|
return await self.get_by_filters(
|
||||||
|
and_(
|
||||||
|
QualityCheckTemplate.tenant_id == tenant_id,
|
||||||
|
QualityCheckTemplate.id == template_id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
async def get_templates_for_stage(
|
||||||
|
self,
|
||||||
|
tenant_id: str,
|
||||||
|
stage: ProcessStage,
|
||||||
|
is_active: Optional[bool] = True
|
||||||
|
) -> List[QualityCheckTemplate]:
|
||||||
|
"""Get all quality check templates applicable to a specific process stage"""
|
||||||
|
|
||||||
|
filters = [
|
||||||
|
QualityCheckTemplate.tenant_id == tenant_id,
|
||||||
|
or_(
|
||||||
|
func.json_contains(
|
||||||
|
QualityCheckTemplate.applicable_stages,
|
||||||
|
f'"{stage.value}"'
|
||||||
|
),
|
||||||
|
QualityCheckTemplate.applicable_stages.is_(None)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
if is_active is not None:
|
||||||
|
filters.append(QualityCheckTemplate.is_active == is_active)
|
||||||
|
|
||||||
|
return await self.get_multi(
|
||||||
|
filters=and_(*filters),
|
||||||
|
order_by=[
|
||||||
|
QualityCheckTemplate.is_critical.desc(),
|
||||||
|
QualityCheckTemplate.is_required.desc(),
|
||||||
|
QualityCheckTemplate.weight.desc(),
|
||||||
|
QualityCheckTemplate.name
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
async def check_template_code_exists(
|
||||||
|
self,
|
||||||
|
tenant_id: str,
|
||||||
|
template_code: str,
|
||||||
|
exclude_id: Optional[UUID] = None
|
||||||
|
) -> bool:
|
||||||
|
"""Check if a template code already exists for the tenant"""
|
||||||
|
|
||||||
|
filters = [
|
||||||
|
QualityCheckTemplate.tenant_id == tenant_id,
|
||||||
|
QualityCheckTemplate.template_code == template_code
|
||||||
|
]
|
||||||
|
|
||||||
|
if exclude_id:
|
||||||
|
filters.append(QualityCheckTemplate.id != exclude_id)
|
||||||
|
|
||||||
|
existing = await self.get_by_filters(and_(*filters))
|
||||||
|
return existing is not None
|
||||||
|
|
||||||
|
async def get_templates_by_ids(
|
||||||
|
self,
|
||||||
|
tenant_id: str,
|
||||||
|
template_ids: List[UUID]
|
||||||
|
) -> List[QualityCheckTemplate]:
|
||||||
|
"""Get quality check templates by list of IDs"""
|
||||||
|
|
||||||
|
return await self.get_multi(
|
||||||
|
filters=and_(
|
||||||
|
QualityCheckTemplate.tenant_id == tenant_id,
|
||||||
|
QualityCheckTemplate.id.in_(template_ids)
|
||||||
|
),
|
||||||
|
order_by=[
|
||||||
|
QualityCheckTemplate.is_critical.desc(),
|
||||||
|
QualityCheckTemplate.is_required.desc(),
|
||||||
|
QualityCheckTemplate.weight.desc()
|
||||||
|
]
|
||||||
|
)
|
||||||
@@ -104,7 +104,7 @@ class ProductionAlertService(BaseAlertService, AlertServiceMixin):
|
|||||||
JOIN production_capacity pc ON pc.equipment_id = p.equipment_id
|
JOIN production_capacity pc ON pc.equipment_id = p.equipment_id
|
||||||
WHERE p.planned_date >= CURRENT_DATE
|
WHERE p.planned_date >= CURRENT_DATE
|
||||||
AND p.planned_date <= CURRENT_DATE + INTERVAL '3 days'
|
AND p.planned_date <= CURRENT_DATE + INTERVAL '3 days'
|
||||||
AND p.status IN ('planned', 'in_progress')
|
AND p.status IN ('PENDING', 'IN_PROGRESS')
|
||||||
AND p.tenant_id = $1
|
AND p.tenant_id = $1
|
||||||
GROUP BY p.tenant_id, p.planned_date
|
GROUP BY p.tenant_id, p.planned_date
|
||||||
)
|
)
|
||||||
@@ -226,10 +226,10 @@ class ProductionAlertService(BaseAlertService, AlertServiceMixin):
|
|||||||
COALESCE(pb.priority::text, 'medium') as priority_level,
|
COALESCE(pb.priority::text, 'medium') as priority_level,
|
||||||
1 as affected_orders -- Default to 1 since we can't count orders
|
1 as affected_orders -- Default to 1 since we can't count orders
|
||||||
FROM production_batches pb
|
FROM production_batches pb
|
||||||
WHERE pb.status IN ('IN_PROGRESS', 'DELAYED')
|
WHERE pb.status IN ('IN_PROGRESS', 'ON_HOLD', 'QUALITY_CHECK')
|
||||||
AND (
|
AND (
|
||||||
(pb.planned_end_time < NOW() AND pb.status = 'IN_PROGRESS')
|
(pb.planned_end_time < NOW() AND pb.status = 'IN_PROGRESS')
|
||||||
OR pb.status = 'DELAYED'
|
OR pb.status IN ('ON_HOLD', 'QUALITY_CHECK')
|
||||||
)
|
)
|
||||||
AND pb.planned_end_time > NOW() - INTERVAL '24 hours'
|
AND pb.planned_end_time > NOW() - INTERVAL '24 hours'
|
||||||
ORDER BY
|
ORDER BY
|
||||||
@@ -831,7 +831,7 @@ class ProductionAlertService(BaseAlertService, AlertServiceMixin):
|
|||||||
FROM production_batches pb
|
FROM production_batches pb
|
||||||
JOIN recipe_ingredients ri ON ri.recipe_id = pb.recipe_id
|
JOIN recipe_ingredients ri ON ri.recipe_id = pb.recipe_id
|
||||||
WHERE ri.ingredient_id = $1
|
WHERE ri.ingredient_id = $1
|
||||||
AND pb.status IN ('planned', 'in_progress')
|
AND pb.status IN ('PENDING', 'IN_PROGRESS')
|
||||||
AND pb.planned_completion_time > NOW()
|
AND pb.planned_completion_time > NOW()
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class QualityTemplateService:
|
|||||||
def __init__(self, db: Session):
|
def __init__(self, db: Session):
|
||||||
self.db = db
|
self.db = db
|
||||||
|
|
||||||
async def create_template(
|
def create_template(
|
||||||
self,
|
self,
|
||||||
tenant_id: str,
|
tenant_id: str,
|
||||||
template_data: QualityCheckTemplateCreate
|
template_data: QualityCheckTemplateCreate
|
||||||
@@ -50,7 +50,7 @@ class QualityTemplateService:
|
|||||||
|
|
||||||
return template
|
return template
|
||||||
|
|
||||||
async def get_templates(
|
def get_templates(
|
||||||
self,
|
self,
|
||||||
tenant_id: str,
|
tenant_id: str,
|
||||||
stage: Optional[ProcessStage] = None,
|
stage: Optional[ProcessStage] = None,
|
||||||
@@ -93,7 +93,7 @@ class QualityTemplateService:
|
|||||||
|
|
||||||
return templates, total
|
return templates, total
|
||||||
|
|
||||||
async def get_template(
|
def get_template(
|
||||||
self,
|
self,
|
||||||
tenant_id: str,
|
tenant_id: str,
|
||||||
template_id: UUID
|
template_id: UUID
|
||||||
@@ -107,7 +107,7 @@ class QualityTemplateService:
|
|||||||
)
|
)
|
||||||
).first()
|
).first()
|
||||||
|
|
||||||
async def update_template(
|
def update_template(
|
||||||
self,
|
self,
|
||||||
tenant_id: str,
|
tenant_id: str,
|
||||||
template_id: UUID,
|
template_id: UUID,
|
||||||
@@ -115,7 +115,7 @@ class QualityTemplateService:
|
|||||||
) -> Optional[QualityCheckTemplate]:
|
) -> Optional[QualityCheckTemplate]:
|
||||||
"""Update a quality check template"""
|
"""Update a quality check template"""
|
||||||
|
|
||||||
template = await self.get_template(tenant_id, template_id)
|
template = self.get_template(tenant_id, template_id)
|
||||||
if not template:
|
if not template:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -143,14 +143,14 @@ class QualityTemplateService:
|
|||||||
|
|
||||||
return template
|
return template
|
||||||
|
|
||||||
async def delete_template(
|
def delete_template(
|
||||||
self,
|
self,
|
||||||
tenant_id: str,
|
tenant_id: str,
|
||||||
template_id: UUID
|
template_id: UUID
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""Delete a quality check template"""
|
"""Delete a quality check template"""
|
||||||
|
|
||||||
template = await self.get_template(tenant_id, template_id)
|
template = self.get_template(tenant_id, template_id)
|
||||||
if not template:
|
if not template:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -165,7 +165,7 @@ class QualityTemplateService:
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
async def get_templates_for_stage(
|
def get_templates_for_stage(
|
||||||
self,
|
self,
|
||||||
tenant_id: str,
|
tenant_id: str,
|
||||||
stage: ProcessStage,
|
stage: ProcessStage,
|
||||||
@@ -198,14 +198,14 @@ class QualityTemplateService:
|
|||||||
QualityCheckTemplate.name
|
QualityCheckTemplate.name
|
||||||
).all()
|
).all()
|
||||||
|
|
||||||
async def duplicate_template(
|
def duplicate_template(
|
||||||
self,
|
self,
|
||||||
tenant_id: str,
|
tenant_id: str,
|
||||||
template_id: UUID
|
template_id: UUID
|
||||||
) -> Optional[QualityCheckTemplate]:
|
) -> Optional[QualityCheckTemplate]:
|
||||||
"""Duplicate an existing quality check template"""
|
"""Duplicate an existing quality check template"""
|
||||||
|
|
||||||
original = await self.get_template(tenant_id, template_id)
|
original = self.get_template(tenant_id, template_id)
|
||||||
if not original:
|
if not original:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -234,9 +234,9 @@ class QualityTemplateService:
|
|||||||
}
|
}
|
||||||
|
|
||||||
create_data = QualityCheckTemplateCreate(**duplicate_data)
|
create_data = QualityCheckTemplateCreate(**duplicate_data)
|
||||||
return await self.create_template(tenant_id, create_data)
|
return self.create_template(tenant_id, create_data)
|
||||||
|
|
||||||
async def get_templates_by_recipe_config(
|
def get_templates_by_recipe_config(
|
||||||
self,
|
self,
|
||||||
tenant_id: str,
|
tenant_id: str,
|
||||||
stage: ProcessStage,
|
stage: ProcessStage,
|
||||||
@@ -268,7 +268,7 @@ class QualityTemplateService:
|
|||||||
|
|
||||||
return templates
|
return templates
|
||||||
|
|
||||||
async def validate_template_configuration(
|
def validate_template_configuration(
|
||||||
self,
|
self,
|
||||||
tenant_id: str,
|
tenant_id: str,
|
||||||
template_data: dict
|
template_data: dict
|
||||||
|
|||||||
Reference in New Issue
Block a user