@muni-sanfer/types-gestor-documental 0.0.1-beta.41 → 0.0.1-beta.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -450,6 +450,7 @@ export interface DocumentTypeEntity {
450
450
  annulledNumbers?: DocumentAnnulledNumberEntity[];
451
451
  flowSteps?: DocumentTypeFlowStepEntity[];
452
452
  signatureBatches?: SignatureBatchEntity[];
453
+ template?: DocumentTemplateEntity | null;
453
454
  deleted: boolean;
454
455
  createdAt: string;
455
456
  updatedAt: string;
@@ -927,6 +928,8 @@ export interface DocumentTemplateEntity {
927
928
  name: string;
928
929
  description?: string | null;
929
930
  documentTypeIds: string[];
931
+ documentType?: DocumentTypeEntity | null;
932
+ documentTypeId?: string | null;
930
933
  content: JsonValue;
931
934
  version: number;
932
935
  enabled: boolean;
@@ -1441,6 +1444,18 @@ export interface DocumentInternalNoteEntity {
1441
1444
  text: string;
1442
1445
  createdAt: string;
1443
1446
  }
1447
+ export interface RichImageEntity {
1448
+ id: string;
1449
+ fileId: string;
1450
+ name: string;
1451
+ mimeType: string;
1452
+ width: number;
1453
+ height: number;
1454
+ sha256: string;
1455
+ sizeBytes: number;
1456
+ employeeId: string;
1457
+ createdAt: string;
1458
+ }
1444
1459
  type JsonValue = string | number | boolean | {
1445
1460
  [key in string]?: JsonValue;
1446
1461
  } | Array<JsonValue> | null;
@@ -1,5 +1,5 @@
1
1
  import { type DocumentCategory, type DocumentParticipantRole, type DocumentTypeEntity } from '../base/entities';
2
- import { type DocumentTypeCreateResponseEntity, type DocumentTypeGetAllResponseEntity, type DocumentTypeGetByIdResponseEntity, type DocumentTypeUpdateResponseEntity } from '../entities';
2
+ import { type DocumentTemplateContent, type DocumentTypeCreateResponseEntity, type DocumentTypeGetAllResponseEntity, type DocumentTypeGetByIdResponseEntity, type DocumentTypeUpdateResponseEntity } from '../entities';
3
3
  import { type RpcPage } from './contract';
4
4
  /** Patrones NATS de `documentType`: `<servicio>.<recurso>.<acción>`. */
5
5
  export declare const DocumentTypePatterns: {
@@ -46,6 +46,7 @@ export interface DocumentTypeWritePayload {
46
46
  sharesNumberingWithId?: string | null;
47
47
  enabled?: boolean;
48
48
  flowSteps?: DocumentFlowStepInput[];
49
+ template?: DocumentTemplateContent | null;
49
50
  }
50
51
  /**
51
52
  * Qué se envía y qué se responde en cada patrón. Generado desde los handlers y los DTO del microservicio.
@@ -25,6 +25,7 @@ import { type SignatureBatchContract } from './signatureBatch.contract';
25
25
  import { type WorkFolderContract } from './workFolder.contract';
26
26
  import { type DraftingRequestContract } from './draftingRequest.contract';
27
27
  import { type InternalReviewContract } from './internalReview.contract';
28
+ import { type RichImageContract } from './richImage.contract';
28
29
  export * from './contract';
29
30
  export * from './document.contract';
30
31
  export * from './documentType.contract';
@@ -53,6 +54,7 @@ export * from './mailIntake.contract';
53
54
  export * from './push.contract';
54
55
  export * from './draftingRequest.contract';
55
56
  export * from './internalReview.contract';
57
+ export * from './richImage.contract';
56
58
  /** Patrones NATS de gestor-documental-ms, por recurso: `gestorDocumental.<recurso>.<acción>`. */
57
59
  export declare const GestorDocumentalPatterns: {
58
60
  readonly documentType: {
@@ -317,6 +319,10 @@ export declare const GestorDocumentalPatterns: {
317
319
  readonly getNotes: "gestorDocumental.internalReview.getNotes";
318
320
  readonly addNote: "gestorDocumental.internalReview.addNote";
319
321
  };
322
+ readonly richImage: {
323
+ readonly register: "gestorDocumental.richImage.register";
324
+ readonly getFile: "gestorDocumental.richImage.getFile";
325
+ };
320
326
  };
321
327
  /** Contrato completo de gestor-documental-ms: la unión de los contratos de sus recursos. */
322
- export type GestorDocumentalContract = DocumentTypeContract & DocumentContract & ProcedureContract & IssuingEntityContract & CaseFileContract & PartsOfficeContract & RegisterBookContract & SignatureBatchContract & WorkFolderContract & ScanContract & ArchivalSeriesContract & TextSnippetContract & DocumentTemplateContract & HolidayContract & IndicatorsContract & AuditContract & SignatureCheckContract & RepositoryExportContract & RetentionContract & AccessRequestContract & TransparencyContract & DataProtectionContract & DeskContract & MailIntakeContract & PushContract & DraftingRequestContract & InternalReviewContract;
328
+ export type GestorDocumentalContract = DocumentTypeContract & DocumentContract & ProcedureContract & IssuingEntityContract & CaseFileContract & PartsOfficeContract & RegisterBookContract & SignatureBatchContract & WorkFolderContract & ScanContract & ArchivalSeriesContract & TextSnippetContract & DocumentTemplateContract & HolidayContract & IndicatorsContract & AuditContract & SignatureCheckContract & RepositoryExportContract & RetentionContract & AccessRequestContract & TransparencyContract & DataProtectionContract & DeskContract & MailIntakeContract & PushContract & DraftingRequestContract & InternalReviewContract & RichImageContract;
@@ -42,6 +42,7 @@ const signatureBatch_contract_1 = require("./signatureBatch.contract");
42
42
  const workFolder_contract_1 = require("./workFolder.contract");
43
43
  const draftingRequest_contract_1 = require("./draftingRequest.contract");
44
44
  const internalReview_contract_1 = require("./internalReview.contract");
45
+ const richImage_contract_1 = require("./richImage.contract");
45
46
  __exportStar(require("./contract"), exports);
46
47
  __exportStar(require("./document.contract"), exports);
47
48
  __exportStar(require("./documentType.contract"), exports);
@@ -70,6 +71,7 @@ __exportStar(require("./mailIntake.contract"), exports);
70
71
  __exportStar(require("./push.contract"), exports);
71
72
  __exportStar(require("./draftingRequest.contract"), exports);
72
73
  __exportStar(require("./internalReview.contract"), exports);
74
+ __exportStar(require("./richImage.contract"), exports);
73
75
  /** Patrones NATS de gestor-documental-ms, por recurso: `gestorDocumental.<recurso>.<acción>`. */
74
76
  exports.GestorDocumentalPatterns = {
75
77
  documentType: documentType_contract_1.DocumentTypePatterns,
@@ -99,4 +101,5 @@ exports.GestorDocumentalPatterns = {
99
101
  push: push_contract_1.PushPatterns,
100
102
  draftingRequest: draftingRequest_contract_1.DraftingRequestPatterns,
101
103
  internalReview: internalReview_contract_1.InternalReviewPatterns,
104
+ richImage: richImage_contract_1.RichImagePatterns,
102
105
  };
@@ -0,0 +1,33 @@
1
+ import { type RichImageResponseEntity } from '../entities';
2
+ /** Patrones NATS de `richImage`: imágenes del editor (logos de membrete e imágenes del texto). */
3
+ export declare const RichImagePatterns: {
4
+ readonly register: "gestorDocumental.richImage.register";
5
+ readonly getFile: "gestorDocumental.richImage.getFile";
6
+ };
7
+ export interface RichImageContract {
8
+ /**
9
+ * Registra una imagen ya subida a Drive por el gateway (en la carpeta de los documentos). El ms descarga el archivo, comprueba que sea PNG o JPEG y de
10
+ * tamaño aceptable, y guarda sus medidas y su huella.
11
+ */
12
+ [RichImagePatterns.register]: {
13
+ payload: {
14
+ fileId: string;
15
+ name: string;
16
+ actor: {
17
+ employeeId: string;
18
+ };
19
+ };
20
+ response: RichImageResponseEntity;
21
+ };
22
+ /** El archivo de una imagen registrada, para mostrarla en el editor. */
23
+ [RichImagePatterns.getFile]: {
24
+ payload: {
25
+ id: string;
26
+ };
27
+ response: {
28
+ fileId: string;
29
+ fileName: string;
30
+ mimeType: string;
31
+ };
32
+ };
33
+ }
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RichImagePatterns = void 0;
4
+ /** Patrones NATS de `richImage`: imágenes del editor (logos de membrete e imágenes del texto). */
5
+ exports.RichImagePatterns = {
6
+ register: 'gestorDocumental.richImage.register',
7
+ getFile: 'gestorDocumental.richImage.getFile',
8
+ };
@@ -1,4 +1,5 @@
1
1
  import { type CommunicationMeans, DocumentAnnulledNumberEntity, DocumentAttachmentEntity, DocumentDeliveryEntity, DocumentEntity, DocumentParticipantEntity, DocumentRecipientEntity, type DocumentStatus, DocumentTrackingEntity, DocumentTypeEntity } from '../../base/entities';
2
+ import { type RichLetterhead, type RichPage, type RichSpacing, type RichTextStyle } from './richStyle';
2
3
  import { type DocumentDraftingRequestEntity } from '../draftingRequest/draftingRequest.entity';
3
4
  /** Tipo documental de un documento, con lo necesario para citarlo. */
4
5
  export interface DocumentTypeSummaryEntity {
@@ -407,8 +408,8 @@ export interface DocumentTrailExportEntity {
407
408
  }
408
409
  /** Plantilla oficial con que se redacta un documento en el sistema. */
409
410
  export type DocumentTemplateKind = 'Decree' | 'Office' | 'Memorandum' | 'General';
410
- /** Formato de un trozo de texto en el editor del gestor. */
411
- export type RichMark = 'bold' | 'italic' | 'underline';
411
+ /** Formato de un trozo de texto en el editor del gestor. Superíndice y subíndice no van juntos. */
412
+ export type RichMark = 'bold' | 'italic' | 'underline' | 'strike' | 'superscript' | 'subscript';
412
413
  /**
413
414
  * Texto con su formato, o un campo de la plantilla (`field`: su clave), que se reemplaza por su valor al armar el PDF.
414
415
  * Un salto de línea dentro del texto (`\n`) es un salto de línea del párrafo.
@@ -416,8 +417,11 @@ export type RichMark = 'bold' | 'italic' | 'underline';
416
417
  export type RichInline = {
417
418
  text: string;
418
419
  marks?: RichMark[];
420
+ style?: RichTextStyle;
419
421
  } | {
420
422
  field: string;
423
+ marks?: RichMark[];
424
+ style?: RichTextStyle;
421
425
  };
422
426
  export type RichAlign = 'left' | 'center' | 'right' | 'justify';
423
427
  /** Numeración de una lista: viñetas, «1.» o la de los decretos, «1.-». */
@@ -435,6 +439,7 @@ export type RichBlock = {
435
439
  id: string;
436
440
  type: 'paragraph';
437
441
  align?: RichAlign;
442
+ spacing?: RichSpacing;
438
443
  locked?: boolean;
439
444
  content: RichInline[];
440
445
  } | {
@@ -442,6 +447,7 @@ export type RichBlock = {
442
447
  type: 'heading';
443
448
  level: 1 | 2;
444
449
  align?: RichAlign;
450
+ spacing?: RichSpacing;
445
451
  locked?: boolean;
446
452
  content: RichInline[];
447
453
  } | {
@@ -449,9 +455,20 @@ export type RichBlock = {
449
455
  type: 'listItem';
450
456
  list: RichListStyle;
451
457
  level: number;
458
+ spacing?: RichSpacing;
452
459
  locked?: boolean;
453
460
  content: RichInline[];
454
461
  }
462
+ /** Imagen registrada en el gestor (`imageId`), con su ancho en puntos (sin pasar el del texto) y alineación. */
463
+ | {
464
+ id: string;
465
+ type: 'image';
466
+ imageId: string;
467
+ width: number;
468
+ align?: 'left' | 'center' | 'right';
469
+ caption?: string;
470
+ locked?: boolean;
471
+ }
455
472
  /** `rows[fila][columna]`: el contenido de cada celda. */
456
473
  | {
457
474
  id: string;
@@ -526,6 +543,9 @@ export type DocumentComposition = {
526
543
  blocks: RichBlock[];
527
544
  fields: RichField[];
528
545
  distribution: string[];
546
+ /** Página y membrete. En una plantilla propia los pone su versión: lo que mande el navegador no cuenta. */
547
+ page?: RichPage;
548
+ letterhead?: RichLetterhead;
529
549
  };
530
550
  /** PDF armado con una plantilla: para la vista previa (`contentBase64`) o ya subido (`fileId`). */
531
551
  export interface DocumentComposeResponseEntity {
@@ -1 +1,2 @@
1
1
  export * from './document.entity';
2
+ export * from './richStyle';
@@ -15,3 +15,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./document.entity"), exports);
18
+ __exportStar(require("./richStyle"), exports);
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Formato del editor del gestor que comparten el navegador y el microservicio: tipografías, colores, tamaños de hoja y
3
+ * márgenes. Todo lo que el PDF muestra sale de aquí, así que el editor y el documento oficial se ven igual.
4
+ */
5
+ /**
6
+ * Tipografías incrustadas en el PDF (PDF/A exige fuentes incrustadas). Liberation Sans, Liberation Serif y Carlito
7
+ * miden igual que Arial, Times New Roman y Calibri: lo que se pegó desde Word ocupa lo mismo.
8
+ */
9
+ export declare const RICH_FONTS: {
10
+ readonly Roboto: "Roboto";
11
+ readonly LiberationSans: "Liberation Sans (Arial)";
12
+ readonly LiberationSerif: "Liberation Serif (Times New Roman)";
13
+ readonly Carlito: "Carlito (Calibri)";
14
+ };
15
+ export type RichFont = keyof typeof RICH_FONTS;
16
+ /** Tamaños de letra que se ofrecen, en puntos. */
17
+ export declare const RICH_FONT_SIZES: readonly [8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 24];
18
+ /** Colores de letra: una paleta acotada, sobria, para documentos oficiales. */
19
+ export declare const RICH_COLORS: {
20
+ readonly black: {
21
+ readonly label: "Negro";
22
+ readonly hex: "#111827";
23
+ };
24
+ readonly gray: {
25
+ readonly label: "Gris";
26
+ readonly hex: "#4B5563";
27
+ };
28
+ readonly blue: {
29
+ readonly label: "Azul";
30
+ readonly hex: "#1E40AF";
31
+ };
32
+ readonly red: {
33
+ readonly label: "Rojo";
34
+ readonly hex: "#B91C1C";
35
+ };
36
+ readonly green: {
37
+ readonly label: "Verde";
38
+ readonly hex: "#166534";
39
+ };
40
+ readonly brown: {
41
+ readonly label: "Café";
42
+ readonly hex: "#78350F";
43
+ };
44
+ };
45
+ export type RichColor = keyof typeof RICH_COLORS;
46
+ /** Resaltado del texto. */
47
+ export declare const RICH_HIGHLIGHTS: {
48
+ readonly yellow: {
49
+ readonly label: "Amarillo";
50
+ readonly hex: "#FEF08A";
51
+ };
52
+ readonly green: {
53
+ readonly label: "Verde";
54
+ readonly hex: "#BBF7D0";
55
+ };
56
+ readonly blue: {
57
+ readonly label: "Celeste";
58
+ readonly hex: "#BFDBFE";
59
+ };
60
+ readonly pink: {
61
+ readonly label: "Rosado";
62
+ readonly hex: "#FBCFE8";
63
+ };
64
+ readonly gray: {
65
+ readonly label: "Gris";
66
+ readonly hex: "#E5E7EB";
67
+ };
68
+ };
69
+ export type RichHighlight = keyof typeof RICH_HIGHLIGHTS;
70
+ /** Formato propio de un trozo de texto, además de sus marcas. Sin valor, el de la página. */
71
+ export interface RichTextStyle {
72
+ font?: RichFont;
73
+ size?: number;
74
+ color?: RichColor;
75
+ highlight?: RichHighlight;
76
+ }
77
+ /** Espaciado y sangría de un párrafo, título o punto de lista, en puntos (el interlineado, en veces la letra). */
78
+ export interface RichSpacing {
79
+ before?: number;
80
+ after?: number;
81
+ lineHeight?: number;
82
+ /** Sangría de la primera línea. */
83
+ firstLine?: number;
84
+ /** Sangría de todo el párrafo, desde el margen izquierdo. */
85
+ left?: number;
86
+ }
87
+ /** Límites del espaciado, en puntos. */
88
+ export declare const RICH_SPACING_LIMITS: {
89
+ readonly maxSpace: 72;
90
+ readonly maxIndent: 216;
91
+ readonly minLineHeight: 0.8;
92
+ readonly maxLineHeight: 3;
93
+ };
94
+ /** Tamaños de hoja, en puntos. Oficio es el chileno: 216 x 330 mm. */
95
+ export declare const RICH_PAGE_SIZES: {
96
+ readonly letter: {
97
+ readonly label: "Carta (216 x 279 mm)";
98
+ readonly width: 612;
99
+ readonly height: 792;
100
+ };
101
+ readonly oficio: {
102
+ readonly label: "Oficio (216 x 330 mm)";
103
+ readonly width: 612;
104
+ readonly height: 936;
105
+ };
106
+ };
107
+ export type RichPageSize = keyof typeof RICH_PAGE_SIZES;
108
+ export interface RichMargins {
109
+ top: number;
110
+ right: number;
111
+ bottom: number;
112
+ left: number;
113
+ }
114
+ /**
115
+ * Márgenes mínimos, en puntos: arriba van el membrete y el número con la fecha que estampa el sistema; abajo, la
116
+ * franja del QR en cada página; a los costados, los sellos. Con menos, lo estampado taparía el texto.
117
+ */
118
+ export declare const RICH_MIN_MARGINS: RichMargins;
119
+ /** Márgenes máximos, en puntos (unos 5 cm). */
120
+ export declare const RICH_MAX_MARGIN = 144;
121
+ /** Página de un documento: tamaño, márgenes y letra base. La define la plantilla; quien redacta no la cambia. */
122
+ export interface RichPage {
123
+ size: RichPageSize;
124
+ margins: RichMargins;
125
+ font: RichFont;
126
+ fontSize: number;
127
+ lineHeight: number;
128
+ }
129
+ /** Página de siempre: Carta, con el espacio del membrete y los sellos, en Roboto 11. */
130
+ export declare const RICH_DEFAULT_PAGE: RichPage;
131
+ /**
132
+ * Membrete de la plantilla, en el margen superior de cada página: un logo o escudo (opcional) y el nombre de la
133
+ * municipalidad y de la unidad que emite. Va a la izquierda: a la derecha el sistema estampa el número y la fecha.
134
+ */
135
+ export interface RichLetterhead {
136
+ /** Imagen registrada en el gestor (`RichImage`), no un archivo de Drive. */
137
+ imageId?: string | null;
138
+ /** Alto del logo, en puntos. */
139
+ imageHeight?: number;
140
+ showOrganName: boolean;
141
+ showUnitName: boolean;
142
+ /** Líneas propias bajo el nombre, como la dirección o el teléfono. */
143
+ lines?: string[];
144
+ }
145
+ export declare const RICH_DEFAULT_LETTERHEAD: RichLetterhead;
146
+ /** Límites de una imagen: formatos, peso y tamaño en el texto. */
147
+ export declare const RICH_IMAGE_LIMITS: {
148
+ readonly types: readonly ["image/png", "image/jpeg"];
149
+ readonly maxBytes: 2000000;
150
+ readonly minWidth: 24;
151
+ readonly maxLetterheadHeight: 56;
152
+ };
153
+ /** Imagen subida al gestor para el editor: se usa por su id; el archivo está en Drive. */
154
+ export interface RichImageResponseEntity {
155
+ id: string;
156
+ name: string;
157
+ mimeType: string;
158
+ width: number;
159
+ height: number;
160
+ }
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ /**
3
+ * Formato del editor del gestor que comparten el navegador y el microservicio: tipografías, colores, tamaños de hoja y
4
+ * márgenes. Todo lo que el PDF muestra sale de aquí, así que el editor y el documento oficial se ven igual.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.RICH_IMAGE_LIMITS = exports.RICH_DEFAULT_LETTERHEAD = exports.RICH_DEFAULT_PAGE = exports.RICH_MAX_MARGIN = exports.RICH_MIN_MARGINS = exports.RICH_PAGE_SIZES = exports.RICH_SPACING_LIMITS = exports.RICH_HIGHLIGHTS = exports.RICH_COLORS = exports.RICH_FONT_SIZES = exports.RICH_FONTS = void 0;
8
+ /**
9
+ * Tipografías incrustadas en el PDF (PDF/A exige fuentes incrustadas). Liberation Sans, Liberation Serif y Carlito
10
+ * miden igual que Arial, Times New Roman y Calibri: lo que se pegó desde Word ocupa lo mismo.
11
+ */
12
+ exports.RICH_FONTS = {
13
+ Roboto: 'Roboto',
14
+ LiberationSans: 'Liberation Sans (Arial)',
15
+ LiberationSerif: 'Liberation Serif (Times New Roman)',
16
+ Carlito: 'Carlito (Calibri)',
17
+ };
18
+ /** Tamaños de letra que se ofrecen, en puntos. */
19
+ exports.RICH_FONT_SIZES = [8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 24];
20
+ /** Colores de letra: una paleta acotada, sobria, para documentos oficiales. */
21
+ exports.RICH_COLORS = {
22
+ black: { label: 'Negro', hex: '#111827' },
23
+ gray: { label: 'Gris', hex: '#4B5563' },
24
+ blue: { label: 'Azul', hex: '#1E40AF' },
25
+ red: { label: 'Rojo', hex: '#B91C1C' },
26
+ green: { label: 'Verde', hex: '#166534' },
27
+ brown: { label: 'Café', hex: '#78350F' },
28
+ };
29
+ /** Resaltado del texto. */
30
+ exports.RICH_HIGHLIGHTS = {
31
+ yellow: { label: 'Amarillo', hex: '#FEF08A' },
32
+ green: { label: 'Verde', hex: '#BBF7D0' },
33
+ blue: { label: 'Celeste', hex: '#BFDBFE' },
34
+ pink: { label: 'Rosado', hex: '#FBCFE8' },
35
+ gray: { label: 'Gris', hex: '#E5E7EB' },
36
+ };
37
+ /** Límites del espaciado, en puntos. */
38
+ exports.RICH_SPACING_LIMITS = { maxSpace: 72, maxIndent: 216, minLineHeight: 0.8, maxLineHeight: 3 };
39
+ /** Tamaños de hoja, en puntos. Oficio es el chileno: 216 x 330 mm. */
40
+ exports.RICH_PAGE_SIZES = {
41
+ letter: { label: 'Carta (216 x 279 mm)', width: 612, height: 792 },
42
+ oficio: { label: 'Oficio (216 x 330 mm)', width: 612, height: 936 },
43
+ };
44
+ /**
45
+ * Márgenes mínimos, en puntos: arriba van el membrete y el número con la fecha que estampa el sistema; abajo, la
46
+ * franja del QR en cada página; a los costados, los sellos. Con menos, lo estampado taparía el texto.
47
+ */
48
+ exports.RICH_MIN_MARGINS = { top: 64, right: 42, bottom: 64, left: 42 };
49
+ /** Márgenes máximos, en puntos (unos 5 cm). */
50
+ exports.RICH_MAX_MARGIN = 144;
51
+ /** Página de siempre: Carta, con el espacio del membrete y los sellos, en Roboto 11. */
52
+ exports.RICH_DEFAULT_PAGE = {
53
+ size: 'letter',
54
+ margins: { top: 104, right: 64, bottom: 76, left: 72 },
55
+ font: 'Roboto',
56
+ fontSize: 11,
57
+ lineHeight: 1.2,
58
+ };
59
+ exports.RICH_DEFAULT_LETTERHEAD = { imageId: null, showOrganName: true, showUnitName: true };
60
+ /** Límites de una imagen: formatos, peso y tamaño en el texto. */
61
+ exports.RICH_IMAGE_LIMITS = {
62
+ types: ['image/png', 'image/jpeg'],
63
+ maxBytes: 2000000,
64
+ minWidth: 24,
65
+ maxLetterheadHeight: 56,
66
+ };
@@ -1,5 +1,6 @@
1
1
  import { type DocumentTemplateEntity } from '../../base/entities';
2
2
  import { type RichBlock, type RichField } from '../document/document.entity';
3
+ import { type RichLetterhead, type RichPage } from '../document/richStyle';
3
4
  /**
4
5
  * Contenido de una plantilla propia: los bloques del editor (con sus partes fijas) y los campos que completa quien
5
6
  * redacta (en la plantilla, sin valor).
@@ -7,6 +8,10 @@ import { type RichBlock, type RichField } from '../document/document.entity';
7
8
  export interface DocumentTemplateContent {
8
9
  blocks: RichBlock[];
9
10
  fields: RichField[];
11
+ /** Tamaño de hoja, márgenes y letra base. Sin valor, la página de siempre (`RICH_DEFAULT_PAGE`). */
12
+ page?: RichPage;
13
+ /** Membrete con logo. Sin valor, el nombre de la municipalidad y de la unidad. */
14
+ letterhead?: RichLetterhead;
10
15
  }
11
16
  /** Plantilla propia en el listado de quien las administra. */
12
17
  export interface DocumentTemplateGetAllResponseEntity {
@@ -38,6 +43,8 @@ export interface DocumentTemplateAvailableResponseEntity {
38
43
  description: string | null;
39
44
  version: DocumentTemplateEntity['version'];
40
45
  content: DocumentTemplateContent;
46
+ /** Es la plantilla del tipo documental pedido: se aplica sola al redactar. */
47
+ ownedByType: boolean;
41
48
  }
42
49
  export interface DocumentTemplateCreateResponseEntity {
43
50
  id: DocumentTemplateEntity['id'];
@@ -1,4 +1,5 @@
1
1
  import { DocumentTypeEntity, DocumentTypeFlowStepEntity } from '../../base/entities';
2
+ import { type DocumentTemplateContent } from '../documentTemplate/documentTemplate.entity';
2
3
  /** Paso del flujo sugerido de un tipo documental: quién visa o firma, en su orden. */
3
4
  export interface DocumentTypeFlowStepResponseEntity {
4
5
  id: DocumentTypeFlowStepEntity['id'];
@@ -50,10 +51,18 @@ export interface DocumentTypeGetAllResponseEntity {
50
51
  visa: number;
51
52
  signature: number;
52
53
  };
54
+ hasTemplate: boolean;
55
+ }
56
+ /** Plantilla propia de un tipo documental: la versión vigente de su contenido. */
57
+ export interface DocumentTypeTemplateResponseEntity {
58
+ id: string;
59
+ version: number;
60
+ content: DocumentTemplateContent;
53
61
  }
54
62
  export interface DocumentTypeGetByIdResponseEntity extends DocumentTypeGetAllResponseEntity {
55
63
  lastCorrelative: number | null;
56
64
  flowSteps: DocumentTypeFlowStepResponseEntity[];
65
+ template: DocumentTypeTemplateResponseEntity | null;
57
66
  }
58
67
  export interface DocumentTypeCreateResponseEntity {
59
68
  id: DocumentTypeEntity['id'];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@muni-sanfer/types-gestor-documental",
3
- "version": "0.0.1-beta.41",
3
+ "version": "0.0.1-beta.43",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "scripts": {
@@ -654,6 +654,7 @@ export interface DocumentTypeEntity {
654
654
  annulledNumbers?: DocumentAnnulledNumberEntity[];
655
655
  flowSteps?: DocumentTypeFlowStepEntity[];
656
656
  signatureBatches?: SignatureBatchEntity[];
657
+ template?: DocumentTemplateEntity | null;
657
658
  deleted: boolean;
658
659
  createdAt: string;
659
660
  updatedAt: string;
@@ -1158,6 +1159,8 @@ export interface DocumentTemplateEntity {
1158
1159
  name: string;
1159
1160
  description?: string | null;
1160
1161
  documentTypeIds: string[];
1162
+ documentType?: DocumentTypeEntity | null;
1163
+ documentTypeId?: string | null;
1161
1164
  content: JsonValue;
1162
1165
  version: number;
1163
1166
  enabled: boolean;
@@ -1706,4 +1709,17 @@ export interface DocumentInternalNoteEntity {
1706
1709
  createdAt: string;
1707
1710
  }
1708
1711
 
1712
+ export interface RichImageEntity {
1713
+ id: string;
1714
+ fileId: string;
1715
+ name: string;
1716
+ mimeType: string;
1717
+ width: number;
1718
+ height: number;
1719
+ sha256: string;
1720
+ sizeBytes: number;
1721
+ employeeId: string;
1722
+ createdAt: string;
1723
+ }
1724
+
1709
1725
  type JsonValue = string | number | boolean | { [key in string]?: JsonValue } | Array<JsonValue> | null;
@@ -1,5 +1,6 @@
1
1
  import { type DocumentCategory, type DocumentParticipantRole, type DocumentTypeEntity } from '../base/entities';
2
2
  import {
3
+ type DocumentTemplateContent,
3
4
  type DocumentTypeCreateResponseEntity,
4
5
  type DocumentTypeGetAllResponseEntity,
5
6
  type DocumentTypeGetByIdResponseEntity,
@@ -57,6 +58,8 @@ export interface DocumentTypeWritePayload {
57
58
  enabled?: boolean;
58
59
  // Flujo sugerido, en el orden en que les toca dentro de cada rol. Al editar, si no viene, el flujo no cambia.
59
60
  flowSteps?: DocumentFlowStepInput[];
61
+ // Plantilla propia del tipo: se aplica sola al redactar. `null` la quita; al editar, si no viene, no cambia.
62
+ template?: DocumentTemplateContent | null;
60
63
  }
61
64
 
62
65
  /**
@@ -25,6 +25,7 @@ import { SignatureBatchPatterns, type SignatureBatchContract } from './signature
25
25
  import { WorkFolderPatterns, type WorkFolderContract } from './workFolder.contract';
26
26
  import { DraftingRequestPatterns, type DraftingRequestContract } from './draftingRequest.contract';
27
27
  import { InternalReviewPatterns, type InternalReviewContract } from './internalReview.contract';
28
+ import { RichImagePatterns, type RichImageContract } from './richImage.contract';
28
29
 
29
30
  export * from './contract';
30
31
  export * from './document.contract';
@@ -54,6 +55,7 @@ export * from './mailIntake.contract';
54
55
  export * from './push.contract';
55
56
  export * from './draftingRequest.contract';
56
57
  export * from './internalReview.contract';
58
+ export * from './richImage.contract';
57
59
 
58
60
  /** Patrones NATS de gestor-documental-ms, por recurso: `gestorDocumental.<recurso>.<acción>`. */
59
61
  export const GestorDocumentalPatterns = {
@@ -84,6 +86,7 @@ export const GestorDocumentalPatterns = {
84
86
  push: PushPatterns,
85
87
  draftingRequest: DraftingRequestPatterns,
86
88
  internalReview: InternalReviewPatterns,
89
+ richImage: RichImagePatterns,
87
90
  } as const;
88
91
 
89
92
  /** Contrato completo de gestor-documental-ms: la unión de los contratos de sus recursos. */
@@ -113,4 +116,5 @@ export type GestorDocumentalContract = DocumentTypeContract &
113
116
  MailIntakeContract &
114
117
  PushContract &
115
118
  DraftingRequestContract &
116
- InternalReviewContract;
119
+ InternalReviewContract &
120
+ RichImageContract;
@@ -0,0 +1,23 @@
1
+ import { type RichImageResponseEntity } from '../entities';
2
+
3
+ /** Patrones NATS de `richImage`: imágenes del editor (logos de membrete e imágenes del texto). */
4
+ export const RichImagePatterns = {
5
+ register: 'gestorDocumental.richImage.register',
6
+ getFile: 'gestorDocumental.richImage.getFile',
7
+ } as const;
8
+
9
+ export interface RichImageContract {
10
+ /**
11
+ * Registra una imagen ya subida a Drive por el gateway (en la carpeta de los documentos). El ms descarga el archivo, comprueba que sea PNG o JPEG y de
12
+ * tamaño aceptable, y guarda sus medidas y su huella.
13
+ */
14
+ [RichImagePatterns.register]: {
15
+ payload: { fileId: string; name: string; actor: { employeeId: string } };
16
+ response: RichImageResponseEntity;
17
+ };
18
+ /** El archivo de una imagen registrada, para mostrarla en el editor. */
19
+ [RichImagePatterns.getFile]: {
20
+ payload: { id: string };
21
+ response: { fileId: string; fileName: string; mimeType: string };
22
+ };
23
+ }
@@ -10,6 +10,7 @@ import {
10
10
  DocumentTrackingEntity,
11
11
  DocumentTypeEntity,
12
12
  } from '../../base/entities';
13
+ import { type RichLetterhead, type RichPage, type RichSpacing, type RichTextStyle } from './richStyle';
13
14
  import { type DocumentDraftingRequestEntity } from '../draftingRequest/draftingRequest.entity';
14
15
 
15
16
  /** Tipo documental de un documento, con lo necesario para citarlo. */
@@ -453,14 +454,16 @@ export interface DocumentTrailExportEntity {
453
454
  /** Plantilla oficial con que se redacta un documento en el sistema. */
454
455
  export type DocumentTemplateKind = 'Decree' | 'Office' | 'Memorandum' | 'General';
455
456
 
456
- /** Formato de un trozo de texto en el editor del gestor. */
457
- export type RichMark = 'bold' | 'italic' | 'underline';
457
+ /** Formato de un trozo de texto en el editor del gestor. Superíndice y subíndice no van juntos. */
458
+ export type RichMark = 'bold' | 'italic' | 'underline' | 'strike' | 'superscript' | 'subscript';
458
459
 
459
460
  /**
460
461
  * Texto con su formato, o un campo de la plantilla (`field`: su clave), que se reemplaza por su valor al armar el PDF.
461
462
  * Un salto de línea dentro del texto (`\n`) es un salto de línea del párrafo.
462
463
  */
463
- export type RichInline = { text: string; marks?: RichMark[] } | { field: string };
464
+ export type RichInline =
465
+ | { text: string; marks?: RichMark[]; style?: RichTextStyle }
466
+ | { field: string; marks?: RichMark[]; style?: RichTextStyle };
464
467
 
465
468
  export type RichAlign = 'left' | 'center' | 'right' | 'justify';
466
469
 
@@ -478,9 +481,35 @@ export type RichTableVariant = 'grid' | 'labels' | 'labelsRight';
478
481
  * bloques seguidos del mismo estilo (su nivel es la sangría, desde 0); un título o un párrafo reinicia la numeración.
479
482
  */
480
483
  export type RichBlock =
481
- | { id: string; type: 'paragraph'; align?: RichAlign; locked?: boolean; content: RichInline[] }
482
- | { id: string; type: 'heading'; level: 1 | 2; align?: RichAlign; locked?: boolean; content: RichInline[] }
483
- | { id: string; type: 'listItem'; list: RichListStyle; level: number; locked?: boolean; content: RichInline[] }
484
+ | { id: string; type: 'paragraph'; align?: RichAlign; spacing?: RichSpacing; locked?: boolean; content: RichInline[] }
485
+ | {
486
+ id: string;
487
+ type: 'heading';
488
+ level: 1 | 2;
489
+ align?: RichAlign;
490
+ spacing?: RichSpacing;
491
+ locked?: boolean;
492
+ content: RichInline[];
493
+ }
494
+ | {
495
+ id: string;
496
+ type: 'listItem';
497
+ list: RichListStyle;
498
+ level: number;
499
+ spacing?: RichSpacing;
500
+ locked?: boolean;
501
+ content: RichInline[];
502
+ }
503
+ /** Imagen registrada en el gestor (`imageId`), con su ancho en puntos (sin pasar el del texto) y alineación. */
504
+ | {
505
+ id: string;
506
+ type: 'image';
507
+ imageId: string;
508
+ width: number;
509
+ align?: 'left' | 'center' | 'right';
510
+ caption?: string;
511
+ locked?: boolean;
512
+ }
484
513
  /** `rows[fila][columna]`: el contenido de cada celda. */
485
514
  | { id: string; type: 'table'; variant: RichTableVariant; locked?: boolean; rows: RichInline[][][] }
486
515
  | { id: string; type: 'rule'; locked?: boolean }
@@ -544,6 +573,9 @@ export type DocumentComposition =
544
573
  blocks: RichBlock[];
545
574
  fields: RichField[];
546
575
  distribution: string[];
576
+ /** Página y membrete. En una plantilla propia los pone su versión: lo que mande el navegador no cuenta. */
577
+ page?: RichPage;
578
+ letterhead?: RichLetterhead;
547
579
  };
548
580
 
549
581
  /** PDF armado con una plantilla: para la vista previa (`contentBase64`) o ya subido (`fileId`). */
@@ -1 +1,2 @@
1
1
  export * from './document.entity';
2
+ export * from './richStyle';
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Formato del editor del gestor que comparten el navegador y el microservicio: tipografías, colores, tamaños de hoja y
3
+ * márgenes. Todo lo que el PDF muestra sale de aquí, así que el editor y el documento oficial se ven igual.
4
+ */
5
+
6
+ /**
7
+ * Tipografías incrustadas en el PDF (PDF/A exige fuentes incrustadas). Liberation Sans, Liberation Serif y Carlito
8
+ * miden igual que Arial, Times New Roman y Calibri: lo que se pegó desde Word ocupa lo mismo.
9
+ */
10
+ export const RICH_FONTS = {
11
+ Roboto: 'Roboto',
12
+ LiberationSans: 'Liberation Sans (Arial)',
13
+ LiberationSerif: 'Liberation Serif (Times New Roman)',
14
+ Carlito: 'Carlito (Calibri)',
15
+ } as const;
16
+
17
+ export type RichFont = keyof typeof RICH_FONTS;
18
+
19
+ /** Tamaños de letra que se ofrecen, en puntos. */
20
+ export const RICH_FONT_SIZES = [8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 24] as const;
21
+
22
+ /** Colores de letra: una paleta acotada, sobria, para documentos oficiales. */
23
+ export const RICH_COLORS = {
24
+ black: { label: 'Negro', hex: '#111827' },
25
+ gray: { label: 'Gris', hex: '#4B5563' },
26
+ blue: { label: 'Azul', hex: '#1E40AF' },
27
+ red: { label: 'Rojo', hex: '#B91C1C' },
28
+ green: { label: 'Verde', hex: '#166534' },
29
+ brown: { label: 'Café', hex: '#78350F' },
30
+ } as const;
31
+
32
+ export type RichColor = keyof typeof RICH_COLORS;
33
+
34
+ /** Resaltado del texto. */
35
+ export const RICH_HIGHLIGHTS = {
36
+ yellow: { label: 'Amarillo', hex: '#FEF08A' },
37
+ green: { label: 'Verde', hex: '#BBF7D0' },
38
+ blue: { label: 'Celeste', hex: '#BFDBFE' },
39
+ pink: { label: 'Rosado', hex: '#FBCFE8' },
40
+ gray: { label: 'Gris', hex: '#E5E7EB' },
41
+ } as const;
42
+
43
+ export type RichHighlight = keyof typeof RICH_HIGHLIGHTS;
44
+
45
+ /** Formato propio de un trozo de texto, además de sus marcas. Sin valor, el de la página. */
46
+ export interface RichTextStyle {
47
+ font?: RichFont;
48
+ size?: number;
49
+ color?: RichColor;
50
+ highlight?: RichHighlight;
51
+ }
52
+
53
+ /** Espaciado y sangría de un párrafo, título o punto de lista, en puntos (el interlineado, en veces la letra). */
54
+ export interface RichSpacing {
55
+ before?: number;
56
+ after?: number;
57
+ lineHeight?: number;
58
+ /** Sangría de la primera línea. */
59
+ firstLine?: number;
60
+ /** Sangría de todo el párrafo, desde el margen izquierdo. */
61
+ left?: number;
62
+ }
63
+
64
+ /** Límites del espaciado, en puntos. */
65
+ export const RICH_SPACING_LIMITS = { maxSpace: 72, maxIndent: 216, minLineHeight: 0.8, maxLineHeight: 3 } as const;
66
+
67
+ /** Tamaños de hoja, en puntos. Oficio es el chileno: 216 x 330 mm. */
68
+ export const RICH_PAGE_SIZES = {
69
+ letter: { label: 'Carta (216 x 279 mm)', width: 612, height: 792 },
70
+ oficio: { label: 'Oficio (216 x 330 mm)', width: 612, height: 936 },
71
+ } as const;
72
+
73
+ export type RichPageSize = keyof typeof RICH_PAGE_SIZES;
74
+
75
+ export interface RichMargins {
76
+ top: number;
77
+ right: number;
78
+ bottom: number;
79
+ left: number;
80
+ }
81
+
82
+ /**
83
+ * Márgenes mínimos, en puntos: arriba van el membrete y el número con la fecha que estampa el sistema; abajo, la
84
+ * franja del QR en cada página; a los costados, los sellos. Con menos, lo estampado taparía el texto.
85
+ */
86
+ export const RICH_MIN_MARGINS: RichMargins = { top: 64, right: 42, bottom: 64, left: 42 };
87
+
88
+ /** Márgenes máximos, en puntos (unos 5 cm). */
89
+ export const RICH_MAX_MARGIN = 144;
90
+
91
+ /** Página de un documento: tamaño, márgenes y letra base. La define la plantilla; quien redacta no la cambia. */
92
+ export interface RichPage {
93
+ size: RichPageSize;
94
+ margins: RichMargins;
95
+ font: RichFont;
96
+ fontSize: number;
97
+ lineHeight: number;
98
+ }
99
+
100
+ /** Página de siempre: Carta, con el espacio del membrete y los sellos, en Roboto 11. */
101
+ export const RICH_DEFAULT_PAGE: RichPage = {
102
+ size: 'letter',
103
+ margins: { top: 104, right: 64, bottom: 76, left: 72 },
104
+ font: 'Roboto',
105
+ fontSize: 11,
106
+ lineHeight: 1.2,
107
+ };
108
+
109
+ /**
110
+ * Membrete de la plantilla, en el margen superior de cada página: un logo o escudo (opcional) y el nombre de la
111
+ * municipalidad y de la unidad que emite. Va a la izquierda: a la derecha el sistema estampa el número y la fecha.
112
+ */
113
+ export interface RichLetterhead {
114
+ /** Imagen registrada en el gestor (`RichImage`), no un archivo de Drive. */
115
+ imageId?: string | null;
116
+ /** Alto del logo, en puntos. */
117
+ imageHeight?: number;
118
+ showOrganName: boolean;
119
+ showUnitName: boolean;
120
+ /** Líneas propias bajo el nombre, como la dirección o el teléfono. */
121
+ lines?: string[];
122
+ }
123
+
124
+ export const RICH_DEFAULT_LETTERHEAD: RichLetterhead = { imageId: null, showOrganName: true, showUnitName: true };
125
+
126
+ /** Límites de una imagen: formatos, peso y tamaño en el texto. */
127
+ export const RICH_IMAGE_LIMITS = {
128
+ types: ['image/png', 'image/jpeg'],
129
+ maxBytes: 2_000_000,
130
+ minWidth: 24,
131
+ maxLetterheadHeight: 56,
132
+ } as const;
133
+
134
+ /** Imagen subida al gestor para el editor: se usa por su id; el archivo está en Drive. */
135
+ export interface RichImageResponseEntity {
136
+ id: string;
137
+ name: string;
138
+ mimeType: string;
139
+ width: number;
140
+ height: number;
141
+ }
@@ -1,5 +1,6 @@
1
1
  import { type DocumentTemplateEntity } from '../../base/entities';
2
2
  import { type RichBlock, type RichField } from '../document/document.entity';
3
+ import { type RichLetterhead, type RichPage } from '../document/richStyle';
3
4
 
4
5
  /**
5
6
  * Contenido de una plantilla propia: los bloques del editor (con sus partes fijas) y los campos que completa quien
@@ -8,6 +9,10 @@ import { type RichBlock, type RichField } from '../document/document.entity';
8
9
  export interface DocumentTemplateContent {
9
10
  blocks: RichBlock[];
10
11
  fields: RichField[];
12
+ /** Tamaño de hoja, márgenes y letra base. Sin valor, la página de siempre (`RICH_DEFAULT_PAGE`). */
13
+ page?: RichPage;
14
+ /** Membrete con logo. Sin valor, el nombre de la municipalidad y de la unidad. */
15
+ letterhead?: RichLetterhead;
11
16
  }
12
17
 
13
18
  /** Plantilla propia en el listado de quien las administra. */
@@ -43,6 +48,8 @@ export interface DocumentTemplateAvailableResponseEntity {
43
48
  description: string | null;
44
49
  version: DocumentTemplateEntity['version'];
45
50
  content: DocumentTemplateContent;
51
+ /** Es la plantilla del tipo documental pedido: se aplica sola al redactar. */
52
+ ownedByType: boolean;
46
53
  }
47
54
 
48
55
  export interface DocumentTemplateCreateResponseEntity {
@@ -1,4 +1,5 @@
1
1
  import { DocumentTypeEntity, DocumentTypeFlowStepEntity } from '../../base/entities';
2
+ import { type DocumentTemplateContent } from '../documentTemplate/documentTemplate.entity';
2
3
 
3
4
  /** Paso del flujo sugerido de un tipo documental: quién visa o firma, en su orden. */
4
5
  export interface DocumentTypeFlowStepResponseEntity {
@@ -45,6 +46,15 @@ export interface DocumentTypeGetAllResponseEntity {
45
46
  enabled: DocumentTypeEntity['enabled'];
46
47
  // Cuántos visadores y firmantes tiene su flujo sugerido.
47
48
  flow: { visa: number; signature: number };
49
+ // Tiene plantilla propia: se aplica sola al redactar.
50
+ hasTemplate: boolean;
51
+ }
52
+
53
+ /** Plantilla propia de un tipo documental: la versión vigente de su contenido. */
54
+ export interface DocumentTypeTemplateResponseEntity {
55
+ id: string;
56
+ version: number;
57
+ content: DocumentTemplateContent;
48
58
  }
49
59
 
50
60
  export interface DocumentTypeGetByIdResponseEntity extends DocumentTypeGetAllResponseEntity {
@@ -53,6 +63,8 @@ export interface DocumentTypeGetByIdResponseEntity extends DocumentTypeGetAllRes
53
63
  lastCorrelative: number | null;
54
64
  // Flujo sugerido: primero los visadores y después los firmantes, cada grupo en su orden.
55
65
  flowSteps: DocumentTypeFlowStepResponseEntity[];
66
+ // Plantilla propia del tipo (sin valor: no la tiene).
67
+ template: DocumentTypeTemplateResponseEntity | null;
56
68
  }
57
69
 
58
70
  export interface DocumentTypeCreateResponseEntity {