feat(f6.8): harden offline field flow and act documents
Android CI / RC / Android · lint, tests, debug APK, release compile (push) Successful in 3m41s
DH V2 CI / API · typecheck, tests, build (push) Successful in 31s
DH V2 CI / WEB · typecheck, build (push) Successful in 19s
Production dependency audit / API · production dependencies (push) Successful in 9s
Production dependency audit / WEB · production dependencies (push) Successful in 8s
DH V2 CI / Docker / scripts contract (push) Successful in 1m14s

This commit is contained in:
DH V2
2026-09-15 15:56:50 -03:00
parent 47cd985931
commit 079728aa6d
62 changed files with 2240 additions and 338 deletions
@@ -98,7 +98,7 @@ export class InventoryFamilyCatalogService {
) VALUES ($1,$2,$3,NULL,$4::jsonb,'MANUAL:F6',true)
RETURNING id
`,[code,dto.name,dto.level,JSON.stringify(this.cleanLabels(dto.informationLabels ?? []))])) as Array<{id:string}>;
if (!inserted) throw new Error('No se pudo crear la clasificación de Inventario');
if (!inserted) throw new Error('No se pudo crear el tipo de Inventario');
await this.replaceParents(manager, inserted.id, parentIds);
const created = await this.family(inserted.id,false,manager);
await this.audit.record({
@@ -186,7 +186,7 @@ export class InventoryFamilyCatalogService {
} catch (error) {
if (this.isUniqueViolation(error)) throw new ConflictException({
code:'INVENTORY_FAMILY_ATTRIBUTE_CODE_EXISTS',
message:'Ya existe un campo técnico con ese código en la clasificación',
message:'Ya existe un campo técnico con ese código en el tipo',
});
throw error;
}
@@ -328,7 +328,7 @@ export class InventoryFamilyCatalogService {
${lockClause}
`),[familyId])) as FamilyRow[];
if (!rows[0]) throw new NotFoundException({
code:'INVENTORY_FAMILY_NOT_FOUND',message:'La clasificación de Inventario no existe',
code:'INVENTORY_FAMILY_NOT_FOUND',message:'El tipo de Inventario no existe',
});
return rows[0];
}
@@ -343,7 +343,7 @@ export class InventoryFamilyCatalogService {
if (level==='INSTALLATION') {
if (ids.length) throw new BadRequestException({
code:'INVENTORY_FAMILY_PARENT_NOT_ALLOWED',
message:'Una clasificación de Instalación no lleva compatibilidades padre',
message:'Un tipo de Instalación no lleva compatibilidades padre',
});
return [];
}
@@ -352,7 +352,7 @@ export class InventoryFamilyCatalogService {
message:'Elegí al menos un tipo de Instalación compatible con esta Subinstalación',
});
if (ownId && ids.includes(ownId)) throw new BadRequestException({
code:'INVENTORY_FAMILY_PARENT_CYCLE',message:'Una clasificación no puede ser compatible consigo misma',
code:'INVENTORY_FAMILY_PARENT_CYCLE',message:'Un tipo no puede ser compatible consigo mismo',
});
const [count]=(await manager.query(`
SELECT COUNT(*)::integer AS total FROM inventory_families
@@ -434,7 +434,7 @@ export class InventoryFamilyCatalogService {
if (!unique.has(identity)) unique.set(identity,clean);
}
if (unique.size>100) throw new ConflictException({
code:'INVENTORY_FAMILY_TOO_MANY_FIELDS',message:'La clasificación admite hasta 100 campos de información',
code:'INVENTORY_FAMILY_TOO_MANY_FIELDS',message:'El tipo admite hasta 100 campos de información',
});
return [...unique.values()];
}