diff --git a/img/fondo_certificado_4x4.png b/img/fondo_certificado_4x4.png new file mode 100644 index 0000000..6c6eba6 Binary files /dev/null and b/img/fondo_certificado_4x4.png differ diff --git a/img/mtc_transparente.png b/img/mtc_transparente.png new file mode 100644 index 0000000..aa25a6c Binary files /dev/null and b/img/mtc_transparente.png differ diff --git a/src/app.module.ts b/src/app.module.ts index 0de352c..18df5d0 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -32,7 +32,7 @@ console.log(dotenv.config()); synchronize: false, }), ], - controllers: [CertificateController, PersonController, SubjectController, MigratorController], + controllers: [CertificateController, PersonController, SubjectController], providers: [CertificateService, PersonService, SubjectService], }) export class AppModule {} diff --git a/src/certs/4X4.ts b/src/certs/4X4.ts new file mode 100644 index 0000000..dfac144 --- /dev/null +++ b/src/certs/4X4.ts @@ -0,0 +1,275 @@ +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_4x4.png", + height: 21.03, + width: 29.69, + horizontalOffset: 0, + verticalOffset: 0.01, + behindDocument: true, +}); + +const imgCIP = getImage({ + name: "colegio_ingenieros_logo.png", + height: 2.15, + width: 2.15, + horizontalOffset: 26.76, + verticalOffset: 12.26, +}); + +const imgCEE = getImage({ + name: "cee_dark_logo.png", + height: 1.5, + width: 2.1, + horizontalOffset: 26.89, + verticalOffset: 17.06, +}); + +const imgMTC = getImage({ + name: "mtc_transparente.png", + height: 1.65, + width: 5.16, + horizontalOffset: 23.92, + verticalOffset: 18.83, +}); + + +const tCertificate = createSimpleText({ + xPosition: 7.7, + yPosition: 3.7, + width: 11.05, + height: 1.72, + text: "CERTIFICADO", + size: 72, + font: "Times New Roman", + bold: true, +}); + +// Otorgado a +const tExpediteText = createSimpleText({ + xPosition: 4.2, + yPosition: 5.5, + width: 3, + height: 0.7, + text: "Otorgado a:", + size: 22, +}); + +// MANEJO EN 4x4 ROAD DANGER +const tCourse = createSimpleText({ + xPosition: 1.8, + yPosition: 8.4, + width: 20.92, + height: 1.5, + text: "MANEJO EN 4x4 ROAD DANGER", + size: 44, + bold: true, +}); + +// (caminos peligrosos) +const tCourseDesc = createSimpleText({ + xPosition: 9.7, + yPosition: 9.6, + width: 5, + height: 0.5, + text: "(CAMINOS PELIGROSOS)", + size: 20, + bold: true, +}); + +// En temas de... +const tTopics = createSimpleText({ + xPosition: 2.3, + yPosition: 10.4, + width: 20.92, + height: 1.5, + text: "En temas de: Terreno Firme y Complicado, Reacciones ante Eventos, Manejo Adecuado de Unidad, Uso Correcto de 4x4, Control Adecuado en Trocha y Pendientes, Uso de Velocidad Adecuada, equivalente a 12 horas lectivas.", + size: 22, + font: "Times New Roman", + alignment: AlignmentType.LEFT, +}); + +// Se expide certificado... +const tFinishLabel = createSimpleText({ + xPosition: 5.95, + yPosition: 11.65, + width: 12.38, + 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, +}); + + +// Recuadro de foto +const photoSection = new Paragraph({ + frame: { + position: { + x: cmText(-1.68), + y: cmText(8.6), + }, + width: cmText(2.7), + 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 _4X4Cert(props: CertData): Promise { + const imgQR = await getQR({ + dni: props.personDni, + height: 2.04, + width: 2.04, + horizontalOffset: 26.85, + verticalOffset: 14.71, + }); + + // FERNANDO ARAOZ + const tName = createSimpleText({ + xPosition: 1, + yPosition: 6.2, + 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(2.5), + y: cmText(7.6), + }, + 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(13), + y: cmText(17.3), + }, + width: cmText(7.5), + height: cmText(0.5), + anchor: { + horizontal: FrameAnchorType.MARGIN, + vertical: FrameAnchorType.MARGIN, + }, + }, + children: [ + new TextRun({ + 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: -2.15, + yPosition: 12.45, + 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, + tCourseDesc, + new Paragraph({ + children: [ + imgFondoDoc, + imgQR, + imgCIP, + imgCEE, + imgMTC, + ], + }), + ], + }, + ], + }); + + // Return document as a buffer + return await Packer.toBuffer(doc); +} diff --git a/src/controller/certificate/certificate.service.ts b/src/controller/certificate/certificate.service.ts index e6f8374..f85721c 100644 --- a/src/controller/certificate/certificate.service.ts +++ b/src/controller/certificate/certificate.service.ts @@ -9,8 +9,9 @@ import { Matpel } from "src/certs/utils"; import { getMatpel } from "./generator/matpel"; import { getMecanicaBasica } from "./generator/mecanicaBasica"; import { getManejoDefensivo } from "./generator/manejoDefensivo"; +import { get4x4 } from "./generator/4x4"; -const generatable = [1, 2, 10, 11, 12]; +const generatable = [1, 2, 3, 10, 11, 12]; @Injectable() export class CertificateService { @@ -92,6 +93,16 @@ export class CertificateService { certDay, ); } + // 4x4 + case 3: { + return await get4x4( + person, + register, + certYear, + certMonth, + certDay, + ); + } // MATPEL 1 case 10: { return await getMatpel( diff --git a/src/controller/certificate/generator/4x4.ts b/src/controller/certificate/generator/4x4.ts new file mode 100644 index 0000000..0b72b8f --- /dev/null +++ b/src/controller/certificate/generator/4x4.ts @@ -0,0 +1,26 @@ +import { _4X4Cert } from "src/certs/4X4"; +import { CertData } from "src/certs/CertData"; +import { Persona } from "src/model/Persona/persona.entity"; +import { RegistroGIE } from "src/model/RegistroGIE/registroGIE.entity"; + +export async function get4x4( + 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 _4X4Cert(data), `4X4 - ${personFullName.toUpperCase()}.docx`]; +}