feature/mensajes-claros-en-eliminar-clases
This commit is contained in:
@@ -370,11 +370,46 @@ class ClassService:
|
||||
def delete(db: Session, class_id: int, tenant_id: int, company_id: int) -> bool:
|
||||
"""Delete a class (and its FA extension if exists)"""
|
||||
from api.v1.modules.a24.fa.fa_classes.models import QClasses
|
||||
|
||||
from api.v1.modules.a76.items.models import LineItem
|
||||
from api.v1.modules.a76.parts.models import Part
|
||||
|
||||
class_obj = ClassService.get_by_id(db, class_id, tenant_id, company_id)
|
||||
if not class_obj:
|
||||
return False
|
||||
|
||||
used_in_parts = (
|
||||
db.query(Part.id)
|
||||
.filter(
|
||||
Part.part_class == class_obj.class_code,
|
||||
Part.tenant_id == tenant_id,
|
||||
Part.company_id == company_id,
|
||||
)
|
||||
.first()
|
||||
is not None
|
||||
)
|
||||
used_in_invoices = (
|
||||
db.query(LineItem.id)
|
||||
.filter(
|
||||
LineItem.class_id == class_id,
|
||||
LineItem.tenant_id == tenant_id,
|
||||
LineItem.company_id == company_id,
|
||||
)
|
||||
.first()
|
||||
is not None
|
||||
)
|
||||
|
||||
if used_in_parts or used_in_invoices:
|
||||
reasons: list[str] = []
|
||||
if used_in_parts:
|
||||
reasons.append("partes")
|
||||
if used_in_invoices:
|
||||
reasons.append("facturas")
|
||||
usage = " y ".join(reasons)
|
||||
raise HTTPException(
|
||||
status_code=409,
|
||||
detail=f"No se puede eliminar la clase porque ya fue utilizada en {usage}.",
|
||||
)
|
||||
|
||||
# Delete FA extension first (if exists) to avoid FK constraint violation
|
||||
fa_extension = db.query(QClasses).filter(
|
||||
QClasses.class_id == class_id,
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import FixedAssetClassForm from '$lib/components/dashboard/goods/classes/forms/FixedAssetClassForm.svelte';
|
||||
import { Folder, Save, Plus, RefreshCw } from 'lucide-svelte';
|
||||
import { toast } from 'svelte-sonner';
|
||||
import { friendlyApiErrorParts, type ApiResponse } from '$lib/api';
|
||||
import { classesApi, type A76Class } from '$lib/api/dashboard/a76/classes';
|
||||
import { faClassesApi, type FAClass } from '$lib/api/dashboard/a24/fa_classes';
|
||||
import { companyStore } from '$lib/stores/company.svelte';
|
||||
@@ -321,29 +322,33 @@
|
||||
|
||||
const idsToDelete = [...selectedClassIds];
|
||||
let okCount = 0;
|
||||
const errors: number[] = [];
|
||||
const failedResponses: ApiResponse[] = [];
|
||||
|
||||
for (const id of idsToDelete) {
|
||||
try {
|
||||
// El backend elimina automáticamente la extensión FA si existe
|
||||
await classesApi.delete(id, companyId);
|
||||
// El backend elimina automáticamente la extensión FA si existe
|
||||
const res = await classesApi.delete(id, companyId);
|
||||
if (res.status >= 400 || res.error) {
|
||||
console.error(`Error deleting class ${id}:`, res.error ?? res.status);
|
||||
failedResponses.push(res);
|
||||
} else {
|
||||
okCount++;
|
||||
} catch (error) {
|
||||
console.error(`Error deleting class ${id}:`, error);
|
||||
errors.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
if (errors.length === 0) {
|
||||
if (failedResponses.length === 0) {
|
||||
toast.success(
|
||||
okCount === 1
|
||||
? 'Clase eliminada correctamente'
|
||||
: `${okCount} clases eliminadas correctamente`
|
||||
);
|
||||
} else if (okCount === 0) {
|
||||
toast.error(`Error al eliminar ${errors.length} clase(s)`);
|
||||
const { title, description } = friendlyApiErrorParts(failedResponses[0]);
|
||||
toast.error(title, { description });
|
||||
} else {
|
||||
toast.error(`${okCount} eliminada(s), ${errors.length} con error`);
|
||||
const { title, description } = friendlyApiErrorParts(failedResponses[0]);
|
||||
toast.error(`${okCount} eliminada(s), ${failedResponses.length} con error`, {
|
||||
description: description || title
|
||||
});
|
||||
}
|
||||
|
||||
await loadClasses();
|
||||
|
||||
Reference in New Issue
Block a user