Compare commits

...

2 Commits

10 changed files with 2177 additions and 31 deletions

View File

@@ -0,0 +1,2 @@
DROP VIEW "public"."v_training_surveys";--> statement-breakpoint
ALTER TABLE "training_surveys" ADD COLUMN "productive_activity_other" text DEFAULT '';

File diff suppressed because it is too large Load Diff

View File

@@ -183,6 +183,13 @@
"when": 1772643066120, "when": 1772643066120,
"tag": "0025_funny_makkari", "tag": "0025_funny_makkari",
"breakpoints": true "breakpoints": true
},
{
"idx": 26,
"version": "7",
"when": 1774379641691,
"tag": "0026_last_vampiro",
"breakpoints": true
} }
] ]
} }

View File

@@ -76,6 +76,7 @@ export const trainingSurveys = t.pgTable(
.notNull() .notNull()
.default(''), .default(''),
productiveActivity: t.text('productive_activity').notNull(), productiveActivity: t.text('productive_activity').notNull(),
productiveActivityOther: t.text('productive_activity_other').default(''),
ospRif: t.text('osp_rif'), ospRif: t.text('osp_rif'),
ospName: t.text('osp_name'), ospName: t.text('osp_name'),
companyConstitutionYear: t.integer('company_constitution_year').notNull(), companyConstitutionYear: t.integer('company_constitution_year').notNull(),

View File

@@ -1,3 +1,4 @@
import { Optional } from '@nestjs/common';
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from '@nestjs/swagger';
import { Transform, Type } from 'class-transformer'; import { Transform, Type } from 'class-transformer';
import { import {
@@ -42,6 +43,11 @@ export class CreateTrainingDto {
@IsString() @IsString()
productiveActivity: string; productiveActivity: string;
@ApiProperty()
@IsString()
@IsOptional()
productiveActivityOther: string;
@ApiProperty() @ApiProperty()
@IsString() @IsString()
currentStatus: string; currentStatus: string;

View File

@@ -16,7 +16,7 @@ export class TrainingService {
constructor( constructor(
@Inject(DRIZZLE_PROVIDER) private drizzle: NodePgDatabase<typeof schema>, @Inject(DRIZZLE_PROVIDER) private drizzle: NodePgDatabase<typeof schema>,
private readonly minioService: MinioService, private readonly minioService: MinioService,
) {} ) { }
async findAll(paginationDto?: PaginationDto) { async findAll(paginationDto?: PaginationDto) {
const { const {
@@ -268,7 +268,7 @@ export class TrainingService {
// 2. Extraer solo visitDate para formatearlo. // 2. Extraer solo visitDate para formatearlo.
// Ya NO extraemos state, municipality, etc. porque no vienen en el DTO. // Ya NO extraemos state, municipality, etc. porque no vienen en el DTO.
const { visitDate, state, municipality, parish, ...rest } = const { visitDate, state, municipality, parish, productiveActivityOther, ...rest } =
createTrainingDto; createTrainingDto;
const [newRecord] = await this.drizzle const [newRecord] = await this.drizzle
@@ -280,6 +280,9 @@ export class TrainingService {
// Conversión de fecha // Conversión de fecha
visitDate: new Date(visitDate), visitDate: new Date(visitDate),
// Borra las tildes y cambia el texto a mayusculas
productiveActivityOther: productiveActivityOther.toUpperCase().normalize("NFD").replace(/[\u0300-\u036f]/g, ""),
// 3. Asignar fotos de forma segura // 3. Asignar fotos de forma segura
photo1: photoPaths[0] ?? null, photo1: photoPaths[0] ?? null,
photo2: photoPaths[1] ?? null, photo2: photoPaths[1] ?? null,

View File

@@ -107,6 +107,7 @@ export function CreateTrainingForm({
coorPhone: defaultValues?.coorPhone || '', coorPhone: defaultValues?.coorPhone || '',
visitDate: formatToLocalISO(defaultValues?.visitDate), visitDate: formatToLocalISO(defaultValues?.visitDate),
productiveActivity: defaultValues?.productiveActivity || undefined, productiveActivity: defaultValues?.productiveActivity || undefined,
productiveActivityOther: defaultValues?.productiveActivityOther || undefined,
ecoSector: defaultValues?.ecoSector || undefined, ecoSector: defaultValues?.ecoSector || undefined,
productiveSector: defaultValues?.productiveSector || undefined, productiveSector: defaultValues?.productiveSector || undefined,
centralProductiveActivity: centralProductiveActivity:
@@ -202,6 +203,11 @@ export function CreateTrainingForm({
name: 'mainProductiveActivity', name: 'mainProductiveActivity',
}); });
const productiveActivity = useWatch({
control: form.control,
name: 'productiveActivity',
});
const productiveSectorOptions = ecoSector const productiveSectorOptions = ecoSector
? SECTOR_PRODUCTIVO_MAP[ecoSector] || [] ? SECTOR_PRODUCTIVO_MAP[ecoSector] || []
: []; : [];
@@ -215,6 +221,8 @@ export function CreateTrainingForm({
? ACTIVIDAD_PRODUCTIVA_MAP[mainProductiveActivity] || [] ? ACTIVIDAD_PRODUCTIVA_MAP[mainProductiveActivity] || []
: []; : [];
const other = productiveActivity == 'OTRO' ? true : false;
// Reset dependent fields when parent changes // Reset dependent fields when parent changes
React.useEffect(() => { React.useEffect(() => {
// This effect handles shifts in options, but react-hook-form values persist // This effect handles shifts in options, but react-hook-form values persist
@@ -225,6 +233,7 @@ export function CreateTrainingForm({
productiveSector, productiveSector,
centralProductiveActivity, centralProductiveActivity,
mainProductiveActivity, mainProductiveActivity,
productiveActivity
]); ]);
const stateOptions = dataState?.data || [{ id: 0, name: 'Sin estados' }]; const stateOptions = dataState?.data || [{ id: 0, name: 'Sin estados' }];
@@ -249,15 +258,6 @@ export function CreateTrainingForm({
setMunicipality(Number(defaultValues.municipality)); setMunicipality(Number(defaultValues.municipality));
setDisabledParish(false); setDisabledParish(false);
} }
// if (defaultValues.coorState) {
// setcoorState(Number(defaultValues.coorState));
// setDisabledCoorMunicipality(false);
// }
// if (defaultValues.coorMunicipality) {
// setcoorMunicipality(Number(defaultValues.coorMunicipality));
// setDisabledCoorParish(false);
// }
} }
}, [defaultValues]); }, [defaultValues]);
@@ -292,16 +292,6 @@ export function CreateTrainingForm({
} }
}); });
// 2. Mapeo manual y conversión a numérico
// if (formData.state) {
// data.append('state', Number(formData.state).toString());
// }
// if (formData.municipality) {
// data.append('municipality', Number(formData.municipality).toString());
// }
// if (formData.parish) {
// data.append('parish', Number(formData.parish).toString());
// }
if (defaultValues?.id) { if (defaultValues?.id) {
data.append('id', defaultValues.id.toString()); data.append('id', defaultValues.id.toString());
} }
@@ -693,6 +683,27 @@ export function CreateTrainingForm({
)} )}
/> />
{other && (<FormField
control={form.control}
name="productiveActivityOther"
render={({ field }) => (
<FormItem className="w-full flex flex-col space-y-3">
<FormLabel className="whitespace-normal leading-tight font-semibold">
¿Cuál otra Actividad Productiva?
</FormLabel>
<FormControl>
<Input
{...field}
value={field.value ?? ''}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>)}
<FormField <FormField
control={form.control} control={form.control}
name="ospRif" name="ospRif"

View File

@@ -101,6 +101,9 @@ export function TrainingViewModal({
</Badge> </Badge>
); );
// console.log(data);
return ( return (
<> <>
<Dialog open={isOpen} onOpenChange={onClose}> <Dialog open={isOpen} onOpenChange={onClose}>
@@ -158,12 +161,17 @@ export function TrainingViewModal({
label="Actividad Principal" label="Actividad Principal"
value={data.mainProductiveActivity} value={data.mainProductiveActivity}
/> />
<div className="col-span-full"> {/* <div className="sm-col-span-full"> */}
<DetailItem <DetailItem
label="Actividad Específica" label="Actividad Específica"
value={data.productiveActivity} value={data.productiveActivity}
/> />
</div>
{data.productiveActivity == 'OTRO' && (<DetailItem
label="Otra Actividad Específica"
value={data.productiveActivityOther}
/>)}
{/* </div> */}
</Section> </Section>
{/* 3. Infraestructura y Ubicación */} {/* 3. Infraestructura y Ubicación */}

View File

@@ -107,6 +107,7 @@ export const ACTIVIDAD_PRODUCTIVA_MAP: Record<string, string[]> = {
'SIEMBRA DE ARROZ', 'SIEMBRA DE ARROZ',
'SIEMBRA DE CEREALES (CEBADA, LINAZA, SOYA)', 'SIEMBRA DE CEREALES (CEBADA, LINAZA, SOYA)',
'ELABORACION DE BIO-INSUMO (ABONO ORGANICO)', 'ELABORACION DE BIO-INSUMO (ABONO ORGANICO)',
'OTRO'
], ],
[ACTIVIDAD_PRINCIPAL.CRIA]: [ [ACTIVIDAD_PRINCIPAL.CRIA]: [
'BOVINO', 'BOVINO',
@@ -115,8 +116,9 @@ export const ACTIVIDAD_PRODUCTIVA_MAP: Record<string, string[]> = {
'CUNICULTURA', 'CUNICULTURA',
'AVICOLA', 'AVICOLA',
'PISCICULA', 'PISCICULA',
'OTRO'
], ],
[ACTIVIDAD_PRINCIPAL.PATIOS_PRODUCTIVOS]: ['SIEMBRA Y CRIA'], [ACTIVIDAD_PRINCIPAL.PATIOS_PRODUCTIVOS]: ['SIEMBRA Y CRIA', 'OTRO'],
[ACTIVIDAD_PRINCIPAL.TRANSFORMACION_MATERIA]: [ [ACTIVIDAD_PRINCIPAL.TRANSFORMACION_MATERIA]: [
'ELABORACION DE PRODUCTOS QUIMICOS (LIMPIEZA E HIGIENE PERSONAL)', 'ELABORACION DE PRODUCTOS QUIMICOS (LIMPIEZA E HIGIENE PERSONAL)',
'PANADERIAS', 'PANADERIAS',
@@ -131,6 +133,7 @@ export const ACTIVIDAD_PRODUCTIVA_MAP: Record<string, string[]> = {
'TORREFACTORA DE CÁFE', 'TORREFACTORA DE CÁFE',
'ESPULPADORA DE TOMATES Y FRUTAS', 'ESPULPADORA DE TOMATES Y FRUTAS',
'ARTESANIAS', 'ARTESANIAS',
'OTRO'
], ],
[ACTIVIDAD_PRINCIPAL.TEXTIL]: [ [ACTIVIDAD_PRINCIPAL.TEXTIL]: [
'ELABORACION DE UNIFORME ESCOLARES Y PRENDA DE VESTIR', 'ELABORACION DE UNIFORME ESCOLARES Y PRENDA DE VESTIR',
@@ -138,12 +141,14 @@ export const ACTIVIDAD_PRODUCTIVA_MAP: Record<string, string[]> = {
'ELABORACION DE LENCERIA', 'ELABORACION DE LENCERIA',
'SUBLIMACION DE TEJIDOS', 'SUBLIMACION DE TEJIDOS',
'ELABORACION DE CALZADOS', 'ELABORACION DE CALZADOS',
'OTRO'
], ],
[ACTIVIDAD_PRINCIPAL.CONSTRUCCION]: [ [ACTIVIDAD_PRINCIPAL.CONSTRUCCION]: [
'BLOQUERAS', 'BLOQUERAS',
'PLANTA PREMEZCLADORA DE CEMENTO', 'PLANTA PREMEZCLADORA DE CEMENTO',
'CARPINTERIAS', 'CARPINTERIAS',
'HERRERIAS', 'HERRERIAS',
'OTRO'
], ],
[ACTIVIDAD_PRINCIPAL.BIENES_SERVICIOS]: [ [ACTIVIDAD_PRINCIPAL.BIENES_SERVICIOS]: [
'MERCADOS COMUNALES', 'MERCADOS COMUNALES',
@@ -157,15 +162,17 @@ export const ACTIVIDAD_PRODUCTIVA_MAP: Record<string, string[]> = {
'REPARACION DE CALZADOS', 'REPARACION DE CALZADOS',
'TALLER DE MECANICA', 'TALLER DE MECANICA',
'TRANSPORTES', 'TRANSPORTES',
'OTRO'
], ],
[ACTIVIDAD_PRINCIPAL.VISITAS_GUIADAS]: ['RUTAS TURISTICAS'], [ACTIVIDAD_PRINCIPAL.VISITAS_GUIADAS]: ['RUTAS TURISTICAS', 'OTRO'],
[ACTIVIDAD_PRINCIPAL.ALOJAMIENTO]: ['POSADAS', 'HOTELES'], [ACTIVIDAD_PRINCIPAL.ALOJAMIENTO]: ['POSADAS', 'HOTELES', 'OTRO'],
[ACTIVIDAD_PRINCIPAL.TURISMO]: ['AGENCIAS DE VIAJES'], [ACTIVIDAD_PRINCIPAL.TURISMO]: ['AGENCIAS DE VIAJES', 'OTRO'],
[ACTIVIDAD_PRINCIPAL.COMERCIO]: [ [ACTIVIDAD_PRINCIPAL.COMERCIO]: [
'VENTA DE VIVERES', 'VENTA DE VIVERES',
'VENTAS DE PRENDAS DE VESTIR', 'VENTAS DE PRENDAS DE VESTIR',
'VENTA DE PRODUCTOS QUIMICOS Y DERIVADOS', 'VENTA DE PRODUCTOS QUIMICOS Y DERIVADOS',
'BODEGAS COMUNALES', 'BODEGAS COMUNALES',
'FRIGORIFICOS Y CARNICOS', 'FRIGORIFICOS Y CARNICOS',
'OTRO'
], ],
}; };

View File

@@ -46,6 +46,7 @@ export const trainingSchema = z.object({
productiveActivity: z.string({ productiveActivity: z.string({
message: 'Actividad Productiva es requerida', message: 'Actividad Productiva es requerida',
}), }),
productiveActivityOther: z.string().min(1, { message: 'Este campo es requerido' }).optional(),
ospRif: z.string().optional().or(z.literal('')).nullable(), ospRif: z.string().optional().or(z.literal('')).nullable(),
ospName: z.string().optional().or(z.literal('')).nullable(), ospName: z.string().optional().or(z.literal('')).nullable(),
companyConstitutionYear: z.coerce companyConstitutionYear: z.coerce
@@ -226,6 +227,7 @@ export const getTrainingSchema = z.object({
centralProductiveActivity: z.string(), centralProductiveActivity: z.string(),
mainProductiveActivity: z.string(), mainProductiveActivity: z.string(),
productiveActivity: z.string(), productiveActivity: z.string(),
productiveActivityOther: z.string(),
ospRif: z.string().optional().or(z.literal('')).nullable(), ospRif: z.string().optional().or(z.literal('')).nullable(),
ospName: z.string().optional().or(z.literal('')).nullable(), ospName: z.string().optional().or(z.literal('')).nullable(),
companyConstitutionYear: z.coerce.number(), companyConstitutionYear: z.coerce.number(),