diff --git a/img/cee_dark_logo.png b/img/cee_dark_logo.png new file mode 100644 index 0000000..db4407d Binary files /dev/null and b/img/cee_dark_logo.png differ diff --git a/img/fondo_certificado_manejo_defensivo.png b/img/fondo_certificado_manejo_defensivo.png new file mode 100644 index 0000000..985afab Binary files /dev/null and b/img/fondo_certificado_manejo_defensivo.png differ diff --git a/img/mtc_2_logo.png b/img/mtc_2_logo.png new file mode 100644 index 0000000..63a9be9 Binary files /dev/null and b/img/mtc_2_logo.png differ diff --git a/src/certs/MANEJO_DEFENSIVO.ts b/src/certs/MANEJO_DEFENSIVO.ts new file mode 100644 index 0000000..9b99a31 --- /dev/null +++ b/src/certs/MANEJO_DEFENSIVO.ts @@ -0,0 +1,278 @@ +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_certificado_manejo_defensivo.png", + height: 21.23, + width: 29.8, + horizontalOffset: 0, + verticalOffset: -0.05, + behindDocument: true, +}); + +const imgCIP = getImage({ + name: "colegio_ingenieros_logo.png", + height: 2.15, + width: 2.15, + horizontalOffset: 26.52, + verticalOffset: 15.24, +}); + +const imgMTC = getImage({ + name: "mtc_2_logo.png", + height: 0.94, + width: 5.14, + horizontalOffset: 3.11, + verticalOffset: 19.21, +}); + +const imgCEE = getImage({ + name: "cee_dark_logo.png", + height: 1.6, + width: 2.25, + horizontalOffset: 0.34, + verticalOffset: 17.99, +}); + + +const tCertificate = createSimpleText({ + xPosition: 2.42, + yPosition: 4.2, + width: 11.05, + height: 1.72, + text: "CERTIFICADO", + size: 72, + font: "Times New Roman", + bold: true, +}); + +// Otorgado a +const tExpediteText = createSimpleText({ + xPosition: -1.08, + yPosition: 5.4, + width: 3, + height: 0.7, + text: "Otorgado a:", + size: 22, +}); + +// MANEJO DEFENSIVO +const tCourse = createSimpleText({ + xPosition: -0.44, + yPosition: 8, + width: 20.92, + height: 1.5, + text: "MANEJO DEFENSIVO", + size: 44, + bold: true, +}); + +// En temas de... +const tTopics = createSimpleText({ + xPosition: -0.44, + yPosition: 9.4, + width: 20.92, + height: 1.5, + text: "En temas de: Reacción a Eventos, Técnicas Preventivas, Puntos Ciegos, Primeros Auxilios Básico, Fatiga y Somnolencia, Normas Vigentes, Acción y Reacción Adecuada, Conducción en Condiciones Adversas, equivalente a 12 horas lectivas.", + size: 22, + font: "Times New Roman", + alignment: AlignmentType.CENTER, +}); + +// Se expide certificado... +const tFinishLabel = createSimpleText({ + xPosition: -0.44, + yPosition: 10.5, + width: 20.92, + height: 0.75, + text: "Se expide el presente certificado para los fines que se estime conveniente", + size: 22, + font: "Times New Roman", + alignment: AlignmentType.CENTER, +}); + +// MTC: R.D.N° ... +const tMTCLabel = createSimpleText({ + xPosition: 0.6, + yPosition: 18, + width: 6, + height: 0.75, + text: "R.D.N° 092-2021-MTC/17.03", + size: 24, + font: "Calibri", + alignment: AlignmentType.LEFT, + color: "FFFFFF", + bold: true, +}); + + +// Recuadro de foto +const photoSection = new Paragraph({ + frame: { + position: { + x: cmText(23.35), + y: cmText(8.3), + }, + width: cmText(2.81), + height: cmText(3.57), + 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 manejoDefensivoCert(props: CertData): Promise { + const imgQR = await getQR({ + dni: props.personDni, + height: 2.45, + width: 2.45, + horizontalOffset: 26.4, + verticalOffset: 17.65, + }); + + // FERNANDO ARAOZ + const tName = createSimpleText({ + xPosition: -2.5, + yPosition: 6, + width: 23.13, + height: 1.5, + text: props.personFullName, + size: 52, + bold: true, + underline: {}, + }); + + // Identificado con DNI... + const tContentPart1 = new Paragraph({ + frame: { + position: { + x: cmText(-0.4), + y: cmText(7.3), + }, + width: cmText(20.92), + height: cmText(1), + anchor: { + horizontal: FrameAnchorType.MARGIN, + vertical: FrameAnchorType.MARGIN, + }, + }, + children: [ + new TextRun({ + text: "Identificado con DNI N° ", + font: "Times New Roman", + size: 22, + }), + new TextRun({ + text: props.personDni, + font: "Times New Roman", + size: 24, + bold: true, + }), + new TextRun({ + text: ", al haber aprobado el curso de capacitación sobre:", + font: "Times New Roman", + size: 22, + }), + ], + alignment: AlignmentType.LEFT, + }); + + // Fecha de Emision: ... + const certificateDate = new Paragraph({ + frame: { + position: { + x: cmText(16), + y: cmText(16), + }, + width: cmText(7.5), + height: cmText(0.9), + anchor: { + horizontal: FrameAnchorType.MARGIN, + vertical: FrameAnchorType.MARGIN, + }, + }, + children: [ + new TextRun({ + text: `Fecha de Emisión:\t\t${props.certDay} / ${props.certMonth} / ${props.certYear}`, + font: "Times New Roman", + size: 20, + }), + ], + alignment: AlignmentType.LEFT, + }); + + // N° XXXX-20XX-EEG + const tCertCode = createSimpleText({ + xPosition: 23, + yPosition: 12, + 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: [ + tCertificate, + tExpediteText, + tName, + tContentPart1, + tCourse, + tTopics, + tFinishLabel, + certificateDate, + photoSection, + tCertCode, + tMTCLabel, + new Paragraph({ + children: [ + imgFondoDoc, + imgQR, + imgCIP, + imgCEE, + imgMTC, + ], + }), + ], + }, + ], + }); + + // Return document as a buffer + return await Packer.toBuffer(doc); +} diff --git a/src/certs/MECANICA_BASICA.ts b/src/certs/MECANICA_BASICA.ts index fcc1332..6a55a50 100644 --- a/src/certs/MECANICA_BASICA.ts +++ b/src/certs/MECANICA_BASICA.ts @@ -1,13 +1,11 @@ import { - Document, Packer, Paragraph, PageOrientation, ImageRun, - HorizontalPositionRelativeFrom, VerticalPositionRelativeFrom, + Document, Packer, Paragraph, PageOrientation, FrameAnchorType, TextRun, AlignmentType, BorderStyle, } from "docx"; -import * as QR from "qrcode"; -import { Matpel, cm, cmText, cmToEmu, createSimpleText, getImage, getMatpelHours, getMatpelLabel, getQR } from "./utils"; +import { cmText, createSimpleText, getImage, getQR } from "./utils"; import { CertData } from "./CertData"; const imgFondoDoc = getImage({ @@ -88,6 +86,50 @@ const tDuration = createSimpleText({ alignment: AlignmentType.JUSTIFIED, }); +// Se expide certificado... +const tFinishLabel = createSimpleText({ + xPosition: 1.52, + yPosition: 11.65, + width: 20.1, + height: 0.8, + text: "Se expide el presente certificado para los fines que se estime conveniente", + size: 22, + alignment: AlignmentType.CENTER, + italics: true, +}); + +// Recuadro de foto +const photoSection = new Paragraph({ + frame: { + position: { + x: cmText(-1.5), + y: cmText(-1.9), + }, + width: cmText(2.81), + height: cmText(3.57), + 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 mecanicaBasicaCert(props: CertData): Promise { const imgQR = await getQR({ dni: props.personDni, @@ -120,7 +162,7 @@ export async function mecanicaBasicaCert(props: CertData): Promise underline: {}, }); - // Fecha de Emision: ... + // Identificado con DNI... const tContentPart1 = new Paragraph({ frame: { position: { @@ -155,18 +197,6 @@ export async function mecanicaBasicaCert(props: CertData): Promise alignment: AlignmentType.LEFT, }); - // Se expide certificado... - const tFinishLabel = createSimpleText({ - xPosition: 1.52, - yPosition: 11.65, - width: 20.1, - height: 0.8, - text: "Se expide el presente certificado para los fines que se estime conveniente", - size: 22, - alignment: AlignmentType.CENTER, - italics: true, - }); - // Fecha de Emision: ... const certificateDate = new Paragraph({ frame: { @@ -197,38 +227,6 @@ export async function mecanicaBasicaCert(props: CertData): Promise alignment: AlignmentType.LEFT, }); - // Recuadro de foto - const photoSection = new Paragraph({ - frame: { - position: { - x: cmText(-1.5), - y: cmText(-1.9), - }, - width: cmText(2.81), - height: cmText(3.57), - 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, - }); - const doc = new Document({ sections: [ diff --git a/src/certs/utils.ts b/src/certs/utils.ts index db29c13..225a7b4 100644 --- a/src/certs/utils.ts +++ b/src/certs/utils.ts @@ -95,6 +95,7 @@ export function createSimpleText(data: { underline?: Record, alignment?: AlignmentType, italics?: boolean, + color?: string, }): Paragraph { return new Paragraph({ @@ -118,6 +119,7 @@ export function createSimpleText(data: { size: data.size, underline: data.underline, italics: data.italics, + color: data.color, }), ], alignment: data.alignment ?? AlignmentType.CENTER, diff --git a/src/controller/certificate/certificate.service.ts b/src/controller/certificate/certificate.service.ts index d440e5c..468de5a 100644 --- a/src/controller/certificate/certificate.service.ts +++ b/src/controller/certificate/certificate.service.ts @@ -5,12 +5,10 @@ import { RegisterReturn } from "../../types/RegisterReturn"; import { CertificateDto } from "./certificate.dto"; import { Persona } from "../../model/Persona/persona.entity"; import { CursoGIE } from "../../model/CursoGIE/cursoGIE.entity"; -import { GenerateCertificateDto } from "./dto/GenerateCertificate.dto"; -import { matpelCert } from "src/certs/MATPEL"; -import { Matpel, getMatpelFileName } from "src/certs/utils"; -import { CertData } from "src/certs/CertData"; +import { Matpel } from "src/certs/utils"; import { getMatpel } from "./generator/matpel"; import { getMecanicaBasica } from "./generator/mecanicaBasica"; +import { getManejoDefensivo } from "./generator/manejoDefensivo"; @Injectable() @@ -73,6 +71,16 @@ export class CertificateService { // IDs from db: educa7ls_plataforma > cursosGIE switch (register.curso) { + // MANEJO DEFENSIVO + case 1: { + return await getManejoDefensivo( + person, + register, + certYear, + certMonth, + certDay, + ); + } // MECANICA BASICA case 2: { return await getMecanicaBasica( diff --git a/src/controller/certificate/generator/manejoDefensivo.ts b/src/controller/certificate/generator/manejoDefensivo.ts new file mode 100644 index 0000000..819ffb0 --- /dev/null +++ b/src/controller/certificate/generator/manejoDefensivo.ts @@ -0,0 +1,26 @@ +import { CertData } from "src/certs/CertData"; +import { manejoDefensivoCert } from "src/certs/MANEJO_DEFENSIVO"; +import { Persona } from "src/model/Persona/persona.entity"; +import { RegistroGIE } from "src/model/RegistroGIE/registroGIE.entity"; + +export async function getManejoDefensivo( + person: Persona, + register: RegistroGIE, + certYear: string, + certMonth: string, + certDay: string +): Promise<[Buffer, string]> { + const personFullName = `${person.nombres} ${person.apellidoPaterno} ${person.apellidoMaterno}`; + + const data: CertData = { + matpel: null, + personFullName: personFullName, + personDni: register.dni, + certCode: register.codigo.toString().padStart(4, "0"), + certYear, + certMonth, + certDay, + }; + + return [await manejoDefensivoCert(data), `MANEJO DEFENSIVO - ${personFullName.toUpperCase()}.docx`]; +}