se agregaron caso-esp, cust-alum, helpers

This commit is contained in:
evenegas
2025-05-26 15:29:47 -06:00
parent b786976565
commit ee1e8d18c5
24 changed files with 1252 additions and 151 deletions
+20
View File
@@ -0,0 +1,20 @@
# Usa una imagen base de Node.js
FROM node:22
# Establece el directorio de trabajo
WORKDIR /app
# Copia los archivos necesarios
COPY package*.json ./
# Instala dependencias
RUN npm install
# Copia el resto del código
COPY . .
# Expone el puerto de la app (ajústalo si usas otro)
EXPOSE 3000
# Comando para correr tu aplicación
CMD ["npm", "run", "start:prod"]
+20 -1
View File
@@ -1,7 +1,9 @@
version: '3.8'
services:
mysql:
image: mariadb:latest
container_name: Iris_back
container_name: Iris_db
restart: always
environment:
MYSQL_ROOT_PASSWORD: root
@@ -12,3 +14,20 @@ services:
- ./mysql:/var/lib/mysql
ports:
- "3307:3306"
nest-app:
build:
context: .
dockerfile: Dockerfile
container_name: Iris_app
restart: always
depends_on:
- mysql
environment:
DATABASE_HOST: mysql
DATABASE_PORT: 3306
DATABASE_USER: user_crud
DATABASE_PASSWORD: root
DATABASE_NAME: Iris
ports:
- "3000:3000"
+94 -8
View File
@@ -9,6 +9,7 @@
"version": "0.0.1",
"license": "UNLICENSED",
"dependencies": {
"@nestjs/axios": "^4.0.0",
"@nestjs/common": "^11.0.1",
"@nestjs/config": "^4.0.2",
"@nestjs/core": "^11.1.1",
@@ -17,6 +18,8 @@
"@nestjs/passport": "^11.0.5",
"@nestjs/platform-express": "^11.0.1",
"@nestjs/typeorm": "^11.0.0",
"bcrypt": "^6.0.0",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.2",
"convert-array-to-csv": "^2.0.0",
"googleapis": "^148.0.0",
@@ -2246,6 +2249,17 @@
"node": ">= 10"
}
},
"node_modules/@nestjs/axios": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@nestjs/axios/-/axios-4.0.0.tgz",
"integrity": "sha512-1cB+Jyltu/uUPNQrpUimRHEQHrnQrpLzVj6dU3dgn6iDDDdahr10TgHFGTmw5VuJ9GzKZsCLDL78VSwJAs/9JQ==",
"license": "MIT",
"peerDependencies": {
"@nestjs/common": "^10.0.0 || ^11.0.0",
"axios": "^1.3.1",
"rxjs": "^7.0.0"
}
},
"node_modules/@nestjs/cli": {
"version": "11.0.7",
"resolved": "https://registry.npmjs.org/@nestjs/cli/-/cli-11.0.7.tgz",
@@ -4911,9 +4925,20 @@
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"dev": true,
"license": "MIT"
},
"node_modules/axios": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz",
"integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==",
"license": "MIT",
"peer": true,
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/b4a": {
"version": "1.6.7",
"resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz",
@@ -5081,6 +5106,20 @@
],
"license": "MIT"
},
"node_modules/bcrypt": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-6.0.0.tgz",
"integrity": "sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"node-addon-api": "^8.3.0",
"node-gyp-build": "^4.8.4"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/bignumber.js": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz",
@@ -5501,6 +5540,12 @@
"dev": true,
"license": "MIT"
},
"node_modules/class-transformer": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz",
"integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==",
"license": "MIT"
},
"node_modules/class-validator": {
"version": "0.14.2",
"resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.2.tgz",
@@ -5666,7 +5711,6 @@
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dev": true,
"license": "MIT",
"dependencies": {
"delayed-stream": "~1.0.0"
@@ -6003,7 +6047,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.4.0"
@@ -6237,7 +6280,6 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
@@ -7016,6 +7058,27 @@
"dev": true,
"license": "ISC"
},
"node_modules/follow-redirects": {
"version": "1.15.9",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"license": "MIT",
"peer": true,
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/foreground-child": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
@@ -7064,7 +7127,6 @@
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
"integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
"dev": true,
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
@@ -7090,7 +7152,6 @@
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.6"
@@ -7100,7 +7161,6 @@
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dev": true,
"license": "MIT",
"dependencies": {
"mime-db": "1.52.0"
@@ -7615,7 +7675,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"dev": true,
"license": "MIT",
"dependencies": {
"has-symbols": "^1.0.3"
@@ -9508,6 +9567,15 @@
"dev": true,
"license": "MIT"
},
"node_modules/node-addon-api": {
"version": "8.3.1",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.3.1.tgz",
"integrity": "sha512-lytcDEdxKjGJPTLEfW4mYMigRezMlyJY8W4wxJK8zE533Jlb8L8dRuObJFWg2P+AuOIxoCgKF+2Oq4d4Zd0OUA==",
"license": "MIT",
"engines": {
"node": "^18 || ^20 || >= 21"
}
},
"node_modules/node-emoji": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz",
@@ -9538,6 +9606,17 @@
}
}
},
"node_modules/node-gyp-build": {
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz",
"integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==",
"license": "MIT",
"bin": {
"node-gyp-build": "bin.js",
"node-gyp-build-optional": "optional.js",
"node-gyp-build-test": "build-test.js"
}
},
"node_modules/node-int64": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
@@ -10192,6 +10271,13 @@
"node": ">= 0.10"
}
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
"license": "MIT",
"peer": true
},
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+3
View File
@@ -20,6 +20,7 @@
"test:e2e": "jest --config ./test/jest-e2e.json"
},
"dependencies": {
"@nestjs/axios": "^4.0.0",
"@nestjs/common": "^11.0.1",
"@nestjs/config": "^4.0.2",
"@nestjs/core": "^11.1.1",
@@ -28,6 +29,8 @@
"@nestjs/passport": "^11.0.5",
"@nestjs/platform-express": "^11.0.1",
"@nestjs/typeorm": "^11.0.0",
"bcrypt": "^6.0.0",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.2",
"convert-array-to-csv": "^2.0.0",
"googleapis": "^148.0.0",
+51 -20
View File
@@ -1,31 +1,62 @@
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { bcrypt } from 'bcrypt';
@Injectable()
export class AuthService {
constructor(private readonly jwtService: JwtService) {}
async jwtVerificar(token:string){
try{
const payload= this.jwtService.verify(token)
return payload;
}catch(err){
if (err.name === 'TokenExpiredError') {
throw new UnauthorizedException('El token ha expirado');
} else if (err.name === 'JsonWebTokenError') {
throw new UnauthorizedException('Token inválido');
} else {
throw new UnauthorizedException('Error al verificar el token');
}
}
async jwtVerificar(token:string){
try{
const payload= this.jwtService.verify(token)
return payload;
}catch(err){
if (err.name === 'TokenExpiredError') {
throw new UnauthorizedException('El token ha expirado');
} else if (err.name === 'JsonWebTokenError') {
throw new UnauthorizedException('Token inválido');
} else {
throw new UnauthorizedException('Error al verificar el token');
}
}
}
async jwtCreate(idUsuario: number, idTipoUsuario:number) {
const payload = { Usuario:idUsuario , tipoUsuario: idTipoUsuario };
return {
access_token: this.jwtService.sign(payload),
};
}
async comparar(password,dbPassword){
if (!bcrypt.compareSync(password, dbPassword)){
return false
}else{
return true;
}
}
async encriptar(password){
bcrypt.hashSync(password, Number(process.env.SALT_ROUNDS))
}
async generarPassword(){
const length = 8;
const charset =
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
let password = '';
for (let i = 0, n = charset.length; i < length; ++i){
password += charset.charAt(Math.floor(Math.random() * n))
}
async jwtCreate(idUsuario: number, idTipoUsuario:number) {
const payload = { Usuario:idUsuario , tipoUsuario: idTipoUsuario };
return {
access_token: this.jwtService.sign(payload),
};
}
return password;
}
}
@@ -9,26 +9,25 @@ export class CasoEspecialController {
@Post()
create(@Body() createCasoEspecialDto: CreateCasoEspecialDto) {
return this.casoEspecialService.create(createCasoEspecialDto);
return this.casoEspecialService.create(createCasoEspecialDto, "example");
}
@Get()
findAll() {
return this.casoEspecialService.findAll();
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.casoEspecialService.findOne(+id);
findOne(@Param('id') id: string) {
}
@Patch(':id')
update(@Param('id') id: string, @Body() updateCasoEspecialDto: UpdateCasoEspecialDto) {
return this.casoEspecialService.update(+id, updateCasoEspecialDto);
}
@Delete(':id')
remove(@Param('id') id: string) {
return this.casoEspecialService.remove(+id);
}
}
@@ -5,5 +5,6 @@ import { CasoEspecialController } from './caso-especial.controller';
@Module({
controllers: [CasoEspecialController],
providers: [CasoEspecialService],
})
export class CasoEspecialModule {}
+241 -13
View File
@@ -1,26 +1,254 @@
import { Injectable } from '@nestjs/common';
import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
import { CreateCasoEspecialDto } from './dto/create-caso-especial.dto';
import { UpdateCasoEspecialDto } from './dto/update-caso-especial.dto';
import { ValidacionService } from 'src/helpers.services/validacion.service';
import { InjectRepository } from '@nestjs/typeorm';
import { CasoEspecial } from './entities/caso-especial.entity';
import { DeepPartial, Repository } from 'typeorm';
import { gmail } from 'src/helpers.services/gmail.service';
import { Usuario } from 'src/usuario/entities/usuario.entity';
import { Carrera } from 'src/carrera/entities/carrera.entity';
import { DriveService } from 'src/drive/drive.service';
import { Status } from 'src/status/entities/status.entity';
import { FilterCasoEspecialDto } from './dto/filter-caso-especial.dto';
@Injectable()
export class CasoEspecialService {
create(createCasoEspecialDto: CreateCasoEspecialDto) {
return 'This action adds a new casoEspecial';
constructor(
@InjectRepository(CasoEspecial)
private casoEspecialRepository: Repository<CasoEspecial>,
@InjectRepository(Usuario)
private usuarioRepository: Repository<Usuario>,
@InjectRepository(Carrera)
private carreraRepository: Repository<Carrera>,
@InjectRepository(Status)
private statusRepository: Repository<Status>,
private validacion: ValidacionService,
private gmail: gmail,
private drive: DriveService,
) { }
async create(body: CreateCasoEspecialDto, file: string) {
const {
idUsuario,
idCarrera,
idStatus,
numeroCuenta,
correo,
creditos,
telefono,
fechaInicio,
fechaFin,
fechaNacimiento,
direccion,
institucion = '',
dependencia = '',
motivo = '',
} = body;
const usuario = await this.usuarioRepository.findOneBy({ idUsuario: idUsuario });
if (!usuario) throw new NotFoundException('Este alumno no existe en la db.');
if (usuario.tipoUsuario.idTipoUsuario !== 3) throw new BadRequestException('Este usuario no es de tipo Alumno.');
const carrera = await this.carreraRepository.findOneBy({ idCarrera: idCarrera });
if (!carrera) throw new NotFoundException('Esta carrera no existe en la db.');
const casoExistente = await this.casoEspecialRepository.findOne({ where: { usuario: usuario } });
if (casoExistente) throw new BadRequestException('Este alumno ya tiene un Caso Especial.');
const path = `./server/uploads/${file}`;
const carpeta = await this.drive.folder(numeroCuenta);
if (!carpeta) {
throw new NotFoundException('Esta carpeta no existe');
}
const archivoZip = await this.drive.uploadFile(path, `archivos.zip`, 'application/zip', carpeta);
const status = await this.statusRepository.findOne({ where: { idStatus: idStatus } })
const nuevoCaso = this.casoEspecialRepository.create(
{correo: correo,
telefono: telefono,
institucion: institucion,
dependencia: dependencia,
motivo: motivo ?? "",
direccion: direccion,
fechaInicio: fechaInicio,
fechaFin: fechaFin,
fechaNacimiento: fechaNacimiento,
carpeta: carpeta,
archivoZip: archivoZip!,
usuario: usuario,
carrera: carrera,
status: status!,
creditos: creditos,
idCasoEspecial: 1}
);
await this.casoEspecialRepository.save(nuevoCaso);
return {
message: 'Se ha registrado el Caso Especial correctamente.',
};
}
findAll() {
return `This action returns all casoEspecial`;
async findAllFiltered(dto: FilterCasoEspecialDto) {
const { pagina = 1, idStatus, nombre = '', numeroCuenta = '' } = dto;
const take = 25;
const skip = (pagina - 1) * take;
const query = this.casoEspecialRepository
.createQueryBuilder('caso')
.leftJoinAndSelect('caso.usuario', 'usuario')
.leftJoinAndSelect('caso.carrera', 'carrera')
.leftJoinAndSelect('caso.status', 'status')
.take(take)
.skip(skip)
.orderBy('caso.updatedAt', 'DESC');
if (idStatus) {
query.andWhere('status.idStatus = :idStatus', { idStatus });
} else {
query.andWhere('status.idStatus > :defaultStatus', { defaultStatus: 10 });
}
if (nombre) {
query.andWhere('usuario.nombre ILIKE :nombre', { nombre: `%${nombre}%` });
}
if (numeroCuenta) {
query.andWhere('usuario.usuario ILIKE :numeroCuenta', { numeroCuenta: `%${numeroCuenta}%` });
}
const [result, total] = await query.getManyAndCount();
return {
count: total,
serviciosEspeciales: result,
};
}
async liberarCasoEspecial(idCEspecial: number): Promise<{ message: string }> {
const idCasoEspecial = this.validacion.validarNumeroEntero(idCEspecial, 'id caso especial');
let update = {};
const caso = await this.casoEspecialRepository.findOne({
where: { idCasoEspecial },
relations: ['usuario'],
});
if (!caso) {
throw new Error('No existe este Caso Especial.');
}
switch (caso.status.idStatus) {
case 11:
case 12:
const correo = terminoValidado(caso.usuario.nombre);
// Actualiza el status según el caso
update = {
idStatus: caso.status.idStatus === 11 ? 13 : 14,
};
let sendMessage = {
to: caso.correo,
subject: correo.subject,
text: correo.msj,
fecha_recibido: new Date(),
html: '',
adjuntos: null
}
if (!process.env.TOKEN_GMAIL) {
throw new Error('No existe el token');
}
// Envía correo
await this.gmail.send(sendMessage, process.env.TOKEN_GMAIL);
break;
case 6:
throw new Error('Este Caso Especial ya se encuentra en Liberación.');
default:
throw new Error('Id status no válido.');
}
// Actualiza en base de datos
await this.casoEspecialRepository.update({ idCasoEspecial }, update);
return {
message: 'Se cambió de estatus correctamente y se envió un correo al alumno informándole de su liberación.',
};
}
findOne(id: number) {
return `This action returns a #${id} casoEspecial`;
findOne(idCasoEspecial: number) {
const id = this.validacion.validarNumeroEntero(
idCasoEspecial,
'id caso especial'
);
const casoEspecial = this.casoEspecialRepository.findOne({ where: { idCasoEspecial }, relations: ['usuario', 'carrera', 'status'] });
if (!casoEspecial) {
throw new Error('No existe este Caso Especial.');
}
}
update(id: number, updateCasoEspecialDto: UpdateCasoEspecialDto) {
return `This action updates a #${id} casoEspecial`;
}
remove(id: number) {
return `This action removes a #${id} casoEspecial`;
async updateCasoEspecial(id: number, dto: UpdateCasoEspecialDto) {
const caso = await this.casoEspecialRepository.findOne({ where: { idCasoEspecial: id } });
if (!caso) {
throw new NotFoundException('Este Caso Especial no existe en la db.');
}
const camposActualizables = [
'correo',
'fechaInicio',
'fechaFin',
'fechaNacimiento',
'direccion',
'telefono',
'institucion',
'dependencia',
'motivo',
];
let huboCambios = false;
for (const campo of camposActualizables) {
if (dto[campo] !== undefined) {
(caso as any)[campo] = dto[campo];
huboCambios = true;
}
}
if (!huboCambios) {
throw new BadRequestException('No se envió ningún campo para actualizar este caso especial.');
}
await this.casoEspecialRepository.save(caso);
return {
message: 'Se guardaron correctamente los cambios de este caso especial.',
};
}
}
@@ -1 +1,66 @@
export class CreateCasoEspecialDto {}
import {
IsEmail,
IsNotEmpty,
IsNumberString,
IsOptional,
IsString,
Length,
IsDateString,
IsNumber,
} from 'class-validator';
export class CreateCasoEspecialDto {
@IsNumber()
@Length(1, 11)
idUsuario: number;
@IsNumber()
@Length(1, 11)
idCarrera: number;
@IsNumber()
@Length(1, 11)
idStatus: number;
@IsString()
@Length(9, 9)
numeroCuenta: string;
@IsEmail()
correo: string;
@IsString()
creditos : string;
@IsString()
@Length(1, 15)
telefono: string;
@IsDateString()
fechaInicio: Date;
@IsDateString()
fechaFin: Date;
@IsDateString()
fechaNacimiento: Date;
@IsString()
@Length(1, 200)
direccion: string;
@IsOptional()
@IsString()
@Length(1, 200)
institucion?: string;
@IsOptional()
@IsString()
@Length(1, 200)
dependencia?: string;
@IsOptional()
@IsNumber()
@Length(1, 1)
motivo?: string;
}
@@ -0,0 +1,23 @@
import { IsOptional, IsString, IsNumber, Min } from 'class-validator';
import { Type } from 'class-transformer';
export class FilterCasoEspecialDto {
@IsOptional()
@Type(() => Number)
@IsNumber()
@Min(1)
pagina?: number = 1;
@IsOptional()
@Type(() => Number)
@IsNumber()
idStatus?: number;
@IsOptional()
@IsString()
nombre?: string;
@IsOptional()
@IsString()
numeroCuenta?: string;
}
@@ -1,4 +1,51 @@
import { PartialType } from '@nestjs/mapped-types';
import { CreateCasoEspecialDto } from './create-caso-especial.dto';
export class UpdateCasoEspecialDto extends PartialType(CreateCasoEspecialDto) {}
import {
IsOptional,
IsString,
IsEmail,
Length,
IsDateString,
IsNumber,
} from 'class-validator';
export class UpdateCasoEspecialDto {
@IsOptional()
@IsEmail()
correo?: string;
@IsOptional()
@IsDateString()
fechaInicio?: Date;
@IsOptional()
@IsDateString()
fechaFin?: Date;
@IsOptional()
@IsDateString()
fechaNacimiento?: Date;
@IsOptional()
@IsString()
@Length(1, 200)
direccion?: string;
@IsOptional()
@IsString()
@Length(1, 15)
telefono?: string;
@IsOptional()
@IsString()
@Length(1, 200)
institucion?: string;
@IsOptional()
@IsString()
@Length(1, 200)
dependencia?: string;
@IsOptional()
@IsNumber()
motivo?: number;
}
@@ -1,7 +1,7 @@
import { Carrera } from "src/carrera/entities/carrera.entity";
import { Status } from "src/status/entities/status.entity";
import { Usuario } from "src/usuario/entities/usuario.entity";
import { Column, Entity, ManyToMany, PrimaryGeneratedColumn } from "typeorm";
import { Column, Entity, ManyToMany, ManyToOne, PrimaryGeneratedColumn } from "typeorm";
@Entity('caso_especial')
export class CasoEspecial {
@@ -44,13 +44,13 @@ export class CasoEspecial {
@Column({ type: 'varchar', length: 60 })
archivoZip: string;
@ManyToMany(()=>Usuario, (usuario)=>usuario.casoEspecial)
@ManyToOne(()=>Usuario, (usuario)=>usuario.casoEspecial)
usuario:Usuario;
@ManyToMany(()=>Carrera, (carrera)=>carrera.casoEspecial)
@ManyToOne(()=>Carrera, (carrera)=>carrera.casoEspecial)
carrera:Carrera;
@ManyToMany(()=>Status, (status)=>status.casoEspecial)
@ManyToOne(()=>Status, (status)=>status.casoEspecial)
status:Status;
@@ -12,23 +12,23 @@ export class CuestionarioAlumnoController {
return this.cuestionarioAlumnoService.create(createCuestionarioAlumnoDto);
}
@Get()
findAll() {
return this.cuestionarioAlumnoService.findAll();
}
// @Get()
// findAll() {
// return this.cuestionarioAlumnoService.findAll();
// }
@Get(':id')
findOne(@Param('id') id: string) {
return this.cuestionarioAlumnoService.findOne(+id);
}
// @Get(':id')
// findOne(@Param('id') id: string) {
// return this.cuestionarioAlumnoService.findOne(+id);
// }
@Patch(':id')
update(@Param('id') id: string, @Body() updateCuestionarioAlumnoDto: UpdateCuestionarioAlumnoDto) {
return this.cuestionarioAlumnoService.update(+id, updateCuestionarioAlumnoDto);
}
// @Patch(':id')
// update(@Param('id') id: string, @Body() updateCuestionarioAlumnoDto: UpdateCuestionarioAlumnoDto) {
// return this.cuestionarioAlumnoService.update(+id, updateCuestionarioAlumnoDto);
// }
@Delete(':id')
remove(@Param('id') id: string) {
return this.cuestionarioAlumnoService.remove(+id);
}
// @Delete(':id')
// remove(@Param('id') id: string) {
// return this.cuestionarioAlumnoService.remove(+id);
// }
}
@@ -7,28 +7,28 @@ import { UpdateCuestionarioAlumno2Dto } from './dto/update-cuestionario-alumno2.
export class CuestionarioAlumno2Controller {
constructor(private readonly cuestionarioAlumno2Service: CuestionarioAlumno2Service) {}
@Post()
create(@Body() createCuestionarioAlumno2Dto: CreateCuestionarioAlumno2Dto) {
return this.cuestionarioAlumno2Service.create(createCuestionarioAlumno2Dto);
}
// @Post()
// create(@Body() createCuestionarioAlumno2Dto: CreateCuestionarioAlumno2Dto) {
// return this.cuestionarioAlumno2Service.create(createCuestionarioAlumno2Dto);
// }
@Get()
findAll() {
return this.cuestionarioAlumno2Service.findAll();
}
// @Get()
// findAll() {
// return this.cuestionarioAlumno2Service.findAll();
// }
@Get(':id')
findOne(@Param('id') id: string) {
return this.cuestionarioAlumno2Service.findOne(+id);
}
// @Get(':id')
// findOne(@Param('id') id: string) {
// return this.cuestionarioAlumno2Service.findOne(+id);
// }
@Patch(':id')
update(@Param('id') id: string, @Body() updateCuestionarioAlumno2Dto: UpdateCuestionarioAlumno2Dto) {
return this.cuestionarioAlumno2Service.update(+id, updateCuestionarioAlumno2Dto);
}
// @Patch(':id')
// update(@Param('id') id: string, @Body() updateCuestionarioAlumno2Dto: UpdateCuestionarioAlumno2Dto) {
// return this.cuestionarioAlumno2Service.update(+id, updateCuestionarioAlumno2Dto);
// }
@Delete(':id')
remove(@Param('id') id: string) {
return this.cuestionarioAlumno2Service.remove(+id);
}
// @Delete(':id')
// remove(@Param('id') id: string) {
// return this.cuestionarioAlumno2Service.remove(+id);
// }
}
@@ -7,8 +7,8 @@ import { IsNull, Not, Repository } from 'typeorm';
import { CuestionarioAlumno } from 'src/cuestionario-alumno/entities/cuestionario-alumno.entity';
import { CuestionarioAlumno2 } from './entities/cuestionario-alumno2.entity';
import { messageByStatus } from 'src/messageByStatus';
import { ArchivoService } from 'src/helpers/archivo.service';
import { ValidacionService } from 'src/validaciones/validacion.service';
import { ArchivoService } from 'src/helpers.services/archivo.service';
import { ValidacionService } from 'src/helpers.services/validacion.service';
const { convertArrayToCSV } = require('convert-array-to-csv');
@@ -71,7 +71,7 @@ export class CuestionarioAlumno2Service {
return resX;
}
async get(version:string, anio:string){
async get(version:string, anio:string){
const year = this.validacionService.validarNumero(anio, 'año', true, 4);
const path = `server/uploads/${year}_cuestionario_alumno.csv`;
@@ -108,11 +108,6 @@ export class CuestionarioAlumno2Service {
return this.archivoService.crearArchivo(path, convertArrayToCSV(data));
}
@@ -7,28 +7,28 @@ import { UpdateCuestionarioPrograma2Dto } from './dto/update-cuestionario-progra
export class CuestionarioPrograma2Controller {
constructor(private readonly cuestionarioPrograma2Service: CuestionarioPrograma2Service) {}
@Post()
create(@Body() createCuestionarioPrograma2Dto: CreateCuestionarioPrograma2Dto) {
return this.cuestionarioPrograma2Service.create(createCuestionarioPrograma2Dto);
}
// @Post()
// create(@Body() createCuestionarioPrograma2Dto: CreateCuestionarioPrograma2Dto) {
// return this.cuestionarioPrograma2Service.create(createCuestionarioPrograma2Dto);
// }
@Get()
findAll() {
return this.cuestionarioPrograma2Service.findAll();
}
// @Get()
// findAll() {
// return this.cuestionarioPrograma2Service.findAll();
// }
@Get(':id')
findOne(@Param('id') id: string) {
return this.cuestionarioPrograma2Service.findOne(+id);
}
// @Get(':id')
// findOne(@Param('id') id: string) {
// return this.cuestionarioPrograma2Service.findOne(+id);
// }
@Patch(':id')
update(@Param('id') id: string, @Body() updateCuestionarioPrograma2Dto: UpdateCuestionarioPrograma2Dto) {
return this.cuestionarioPrograma2Service.update(+id, updateCuestionarioPrograma2Dto);
}
// @Patch(':id')
// update(@Param('id') id: string, @Body() updateCuestionarioPrograma2Dto: UpdateCuestionarioPrograma2Dto) {
// return this.cuestionarioPrograma2Service.update(+id, updateCuestionarioPrograma2Dto);
// }
@Delete(':id')
remove(@Param('id') id: string) {
return this.cuestionarioPrograma2Service.remove(+id);
}
// @Delete(':id')
// remove(@Param('id') id: string) {
// return this.cuestionarioPrograma2Service.remove(+id);
// }
}
@@ -1,15 +1,101 @@
import { Injectable } from '@nestjs/common';
import { BadRequestException, Injectable } from '@nestjs/common';
import { CreateCuestionarioPrograma2Dto } from './dto/create-cuestionario-programa2.dto';
import { UpdateCuestionarioPrograma2Dto } from './dto/update-cuestionario-programa2.dto';
import { InjectRepository } from '@nestjs/typeorm';
import { CuestionarioPrograma } from 'src/cuestionario-programa/entities/cuestionario-programa.entity';
import { Not, Repository } from 'typeorm';
import { CuestionarioPrograma2 } from './entities/cuestionario-programa2.entity';
import { ArchivoService } from 'src/helpers.services/archivo.service';
import { ValidacionService } from 'src/helpers.services/validacion.service';
import { Servicio } from 'src/servicio/entities/servicio.entity';
import { messageByStatus } from 'src/messageByStatus';
const { convertArrayToCSV } = require('convert-array-to-csv');
@Injectable()
export class CuestionarioPrograma2Service {
create(createCuestionarioPrograma2Dto: CreateCuestionarioPrograma2Dto) {
return 'This action adds a new cuestionarioPrograma2';
constructor(
@InjectRepository(CuestionarioPrograma)
private cuestionarioRepo: Repository<CuestionarioPrograma>,
@InjectRepository(CuestionarioPrograma2)
private cuestionario2Repo: Repository<CuestionarioPrograma2>,
@InjectRepository(Servicio)
private servicioRepository:Repository<Servicio>,
private archivoService:ArchivoService,
private validacionService:ValidacionService,
) {}
async create(cuestionarioPrograma2: CreateCuestionarioPrograma2Dto) {
let idServicio = cuestionarioPrograma2.idServicio;
let cuestionario = this.validacionService.validarCuestionarioPrograma2(cuestionarioPrograma2);
let servicio = await this.servicioRepository.findOne({where:{idServicio}});
if(!servicio){
throw new Error('No existe este Servicio Social.');
}
if(servicio.cuestionarioPrograma2.idCuestionarioPrograma2){
throw new Error('Este Servicio Social ya cuenta con cuestionario de alumno');
}
console.log('el servicio social si existe', servicio);
console.log('antes de create ques2');
if (messageByStatus.hasOwnProperty(servicio.status.idStatus))
throw new Error(messageByStatus[servicio.status.idStatus]);
console.log('despues de registrar cuestionario', cuestionario);
let respuestasRegistradas = await this.cuestionario2Repo.save(cuestionario);
// si el cuestionario ya existe solo hay que actualizar el id de cuestionarioprograma o alumno
console.log("registrar id en servicio en cuestionario 2");
let x = await this.servicioRepository.update(
{ idServicio },
{ cuestionarioPrograma2: respuestasRegistradas }
)
console.log(x);
return respuestasRegistradas;
}
findAll() {
return `This action returns all cuestionarioPrograma2`;
async getCuestionario(dto: {version:string, year:string}) {
const { version, year } = dto;
const filePath = `server/uploads/${year}_cuestionario_programa.csv`;
let registros: any[];
if (version === 'v1') {
registros = await this.cuestionarioRepo.find();
} else if (version === 'v2') {
registros = await this.cuestionario2Repo.find();
} else {
throw new BadRequestException('Versión inválida');
}
const data = registros.map((item) => ({ ...item }));
await this.archivoService.eliminarArchivo(filePath).catch((err) => {
console.log(err);
});
return this.archivoService.crearArchivo(filePath, convertArrayToCSV(data));
}
findOne(id: number) {
@@ -1 +1,142 @@
export class CreateCuestionarioPrograma2Dto {}
import {
IsNotEmpty,
IsNumber,
IsOptional,
IsString,
Length,
} from 'class-validator';
export class CreateCuestionarioPrograma2Dto {
@IsNumber()
@IsNotEmpty()
idServicio:number
// p1, p2, p4, p5, p6
@IsString()
@IsNotEmpty()
@Length(1, 100)
p1: string;
@IsString()
@IsNotEmpty()
@Length(1, 50)
p2: string;
@IsString()
@IsNotEmpty()
@Length(1, 100)
p4: string;
@IsString()
@IsNotEmpty()
@Length(1, 5)
p5: string;
@IsOptional()
@IsString()
@Length(1, 100)
p6?: string;
// Sección p3_A
@IsString()
@IsNotEmpty()
@Length(1, 50)
p3_A_1: string;
@IsString()
@IsNotEmpty()
@Length(1, 50)
p3_A_2: string;
@IsString()
@IsNotEmpty()
@Length(1, 50)
p3_A_3: string;
@IsString()
@IsNotEmpty()
@Length(1, 50)
p3_A_4: string;
// Sección p3_B
@IsString()
@IsNotEmpty()
@Length(1, 50)
p3_B_1: string;
@IsString()
@IsNotEmpty()
@Length(1, 50)
p3_B_2: string;
@IsString()
@IsNotEmpty()
@Length(1, 50)
p3_B_3: string;
@IsString()
@IsNotEmpty()
@Length(1, 50)
p3_B_4: string;
// Sección p3_C
@IsString()
@IsNotEmpty()
@Length(1, 50)
p3_C_1: string;
@IsString()
@IsNotEmpty()
@Length(1, 50)
p3_C_2: string;
@IsString()
@IsNotEmpty()
@Length(1, 50)
p3_C_3: string;
@IsString()
@IsNotEmpty()
@Length(1, 50)
p3_C_4: string;
@IsString()
@IsNotEmpty()
@Length(1, 50)
p3_C_5: string;
// Sección p3_D
@IsString()
@IsNotEmpty()
@Length(1, 50)
p3_D_1: string;
@IsString()
@IsNotEmpty()
@Length(1, 50)
p3_D_2: string;
@IsString()
@IsNotEmpty()
@Length(1, 50)
p3_D_3: string;
@IsString()
@IsNotEmpty()
@Length(1, 50)
p3_D_4: string;
@IsString()
@IsNotEmpty()
@Length(1, 50)
p3_D_5: string;
// Sección p3_E
@IsString()
@IsNotEmpty()
@Length(1, 50)
p3_E_1: string;
}
@@ -7,82 +7,82 @@ export class CuestionarioPrograma2 {
idCuestionarioPrograma2: number;
// Sección p3_A_*
@Column({ type: 'varchar', length: 50, nullable: true })
@Column({ type: 'varchar', length: 50, nullable: false })
p3_A_1: string;
@Column({ type: 'varchar', length: 50, nullable: true })
@Column({ type: 'varchar', length: 50, nullable: false })
p3_A_2: string;
@Column({ type: 'varchar', length: 50, nullable: true })
@Column({ type: 'varchar', length: 50, nullable: false })
p3_A_3: string;
@Column({ type: 'varchar', length: 50, nullable: true })
@Column({ type: 'varchar', length: 50, nullable: false })
p3_A_4: string;
// Sección p3_B_*
@Column({ type: 'varchar', length: 50, nullable: true })
@Column({ type: 'varchar', length: 50, nullable: false })
p3_B_1: string;
@Column({ type: 'varchar', length: 50, nullable: true })
@Column({ type: 'varchar', length: 50, nullable: false })
p3_B_2: string;
@Column({ type: 'varchar', length: 50, nullable: true })
@Column({ type: 'varchar', length: 50, nullable: false })
p3_B_3: string;
@Column({ type: 'varchar', length: 50, nullable: true })
@Column({ type: 'varchar', length: 50, nullable: false })
p3_B_4: string;
// Sección p3_C_*
@Column({ type: 'varchar', length: 50, nullable: true })
@Column({ type: 'varchar', length: 50, nullable: false })
p3_C_1: string;
@Column({ type: 'varchar', length: 50, nullable: true })
@Column({ type: 'varchar', length: 50, nullable: false })
p3_C_2: string;
@Column({ type: 'varchar', length: 50, nullable: true })
@Column({ type: 'varchar', length: 50, nullable: false })
p3_C_3: string;
@Column({ type: 'varchar', length: 50, nullable: true })
@Column({ type: 'varchar', length: 50, nullable: false })
p3_C_4: string;
@Column({ type: 'varchar', length: 50, nullable: true })
@Column({ type: 'varchar', length: 50, nullable: false })
p3_C_5: string;
// Sección p3_D_*
@Column({ type: 'varchar', length: 50, nullable: true })
@Column({ type: 'varchar', length: 50, nullable: false })
p3_D_1: string;
@Column({ type: 'varchar', length: 50, nullable: true })
@Column({ type: 'varchar', length: 50, nullable: false })
p3_D_2: string;
@Column({ type: 'varchar', length: 50, nullable: true })
@Column({ type: 'varchar', length: 50, nullable: false })
p3_D_3: string;
@Column({ type: 'varchar', length: 50, nullable: true })
@Column({ type: 'varchar', length: 50, nullable: false })
p3_D_4: string;
@Column({ type: 'varchar', length: 50, nullable: true })
@Column({ type: 'varchar', length: 50, nullable: false })
p3_D_5: string;
// Sección p3_E_*
@Column({ type: 'varchar', length: 50, nullable: true })
@Column({ type: 'varchar', length: 50, nullable: false })
p3_E_1: string;
// p1, p2, p4, p5, p6
@Column({ type: 'varchar', length: 100, nullable: true })
@Column({ type: 'varchar', length: 100, nullable: false })
p1: string;
@Column({ type: 'varchar', length: 50, nullable: true })
@Column({ type: 'varchar', length: 50, nullable: false })
p2: string;
@Column({ type: 'varchar', length: 100, nullable: true })
@Column({ type: 'varchar', length: 100, nullable: false })
p4: string;
@Column({ type: 'varchar', length: 5, nullable: true })
@Column({ type: 'varchar', length: 5, nullable: false })
p5: string;
@Column({ type: 'varchar', length: 100, nullable: true })
p6: string;
p6?: string;
@OneToMany(()=>Servicio,(servicio)=>servicio.cuestionarioAlumno2)
servicio:Servicio[];
@@ -0,0 +1,29 @@
import { IsString, IsEmail, IsDate, IsOptional } from 'class-validator';
import { Type } from 'class-transformer';
export class SendCorreoDto {
@IsEmail()
to: string;
@IsString()
@IsOptional()
subject: string;
@IsString()
@IsOptional()
text: string;
@IsDate()
@Type(() => Date)
fecha_recibido: Date;
@IsString()
@IsOptional()
html: string;
@IsOptional()
adjuntos: any;
}
+39
View File
@@ -0,0 +1,39 @@
import { Injectable, InternalServerErrorException } from "@nestjs/common";
import { HttpService } from '@nestjs/axios';
import { SendCorreoDto } from "./dto/send-email.dto";
import { catchError, firstValueFrom, map, retry } from 'rxjs';
@Injectable()
export class gmail{
constructor(
private httpService:HttpService
){}
async send(sendCorreo:SendCorreoDto,token:string){
const url = 'https://api.otro-back.com/login';
const headers = {
'token': token,
};
const response = await firstValueFrom(
this.httpService.post(url, sendCorreo,{headers} ).pipe(
retry(2),
map(response => response.data),
catchError(error => {
throw new InternalServerErrorException('Falló la petición POST');
})
)
)
}
}
+289
View File
@@ -0,0 +1,289 @@
const dudasAlumno = `Cualquier duda puedes acudir a las ventanillas de servicio social de la Secretaría de Asuntos Académicos Estudiantiles, en la planta baja del Edificio A-8 de lunes a viernes de 09:00 a 15:00 hrs. y de 17:00 a 19:00 hrs. o bien, comunicarte al 5623 1686 o al correo tramites.ss@acatlan.unam.mx`;
const dudasResponsable = `Cualquier duda puede comunicarse al 5623 1686 o al correo tramites.ss@acatlan.unam.mx`;
const atentamente = `
Atentamente
Departamento de Servicio Social, Desarrollo Profesional e Inserción Laboral
FES Acatlán
`;
const preRegistro = (password, nombre) => {
return {
subject: 'Notificación de Pre-Registro.',
msj: `Estimado(a) ${nombre}:
Te informamos que la dependencia en donde decidiste realizar tu servicio social ya te registró en nuestro sistema de servicio social, por lo que para completar el proceso debes ingresar en un periodo máximo de 10 días hábiles a partir de la recepción de este mensaje, a la página https://iris.acatlan.unam.mx/ con tu número de cuenta y contraseña: ${password}, para llenar un formulario con tus datos.
En caso de no realizar dicho registro, tu trámite queda inconcluso y no nos hacemos responsables por las horas de servicio social prestadas en cualquier dependencia.
En el sistema que se te indicó podrás dar seguimiento al resto de tu trámite de servicio social.
Instrucciones al término de tu servicio social:
Al día siguiente de tu fecha de término programada, quedará habilitado en el sistema la opción para subir los documentos correspondientes, por lo que la institución deberá subir escaneada tu carta de término y llenar un cuestionario sobre tu desempeño, mientras que tú debes encargarte de subir tu informe global de actividades en el formato disponible en https://bit.ly/informe-serviciosocialFESA, así como llenar un cuestionario sobre el programa en el que participaste.
Si se suben correctamente los documentos y cuestionarios mencionados, el Departamento de Servicio Social validará tu trámite de término en el sistema y en un periodo aproximado de 15 días hábiles te hará llegar por correo electrónico tu carta de liberación del servicio social.
Finalmente, te recomendamos destacar en tu bandeja de correos este mensaje para tener siempre a la mano las instrucciones recibidas, o bien, copiar en otro archivo el texto para que lo puedas ubicar fácilmente.
${dudasAlumno}
${atentamente}
`,
};
};
const preRegistroRechazadoAlumno = (motivo, nombre) => {
return {
subject: `Notificación de rechazo de pre-registro.`,
msj: `Estimado(a) ${nombre}:
Te informamos que hay un error con tu pre-registro de servicio social por los siguientes motivos:
${motivo}
${dudasAlumno}
${atentamente}
`,
};
};
const preRegistroRechazadoResponsable = (motivo, nombre) => {
return {
subject: `Notificación de rechazo de pre-registro.`,
msj: `Estimado responsable de programa:
Te informamos que hubo un error con el pre-registro de servicio social del alumno ${nombre} por los siguientes motivos:
${motivo}
${dudasResponsable}
${atentamente}
`,
};
};
const registroValidadoAlumno = (nombre) => {
return {
subject: 'Validación de registro.',
msj: `Estimado(a) ${nombre}:
Te informamos que el Área de Registro y Control de Servicio Social ha validado tu solicitud de registro de servicio social, por lo que el siguiente trámite lo realizarás hasta que concluyas 480 horas en un período de mínimo 6 meses y obtengas tu carta de término por parte de la institución, quien se encargará de subir dicho archivo a la página en donde te registraste, además de responder un cuestionario sobre tu desempeño.
A su vez, deberás responder un cuestionario de evaluación del programa de servicio social en donde participaste y enviar el informe global de actividades elaborado por ti, con firma y sello de visto bueno de tu jefe inmediato.
Cabe mencionar que se ha enviado copia de este mensaje al responsable de programa de servicio social de tu dependencia para que esté enterado de la validación de tu registro.
${dudasAlumno}
${atentamente}
`,
};
};
const registroValidadoResponsable = (nombre) => {
return {
subject: 'Validación de registro.',
msj: `Estimado responsable de programa:
Te informamos que el Área de Registro y Control de Servicio Social ha validado la solicitud de registro del alumno ${nombre}.
${dudasResponsable}
${atentamente}
`,
};
};
const terminoValidado = (nombre) => {
return {
subject: 'Validación de término.',
msj: `Estimado(a) ${nombre}:
Te confirmamos que has concluido con los trámites necesarios para la liberación de tu servicio social por lo que ahora solo queda esperar máximo 15 días hábiles para que se te envíe a tu correo, la copia de tu carta de liberación.
${dudasAlumno}
${atentamente}
`,
};
};
const terminoRechazadoAlumno = (motivo, nombre) => {
return {
subject: 'Correo de rechazo de término',
msj: `Estimado(a) ${nombre}:
Te informamos que no fue validado tu trámite de término por el Departamento de Servicio Social y Bolsa de Trabajo por los siguientes motivos:
${motivo}
${dudasAlumno}
${atentamente}
`,
};
};
const terminoRechazadoResponsable = (motivo, nombre) => {
return {
subject: 'Correo de rechazo de término',
msj: `Estimado responsable de programa:
Te informamos que no fue validado el trámite de término del alumno ${nombre} por el Departamento de Servicio Social y Bolsa de Trabajo por los siguientes motivos:
${motivo}
${dudasResponsable}
${atentamente}
`,
};
};
const canceladoAlumno = (motivo, nombre) => {
return {
subject: 'Correo de cancelación de servicio social',
msj: `Estimado(a) ${nombre}:
Te informamos que fue cancelado tu trámite de servicio social, por el Departamento de Servicio Social y Bolsa de Trabajo por los siguientes motivos:
${motivo}
${dudasAlumno}
${atentamente}
`,
};
};
const canceladoResponsable = (motivo, nombre) => {
return {
subject: 'Correo de cancelación de servicio social',
msj: `Estimado responsable de programa:
Te informamos que fue cancelado el trámite de servicio social del alumno ${nombre}, por el Departamento de Servicio Social y Bolsa de Trabajo por los siguientes motivos:
${motivo}
${dudasResponsable}
${atentamente}
`,
};
};
const enviarSec = (secreto, usuariomail, nombre) => {
return {
subject: `Estimado responsable de programa de servicio social: ${nombre}`,
msj: `Le informamos que desde marzo de 2020 se implementó un nuevo sistema interno de servicio social en el cual estará el expediente electrónico del alumno y su seguimiento con respecto a estos trámites. La dirección electrónica de dicho sistema es https://iris.acatlan.unam.mx y su usuario y contraseña son:
Nombre de usuario para ingresar: ${usuariomail}
Contraseña: ${secreto}
Le pedimos sea cuidadoso de sus claves de acceso ya que con ellos tiene la facultad para registrar el trámite de inicio y término de servicio social de nuestros alumnos, lo que genera un riesgo para malas prácticas si comparte sus datos con otras personas.
Para el uso de dicho sistema el proceso es el siguiente:
1. Al ingresar sólo debe seguir las sencillas instrucciones para pre-registrar a sus prestadores de servicio social, lo cual es un proceso fácil debido a que con sólo capturar el número de cuenta del alumno, aparecerá de manera automática su nombre y carrera, quedando pendiente sólo los campos de correo electrónico del alumno y los datos de su proyecto de servicio social. Adicionalmente deberá cargar el archivo con la carta aceptación escaneada en formato pdf.
2. Con dicho pre-registro el Departamento de servicio social revisará que la carta de aceptación esté correcta y dará su aprobación en el sistema para que le llegue un correo electrónico al alumno notificándole sus claves de acceso para completar el registro.
3. El alumno ingresará al sistema para llenar algunos datos pendientes y una vez hecho esto, el Departamento de servicio social validará el registro del alumno y el sistema enviará un correo de notificación tanto al alumno como a usted para que tengan conocimiento que el proceso de registro se completó de manera satisfactoria.
4. Para notificar el término del alumno deberá ingresar nuevamente al sistema y cargar el archivo de la carta de término escaneada en formato pdf, así como llenar un cuestionario de desempeño del alumno.
5. Por su parte el alumno ingresará al sistema para subir escaneado su informe de actividades con firma y sello de su jefe inmediato y llenará un cuestionario de evaluación del programa de servicio social en el que participó.
6. Si todo está correcto el Departamento de servicio social validará el trámite de término del alumno y le notificará el tiempo aproximado en que se le enviará por correo su carta de liberación.
Otras consideraciones:
- Le pedimos su apoyo cargando las cartas de los alumnos en un periodo de 10 días hábiles posteriores a la fecha de inicio y término, ya que a su vez los alumnos tendrán otros 10 días hábiles para completar lo que les corresponde en cada etapa.
- Para obtener los datos que el sistema le pide del alumno puede preguntárselos directamente, ya que las cartas de presentación sólo se emiten para instituciones externas.
- Los profesores de carrera con proyectos de servicio social registrados no tendrán claves de acceso a este sistema, por lo que sus áreas de adscripción deberán encargarse de hacer los trámites de servicio social de sus alumnos.
- De cualquier forma para atender dudas o comentarios al respecto, podrá comunicarse con el equipo del Departamento de Servicio Social:
Lic. Lourdes Ibarra Celorio
56231686
tramites.ss@acatlan.unam.mx
Lic. Marcela Martínez Rangel
56231600
sesocial@acatlan.unam.mx.
Lic. Ivette Selene Hernández Rios
56231600
sesoprof@acatlan.unam.mx
Atentamente
Lic. Ivette Selene Hernández Rios
Jefa del Departamento de Servicio Social, Desarrollo Profesional e Inserción Laboral
`,
};
};
const avisoTerminoAlumno = (nombre) => {
return {
subject: `Aviso de Termino de Servicio Social`,
msj: `Estimado(a) ${nombre}:
Te recordamos que está próxima la fecha programada para el término de tu servicio social, por lo que un día después de ésta se habilitará en el sistema iris.acatlan.unam.mx la opción para que realices tu trámite de conclusión.
En cuanto cumplas con las 480 horas reglamentarias, tienes 15 días hábiles para ingresar con tu usuario y contraseña recibidos anteriormente y subir escaneado tu informe de servicio social en el formato descargable que aparece en la siguiente página: https://www.acatlan.unam.mx/index.php?id=160. Adicionalmente deberás responder en el sistema el Cuestionario de evaluación del programa de servicio social en el que participaste.
Por su parte el responsable del programa de servicio social deberá ingresar al mismo sistema para subir escaneada tu carta de término y debe responder el Cuestionario de desempeño del alumno. Para lo anterior, también la institución tiene 15 días hábiles a partir de que concluiste las 480 horas de servicio.
En cuanto el responsable de programa de servicio social y tú suban al sistema lo que les corresponde, el Departamento de Servicio Social revisará tus documentos y en caso de estar correctos validará tu trámite para realizar la liberación de este requisito. Recibirás una notificación por correo con el periodo de tiempo aproximado que debes esperar para recibir por correo electrónico tu carta de liberación o bien, las indicaciones de los documentos que debes corregir para poder aceptar tu trámite de término.
Por reglamento de la Universidad, si en máximo dos años a partir de la fecha de inicio de servicio social no se realiza el trámite de término mencionado anteriormente, debes tomar en cuenta que tu registro queda cancelado y deberás tramitarlo nuevamente en otro programa.
${dudasAlumno}
${atentamente}
`,
};
};
const avisoTerminoResponsable = (nombre) => {
return {
subject: `Aviso de Termino de Servicio Social`,
msj: `Estimado responsable de programa de servicio social:
Te informamos que la fecha de término programada para el alumno ${nombre} está próxima a cumplirse por lo que te notificamos que un día después de que se cumpla quedará habilitada en el sistema iris.acatlan.unam.mx la opción para realizar el trámite de conclusión.
Se ha enviado un correo al alumno para notificarle que una vez que cumpla 480 horas, tiene 15 días hábiles para ingresar con su usuario y contraseña recibidos anteriormente y subir escaneado su informe de servicio social y deberá responder en el sistema el Cuestionario de evaluación del programa en el que participó.
Por su parte usted deberá ingresar al mismo sistema para subir escaneada su carta de término y responder el Cuestionario de desempeño del alumno. Para lo anterior, también tiene 15 días hábiles a partir de que el prestador cumplió las 480 horas de servicio.
En cuanto usted y el alumno suban al sistema lo que les corresponde, el Departamento de Servicio Social revisará los documentos y en caso de estar correctos validará el trámite para realizar la liberación de este requisito. El alumno recibirá una notificación por correo con el periodo de tiempo aproximado que debe esperar para acudir a recoger la copia de su carta de liberación o bien, recibirán las indicaciones de los documentos que se deben corregir para poder aceptar el trámite de término.
También se le ha informado al alumno que por reglamento de la Universidad, si en máximo dos años a partir de la fecha de inicio de servicio social no se realiza el trámite de término mencionado anteriormente, debe tomar en cuenta que su registro queda cancelado y deberá tramitarlo nuevamente en otro programa.
${dudasResponsable}
${atentamente}
`,
};
};
module.exports = {
preRegistro,
preRegistroRechazadoAlumno,
preRegistroRechazadoResponsable,
registroValidadoAlumno,
registroValidadoResponsable,
terminoValidado,
terminoRechazadoAlumno,
terminoRechazadoResponsable,
enviarSec,
canceladoAlumno,
canceladoResponsable,
avisoTerminoAlumno,
avisoTerminoResponsable,
};