[docx] Generate SegOpMaqPes certificate
This commit is contained in:
parent
dcc27291c0
commit
ac20c9391f
BIN
img/fondo_seg_op_maq_pes.png
Normal file
BIN
img/fondo_seg_op_maq_pes.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 125 KiB |
BIN
img/logo_hazescorp.png
Normal file
BIN
img/logo_hazescorp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 42 KiB |
BIN
img/mundo_maq.png
Normal file
BIN
img/mundo_maq.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 102 KiB |
@ -10,20 +10,32 @@ import { PersonService } from "./controller/person/person.service";
|
||||
import { SubjectController } from "./controller/subject/subject.controller";
|
||||
import { SubjectService } from "./controller/subject/subject.service";
|
||||
import * as dotenv from "dotenv";
|
||||
import { MigratorController } from "./controller/migrator/migrator.controller";
|
||||
|
||||
// Must be done before initializing DB.
|
||||
console.log(dotenv.config());
|
||||
|
||||
const user = process.env.MY_SQL_USER;
|
||||
const host = process.env.MY_SQL_HOST;
|
||||
const port = parseInt(process.env.MY_SQL_PORT ?? "3306", 10);
|
||||
const password = process.env.MY_SQL_PASSWORD;
|
||||
const db = process.env.MY_SQL_DB;
|
||||
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forRoot({
|
||||
type: "mysql",
|
||||
host: "localhost",
|
||||
// To allow remote connections a manual URI is used, for some
|
||||
url: `mysql://${user}:${password}@${host}:${port}/${db}`,
|
||||
|
||||
// These values are rejected when using a remote connection, for some reason
|
||||
/*
|
||||
host: process.env.MY_SQL_HOST,
|
||||
port: parseInt(process.env.MY_SQL_PORT ?? "3306", 10),
|
||||
username: process.env.MY_SQL_USER,
|
||||
password: process.env.MY_SQL_PASSWORD,
|
||||
database: process.env.MY_SQL_DB,
|
||||
*/
|
||||
entities: [
|
||||
Persona,
|
||||
CursoGIE,
|
||||
|
@ -145,6 +145,7 @@ const photoSection = new Paragraph({
|
||||
|
||||
export async function _4X4Cert(props: CertData<null>): Promise<Buffer> {
|
||||
const imgQR = await getQR({
|
||||
iid: props.certIId,
|
||||
dni: props.personDni,
|
||||
height: 2.04,
|
||||
width: 2.04,
|
||||
|
@ -35,4 +35,8 @@ export type CertData<T> = {
|
||||
* E.g.: "23"
|
||||
*/
|
||||
certDay: string,
|
||||
/**
|
||||
* Id of the certificate
|
||||
*/
|
||||
certIId: number,
|
||||
}
|
||||
|
@ -148,6 +148,7 @@ const photoSection = new Paragraph({
|
||||
|
||||
export async function manejoDefensivoCert(props: CertData<null>): Promise<Buffer> {
|
||||
const imgQR = await getQR({
|
||||
iid: props.certIId,
|
||||
dni: props.personDni,
|
||||
height: 2.45,
|
||||
width: 2.45,
|
||||
|
@ -132,6 +132,7 @@ const photoSection = new Paragraph({
|
||||
|
||||
export async function mecanicaBasicaCert(props: CertData<null>): Promise<Buffer> {
|
||||
const imgQR = await getQR({
|
||||
iid: props.certIId,
|
||||
dni: props.personDni,
|
||||
height: 2.2,
|
||||
width: 2.2,
|
||||
|
253
src/certs/SEG_OP_MAQ_PES.ts
Normal file
253
src/certs/SEG_OP_MAQ_PES.ts
Normal file
@ -0,0 +1,253 @@
|
||||
import {
|
||||
Document, Packer, Paragraph, PageOrientation,
|
||||
FrameAnchorType,
|
||||
TextRun,
|
||||
AlignmentType,
|
||||
BorderStyle,
|
||||
} from "docx";
|
||||
import { cmText, createSimpleText, getImage, getQR } from "./utils";
|
||||
import { CertData } from "./CertData";
|
||||
|
||||
const imgFondoDoc = getImage({
|
||||
name: "fondo_seg_op_maq_pes.png",
|
||||
height: 21.02,
|
||||
width: 29.63,
|
||||
horizontalOffset: 0.03,
|
||||
verticalOffset: 0.04,
|
||||
behindDocument: true,
|
||||
});
|
||||
|
||||
const imgCIP = getImage({
|
||||
name: "colegio_ingenieros_logo.png",
|
||||
height: 2.02,
|
||||
width: 2.02,
|
||||
horizontalOffset: 25.53,
|
||||
verticalOffset: 14.17,
|
||||
});
|
||||
|
||||
const imgMundomaq = getImage({
|
||||
name: "mundo_maq.png",
|
||||
height: 4.82,
|
||||
width: 6.73,
|
||||
horizontalOffset: 20.87,
|
||||
verticalOffset: 0.9,
|
||||
});
|
||||
|
||||
const imgHazescorp = getImage({
|
||||
name: "logo_hazescorp.png",
|
||||
height: 2.95,
|
||||
width: 3.33,
|
||||
horizontalOffset: 0.4,
|
||||
verticalOffset: 17.73,
|
||||
});
|
||||
|
||||
const imgEEG = getImage({
|
||||
name: "eeg_logo.png",
|
||||
height: 2.38,
|
||||
width: 4.94,
|
||||
horizontalOffset: 1.66,
|
||||
verticalOffset: 1.6,
|
||||
});
|
||||
|
||||
|
||||
|
||||
// SEGURIDAD EN LA OPERACIÓN DE MAQUINARIA PESADA
|
||||
const tCourse = createSimpleText({
|
||||
xPosition: 5.5,
|
||||
yPosition: 6.65,
|
||||
width: 12.83,
|
||||
height: 1.5,
|
||||
text: "SEGURIDAD EN LA OPERACIÓN DE MAQUINARIA PESADA",
|
||||
size: 44,
|
||||
bold: true,
|
||||
});
|
||||
|
||||
// En temas de...
|
||||
const tTopics = createSimpleText({
|
||||
xPosition: 1.65,
|
||||
yPosition: 8.9,
|
||||
width: 20.42,
|
||||
height: 1.5,
|
||||
text: "En los temas de: Seguridad en maquinaria pesada, IPERC, Prevención de riesgos con Maquinas, Medidas de prevención con máquinas en movimientos de tierra, Seguridad en la operación, Procedimiento de mantenimiento, Correcto llenado de IPERC, Correcto llenado de Check List, Mantenimiento Preventivo, predictivo, correctivo.",
|
||||
size: 22,
|
||||
font: "Arial",
|
||||
alignment: AlignmentType.JUSTIFIED,
|
||||
});
|
||||
|
||||
// Con una duracion...
|
||||
const tHours = createSimpleText({
|
||||
xPosition: 1.65,
|
||||
yPosition: 10.7,
|
||||
width: 13.15,
|
||||
height: 0.5,
|
||||
text: "Con una duración de 36 horas lectivas",
|
||||
size: 22,
|
||||
font: "Arial",
|
||||
alignment: AlignmentType.LEFT,
|
||||
});
|
||||
|
||||
// Se expide certificado...
|
||||
const tFinishLabel = createSimpleText({
|
||||
xPosition: 5.3,
|
||||
yPosition: 11.5,
|
||||
width: 13.15,
|
||||
height: 0.5,
|
||||
text: "Se expide el presente certificado para los fines que se estime conveniente",
|
||||
size: 22,
|
||||
font: "Arial",
|
||||
italics: true,
|
||||
alignment: AlignmentType.CENTER,
|
||||
});
|
||||
|
||||
|
||||
// Recuadro de foto
|
||||
const photoSection = new Paragraph({
|
||||
frame: {
|
||||
position: {
|
||||
x: cmText(22.62),
|
||||
y: cmText(7),
|
||||
},
|
||||
height: cmText(3.57),
|
||||
width: cmText(2.81),
|
||||
anchor: {
|
||||
horizontal: FrameAnchorType.MARGIN,
|
||||
vertical: FrameAnchorType.MARGIN,
|
||||
},
|
||||
},
|
||||
children: [],
|
||||
border: {
|
||||
top: {
|
||||
style: BorderStyle.DASHED,
|
||||
},
|
||||
bottom: {
|
||||
style: BorderStyle.DASHED,
|
||||
},
|
||||
left: {
|
||||
style: BorderStyle.DASHED,
|
||||
},
|
||||
right: {
|
||||
style: BorderStyle.DASHED,
|
||||
},
|
||||
},
|
||||
alignment: AlignmentType.LEFT,
|
||||
});
|
||||
|
||||
|
||||
export async function segOpMaqPesCert(props: CertData<null>): Promise<Buffer> {
|
||||
const imgQR = await getQR({
|
||||
iid: props.certIId,
|
||||
dni: props.personDni,
|
||||
height: 2.01,
|
||||
width: 2.01,
|
||||
horizontalOffset: 25.53,
|
||||
verticalOffset: 16.43,
|
||||
});
|
||||
|
||||
// FERNANDO ARAOZ
|
||||
const tName = createSimpleText({
|
||||
xPosition: 0,
|
||||
yPosition: 4.15,
|
||||
width: 23.56,
|
||||
height: 1.5,
|
||||
text: props.personFullName,
|
||||
size: 52,
|
||||
bold: true,
|
||||
underline: {},
|
||||
});
|
||||
|
||||
// Identificado con DNI...
|
||||
const tContentPart1 = new Paragraph({
|
||||
frame: {
|
||||
position: {
|
||||
x: cmText(1.4),
|
||||
y: cmText(5.9),
|
||||
},
|
||||
width: cmText(20.92),
|
||||
height: cmText(0.6),
|
||||
anchor: {
|
||||
horizontal: FrameAnchorType.MARGIN,
|
||||
vertical: FrameAnchorType.MARGIN,
|
||||
},
|
||||
},
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "Identificado con DNI N° ",
|
||||
font: "Arial",
|
||||
size: 22,
|
||||
}),
|
||||
new TextRun({
|
||||
text: props.personDni,
|
||||
font: "Arial",
|
||||
size: 24,
|
||||
bold: true,
|
||||
}),
|
||||
new TextRun({
|
||||
text: ", al haber aprobado el curso de capacitación sobre:",
|
||||
font: "Arial",
|
||||
size: 22,
|
||||
}),
|
||||
],
|
||||
alignment: AlignmentType.CENTER,
|
||||
});
|
||||
|
||||
// Fecha de Emision: ...
|
||||
const certificateDate = createSimpleText({
|
||||
xPosition: 19.25,
|
||||
yPosition: 16.2,
|
||||
width: 5.87,
|
||||
height: 0.5,
|
||||
text: `Fecha de Emisión:\t${props.certDay} / ${props.certMonth} / ${props.certYear}`,
|
||||
font: "Times New Roman",
|
||||
size: 20,
|
||||
alignment: AlignmentType.LEFT,
|
||||
});
|
||||
|
||||
// N° XXXX-20XX-EEG
|
||||
const tCertCode = createSimpleText({
|
||||
xPosition: 22.15,
|
||||
yPosition: 10.85,
|
||||
width: 3.67,
|
||||
height: 0.8,
|
||||
text: `N° ${props.certCode}-${props.certYear}-EEG`,
|
||||
size: 20,
|
||||
alignment: AlignmentType.CENTER,
|
||||
});
|
||||
|
||||
const doc = new Document({
|
||||
sections: [
|
||||
{
|
||||
properties: {
|
||||
page: {
|
||||
size: {
|
||||
orientation: PageOrientation.LANDSCAPE,
|
||||
},
|
||||
},
|
||||
},
|
||||
children: [
|
||||
tName,
|
||||
tContentPart1,
|
||||
tCourse,
|
||||
tTopics,
|
||||
tHours,
|
||||
tFinishLabel,
|
||||
certificateDate,
|
||||
photoSection,
|
||||
tCertCode,
|
||||
new Paragraph({
|
||||
children: [
|
||||
imgFondoDoc,
|
||||
imgQR,
|
||||
imgCIP,
|
||||
imgMundomaq,
|
||||
imgHazescorp,
|
||||
imgEEG,
|
||||
],
|
||||
}),
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// Return document as a buffer
|
||||
return await Packer.toBuffer(doc);
|
||||
}
|
@ -52,6 +52,8 @@ export function getImage(data: ImgConfig): ImageRun {
|
||||
}
|
||||
|
||||
export async function getQR(data : {
|
||||
/** ID of the entity in the DB */
|
||||
iid: number,
|
||||
dni: string,
|
||||
height: number,
|
||||
width: number,
|
||||
@ -59,7 +61,7 @@ export async function getQR(data : {
|
||||
verticalOffset: number,
|
||||
behindDocument?: boolean,
|
||||
}): Promise<ImageRun> {
|
||||
const qr = await QR.toDataURL(`https://www.eegsac.com/alumnoscertificados.php?DNI=${data.dni}`, {margin: 1});
|
||||
const qr = await QR.toDataURL(`https://www.eegsac.com/alumnoscertificados.php?DNI=${data.dni}&iid=${data.iid}`, {margin: 1});
|
||||
|
||||
return new ImageRun({
|
||||
data: qr,
|
||||
|
@ -10,8 +10,9 @@ import { getMatpel } from "./generator/matpel";
|
||||
import { getMecanicaBasica } from "./generator/mecanicaBasica";
|
||||
import { getManejoDefensivo } from "./generator/manejoDefensivo";
|
||||
import { get4x4 } from "./generator/4x4";
|
||||
import { getSegOpMaqPesada } from "./generator/segOpMaqPes";
|
||||
|
||||
const generatable = [1, 2, 3, 10, 11, 12];
|
||||
const generatable = [1, 2, 3, 10, 11, 12, 72];
|
||||
|
||||
@Injectable()
|
||||
export class CertificateService {
|
||||
@ -136,6 +137,16 @@ export class CertificateService {
|
||||
certDay,
|
||||
);
|
||||
}
|
||||
// Seguridad en la Operacion de Maquinaria Pesada
|
||||
case 72: {
|
||||
return await getSegOpMaqPesada(
|
||||
person,
|
||||
register,
|
||||
certYear,
|
||||
certMonth,
|
||||
certDay,
|
||||
);
|
||||
}
|
||||
default: {
|
||||
throw new BadRequestException("Curso no soportado");
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ export async function get4x4(
|
||||
certYear,
|
||||
certMonth,
|
||||
certDay,
|
||||
certIId: register.id,
|
||||
};
|
||||
|
||||
return [await _4X4Cert(data), `4X4 - ${personFullName.toUpperCase()}.docx`];
|
||||
|
@ -20,6 +20,7 @@ export async function getManejoDefensivo(
|
||||
certYear,
|
||||
certMonth,
|
||||
certDay,
|
||||
certIId: register.id,
|
||||
};
|
||||
|
||||
return [await manejoDefensivoCert(data), `MANEJO DEFENSIVO - ${personFullName.toUpperCase()}.docx`];
|
||||
|
@ -22,6 +22,7 @@ export async function getMatpel(
|
||||
certYear,
|
||||
certMonth,
|
||||
certDay,
|
||||
certIId: register.id,
|
||||
};
|
||||
|
||||
return [await matpelCert(data), `${getMatpelFileName(matpel)} - ${personFullName.toUpperCase()}.docx`];
|
||||
|
@ -20,6 +20,7 @@ export async function getMecanicaBasica(
|
||||
certYear,
|
||||
certMonth,
|
||||
certDay,
|
||||
certIId: register.id,
|
||||
};
|
||||
|
||||
return [await mecanicaBasicaCert(data), `MECANICA BASICA - ${personFullName.toUpperCase()}.docx`];
|
||||
|
27
src/controller/certificate/generator/segOpMaqPes.ts
Normal file
27
src/controller/certificate/generator/segOpMaqPes.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { CertData } from "src/certs/CertData";
|
||||
import { segOpMaqPesCert } from "src/certs/SEG_OP_MAQ_PES";
|
||||
import { Persona } from "src/model/Persona/persona.entity";
|
||||
import { RegistroGIE } from "src/model/RegistroGIE/registroGIE.entity";
|
||||
|
||||
export async function getSegOpMaqPesada(
|
||||
person: Persona,
|
||||
register: RegistroGIE,
|
||||
certYear: string,
|
||||
certMonth: string,
|
||||
certDay: string
|
||||
): Promise<[Buffer, string]> {
|
||||
const personFullName = `${person.nombres} ${person.apellidoPaterno} ${person.apellidoMaterno}`;
|
||||
|
||||
const data: CertData<null> = {
|
||||
matpel: null,
|
||||
personFullName: personFullName,
|
||||
personDni: register.dni,
|
||||
certCode: register.codigo.toString().padStart(4, "0"),
|
||||
certYear,
|
||||
certMonth,
|
||||
certDay,
|
||||
certIId: register.id,
|
||||
};
|
||||
|
||||
return [await segOpMaqPesCert(data), `SEGURIDAD OPERACION MAQUINARIA PESADA - ${personFullName.toUpperCase()}.docx`];
|
||||
}
|
@ -87,6 +87,7 @@ export function Registers(props: { person: Person | null, lastUpdate: number })
|
||||
function Register(props: { cert: RegisterReturn, onUpdate: () => void }) {
|
||||
const [deleteConfirmation, setDeleteConfirmation] = createSignal(false);
|
||||
const [deleteText, setDeleteText] = createSignal("Eliminar");
|
||||
const [downloading, setDownloading] = createSignal(false);
|
||||
|
||||
const deleteRegister = async() => {
|
||||
if (deleteConfirmation()) {
|
||||
@ -113,6 +114,7 @@ function Register(props: { cert: RegisterReturn, onUpdate: () => void }) {
|
||||
};
|
||||
|
||||
const getCertificate = async() => {
|
||||
setDownloading(true);
|
||||
const response = await fetch(`/certificate/generate/${props.cert.id}`, {
|
||||
method: "POST",
|
||||
});
|
||||
@ -141,13 +143,12 @@ function Register(props: { cert: RegisterReturn, onUpdate: () => void }) {
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
|
||||
return;
|
||||
|
||||
} else {
|
||||
const json = await response.json();
|
||||
alert(json);
|
||||
}
|
||||
|
||||
setDownloading(false);
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -91,8 +91,7 @@ export function RegisterPerson(props: {dni: string, onSuccess: () => void}) {
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div class="grid grid-cols-2 w-1/2">
|
||||
<div>
|
||||
|
||||
<label for="add-person-apellido-paterno">Apellido Paterno</label>
|
||||
<br/>
|
||||
<input
|
||||
@ -108,8 +107,10 @@ export function RegisterPerson(props: {dni: string, onSuccess: () => void}) {
|
||||
onChange={(e) => setApellidoP(e.target.value.toUpperCase())}
|
||||
disabled={loading()}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<label for="add-person-apellido-paterno">Apellido Materno</label>
|
||||
<br/>
|
||||
<input
|
||||
@ -125,8 +126,7 @@ export function RegisterPerson(props: {dni: string, onSuccess: () => void}) {
|
||||
onChange={(e) => setApellidoM(e.target.value.toUpperCase())}
|
||||
disabled={loading()}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
<br />
|
||||
|
||||
<input
|
||||
|
Loading…
Reference in New Issue
Block a user