@tstdl/base 0.93.95 → 0.93.97

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.
Files changed (46) hide show
  1. package/document-management/api/document-management.api.d.ts +19 -1
  2. package/document-management/api/document-management.api.js +8 -4
  3. package/document-management/models/document-category.model.d.ts +1 -0
  4. package/document-management/models/document-category.model.js +7 -1
  5. package/document-management/models/document-property.model.d.ts +1 -0
  6. package/document-management/models/document-property.model.js +7 -1
  7. package/document-management/models/document-type.model.d.ts +1 -0
  8. package/document-management/models/document-type.model.js +7 -1
  9. package/document-management/models/document-workflow.model.d.ts +1 -0
  10. package/document-management/models/document-workflow.model.js +6 -1
  11. package/document-management/server/api/document-management.api.d.ts +1 -0
  12. package/document-management/server/api/document-management.api.js +8 -7
  13. package/document-management/server/drizzle/{0000_glamorous_lorna_dane.sql → 0000_needy_steel_serpent.sql} +7 -0
  14. package/document-management/server/drizzle/meta/0000_snapshot.json +49 -1
  15. package/document-management/server/drizzle/meta/_journal.json +2 -2
  16. package/document-management/server/module.d.ts +1 -0
  17. package/document-management/server/module.js +1 -0
  18. package/document-management/server/services/document-category-type.service.d.ts +8 -3
  19. package/document-management/server/services/document-category-type.service.js +49 -6
  20. package/document-management/server/services/document-management.service.js +17 -15
  21. package/document-management/server/services/document-property.service.d.ts +3 -1
  22. package/document-management/server/services/document-property.service.js +23 -2
  23. package/document-management/server/services/document-validation.service.js +2 -1
  24. package/document-management/server/services/document-workflow.service.d.ts +3 -3
  25. package/document-management/server/services/document-workflow.service.js +34 -15
  26. package/document-management/server/services/document.service.d.ts +1 -1
  27. package/document-management/server/services/document.service.js +7 -2
  28. package/document-management/service-models/categories-and-types.view-model.d.ts +6 -0
  29. package/document-management/service-models/categories-and-types.view-model.js +18 -0
  30. package/document-management/service-models/document-management.view-model.d.ts +1 -0
  31. package/document-management/service-models/document-management.view-model.js +5 -0
  32. package/document-management/service-models/document.service-model.d.ts +7 -0
  33. package/document-management/service-models/document.service-model.js +7 -1
  34. package/document-management/service-models/enriched/enriched-document-category.view.d.ts +1 -0
  35. package/document-management/service-models/enriched/enriched-document-category.view.js +2 -0
  36. package/document-management/service-models/enriched/enriched-document-type.view.d.ts +1 -0
  37. package/document-management/service-models/enriched/enriched-document-type.view.js +2 -0
  38. package/document-management/tests/document-management-core.test.d.ts +1 -0
  39. package/document-management/tests/document-management-core.test.js +162 -0
  40. package/document-management/tests/document.service.test.d.ts +1 -0
  41. package/document-management/tests/document.service.test.js +139 -0
  42. package/document-management/tests/enum-helpers.test.d.ts +1 -0
  43. package/document-management/tests/enum-helpers.test.js +452 -0
  44. package/document-management/tests/helper.d.ts +24 -0
  45. package/document-management/tests/helper.js +39 -0
  46. package/package.json +5 -5
@@ -18,7 +18,7 @@ import { distinct } from '../../../utils/array/index.js';
18
18
  import { compareByValueSelection } from '../../../utils/comparison.js';
19
19
  import { groupToMap, groupToSingleMap } from '../../../utils/iterable-helpers/index.js';
20
20
  import { fromEntries, objectEntries } from '../../../utils/object/index.js';
21
- import { assertDefinedPass, isDefined, isNotNull, isNotNullOrUndefined, isNull, isUndefined } from '../../../utils/type-guards.js';
21
+ import { assertDefinedPass, isDefined, isNotNull, isNull, isUndefined } from '../../../utils/type-guards.js';
22
22
  import { filter, merge } from 'rxjs';
23
23
  import { DocumentAssignmentScope, DocumentAssignmentTask, DocumentCategory, DocumentCollectionAssignment, DocumentRequest, DocumentRequestCollectionAssignment, DocumentRequestTemplate, DocumentRequestsTemplate, DocumentType, DocumentTypeProperty, DocumentValidationExecution, DocumentWorkflowStep } from '../../models/index.js';
24
24
  import { documentAssignmentScope, documentAssignmentTask, documentCollectionAssignment, documentRequest, documentRequestCollectionAssignment } from '../schemas.js';
@@ -29,7 +29,6 @@ import { DocumentPropertyService } from './document-property.service.js';
29
29
  import { DocumentTagService } from './document-tag.service.js';
30
30
  import { DocumentWorkflowService } from './document-workflow.service.js';
31
31
  import { DocumentService } from './document.service.js';
32
- import { enumTypeKey } from './enum-type-key.js';
33
32
  import { DocumentManagementSingleton } from './singleton.js';
34
33
  let DocumentManagementService = DocumentManagementService_1 = class DocumentManagementService extends Transactional {
35
34
  #documentCollectionService = injectTransactional(DocumentCollectionService);
@@ -92,7 +91,7 @@ let DocumentManagementService = DocumentManagementService_1 = class DocumentMana
92
91
  throw new BadRequestError('At least one collection ID must be provided to load document management data.');
93
92
  }
94
93
  return await this.transaction(async (tx) => {
95
- const [collections, documentCollectionAssignments, requestAssignments, assignmentScopes, { categories, types }] = await Promise.all([
94
+ const [collections, documentCollectionAssignments, requestAssignments, assignmentScopes, { categories, types, properties }] = await Promise.all([
96
95
  this.#documentCollectionService.repository.withTransaction(tx).loadManyByQuery({ tenantId, id: { $in: collectionIds } }),
97
96
  this.#documentCollectionAssignmentRepository.withTransaction(tx).loadManyByQuery({ tenantId, collectionId: { $in: collectionIds } }),
98
97
  this.#documentRequestCollectionAssignmentRepository.withTransaction(tx).loadManyByQuery({ tenantId, collectionId: { $in: collectionIds } }),
@@ -110,9 +109,8 @@ let DocumentManagementService = DocumentManagementService_1 = class DocumentMana
110
109
  const requestDocumentIds = requests.map((request) => request.documentId).filter(isNotNull);
111
110
  const assignmentTaskDocumentIds = assignmentTasks.map((task) => task.documentId);
112
111
  const documentIds = distinct([...assignmentDocumentIds, ...requestDocumentIds, ...assignmentTaskDocumentIds]);
113
- const [documents, propertyViews, propertyValues, workflows] = await Promise.all([
112
+ const [documents, propertyValues, workflows] = await Promise.all([
114
113
  this.#documentService.repository.withTransaction(tx).loadManyByQuery({ tenantId, id: { $in: documentIds } }, { order: { 'metadata.createTimestamp': 'desc' } }),
115
- this.#documentPropertyService.withTransaction(tx).loadViews(tenantId),
116
114
  this.#documentPropertyService.withTransaction(tx).loadDocumentPropertyValues(tenantId, documentIds),
117
115
  this.#documentWorkflowService.withTransaction(tx).loadWorkflows(tenantId, documentIds),
118
116
  ]);
@@ -164,7 +162,7 @@ let DocumentManagementService = DocumentManagementService_1 = class DocumentMana
164
162
  categories,
165
163
  types,
166
164
  tags,
167
- properties: propertyViews,
165
+ properties,
168
166
  };
169
167
  });
170
168
  }
@@ -182,25 +180,27 @@ let DocumentManagementService = DocumentManagementService_1 = class DocumentMana
182
180
  });
183
181
  }
184
182
  async initializeCategoriesAndTypes(tenantId, data) {
183
+ this.#documentCategoryTypeService.invalidateCache(tenantId);
184
+ this.#documentPropertyService.invalidateCache(tenantId);
185
185
  const categoryEntries = objectEntries(data.categoryLabels);
186
186
  const typeEntries = objectEntries(data.typeLabels);
187
187
  const propertyEntries = objectEntries(data.propertyConfigurations);
188
188
  const { categoryMap, typeMap, propertyMap } = await this.transaction(async (tx) => {
189
189
  const { categories: dbCategories, types: dbTypes } = await this.#documentCategoryTypeService.withTransaction(tx).loadCategoriesAndTypes(tenantId);
190
190
  const dbProperties = await this.#documentPropertyService.withTransaction(tx).repository.loadManyByQuery({ tenantId });
191
- const categories = dbCategories.filter((category) => isNotNullOrUndefined(category.metadata.attributes[enumTypeKey]));
192
- const types = dbTypes.filter((type) => isNotNullOrUndefined(type.metadata.attributes[enumTypeKey]));
193
- const properties = dbProperties.filter((property) => isNotNullOrUndefined(property.metadata.attributes[enumTypeKey]));
194
- const enumKeyCategoryMap = groupToSingleMap(categories, (category) => category.metadata.attributes[enumTypeKey]);
195
- const enumKeyTypeMap = groupToSingleMap(types, (type) => type.metadata.attributes[enumTypeKey]);
196
- const enumKeyPropertyMap = groupToSingleMap(properties, (property) => property.metadata.attributes[enumTypeKey]);
191
+ const categories = dbCategories.filter((category) => isNotNull(category.key));
192
+ const types = dbTypes.filter((type) => isNotNull(type.key));
193
+ const properties = dbProperties.filter((property) => isNotNull(property.key));
194
+ const enumKeyCategoryMap = groupToSingleMap(categories, (category) => category.key);
195
+ const enumKeyTypeMap = groupToSingleMap(types, (type) => type.key);
196
+ const enumKeyPropertyMap = groupToSingleMap(properties, (property) => property.key);
197
197
  for (const [enumKey, label] of categoryEntries) {
198
198
  const category = enumKeyCategoryMap.get(enumKey);
199
199
  const parentKey = assertDefinedPass(data.categoryParents[enumKey], `Parent category not defined for ${enumKey}`);
200
200
  const parentCategory = isNull(parentKey) ? null : assertDefinedPass(enumKeyCategoryMap.get(parentKey));
201
201
  const parentCategoryId = parentCategory?.id ?? null;
202
202
  if (isUndefined(category)) {
203
- const category = await this.#documentCategoryTypeService.withTransaction(tx).createCategory({ tenantId, label, parentId: parentCategoryId, enumKey });
203
+ const category = await this.#documentCategoryTypeService.withTransaction(tx).createCategory({ tenantId, label, parentId: parentCategoryId, key: enumKey });
204
204
  enumKeyCategoryMap.set(enumKey, category);
205
205
  this.#logger.info(`Created category "${category.label}"`);
206
206
  }
@@ -215,7 +215,7 @@ let DocumentManagementService = DocumentManagementService_1 = class DocumentMana
215
215
  const enumCategory = data.typeCategories[enumKey];
216
216
  const category = assertDefinedPass(enumKeyCategoryMap.get(enumCategory));
217
217
  if (isUndefined(type)) {
218
- const type = await this.#documentCategoryTypeService.withTransaction(tx).createType({ tenantId, label, categoryId: category.id, enumKey });
218
+ const type = await this.#documentCategoryTypeService.withTransaction(tx).createType({ tenantId, label, categoryId: category.id, key: enumKey });
219
219
  enumKeyTypeMap.set(enumKey, type);
220
220
  this.#logger.info(`Created type "${type.label}" in category "${category.label}"`);
221
221
  }
@@ -228,7 +228,7 @@ let DocumentManagementService = DocumentManagementService_1 = class DocumentMana
228
228
  for (const [enumKey, [dataType, label]] of propertyEntries) {
229
229
  const property = enumKeyPropertyMap.get(enumKey);
230
230
  if (isUndefined(property)) {
231
- const newProperty = await this.#documentPropertyService.withTransaction(tx).createProperty({ tenantId, label, dataType, enumKey });
231
+ const newProperty = await this.#documentPropertyService.withTransaction(tx).createProperty({ tenantId, label, dataType, key: enumKey });
232
232
  enumKeyPropertyMap.set(enumKey, newProperty);
233
233
  this.#logger.info(`Created property "${newProperty.label}" of type "${dataType}"`);
234
234
  }
@@ -249,6 +249,8 @@ let DocumentManagementService = DocumentManagementService_1 = class DocumentMana
249
249
  }
250
250
  return { categoryMap: enumKeyCategoryMap, typeMap: enumKeyTypeMap, propertyMap: enumKeyPropertyMap };
251
251
  });
252
+ this.#documentCategoryTypeService.invalidateCache(tenantId);
253
+ this.#documentPropertyService.invalidateCache(tenantId);
252
254
  const mappedCategories = categoryEntries.map(([key]) => [key, assertDefinedPass(categoryMap.get(key), 'Could not map document category.')]);
253
255
  const mappedTypes = typeEntries.map(([key]) => [key, assertDefinedPass(typeMap.get(key), 'Could not map document type.')]);
254
256
  const mappedProperties = propertyEntries.map(([key]) => [key, assertDefinedPass(propertyMap.get(key), 'Could not map document property.')]);
@@ -5,6 +5,8 @@ import type { DocumentPropertyValueView, DocumentPropertyView, SetDocumentProper
5
5
  export declare class DocumentPropertyService extends Transactional {
6
6
  #private;
7
7
  readonly repository: import("../../../orm/server/index.js").EntityRepository<DocumentProperty>;
8
+ invalidateCache(tenantId: string): void;
9
+ getPropertyId(tenantId: string, key: string): Promise<string>;
8
10
  readonly documentProperties: import("drizzle-orm/pg-core").WithSubqueryWithSelection<{
9
11
  documentId: import("drizzle-orm").SQL.Aliased<string>;
10
12
  propertyId: import("drizzle-orm").SQL.Aliased<string>;
@@ -51,7 +53,7 @@ export declare class DocumentPropertyService extends Transactional {
51
53
  tenantId: string;
52
54
  label: string;
53
55
  dataType: DocumentPropertyDataType;
54
- enumKey?: string;
56
+ key?: string;
55
57
  }): Promise<DocumentProperty>;
56
58
  updateProperty(tenantId: string, id: string, update: {
57
59
  label?: string;
@@ -15,7 +15,6 @@ import { assertBooleanPass, assertNumberPass, assertStringPass, isBoolean, isNot
15
15
  import { DocumentProperty, DocumentPropertyDataType, DocumentPropertyValue, DocumentTypeProperty } from '../../models/index.js';
16
16
  import { document, documentProperty, documentPropertyValue, documentType, documentTypeProperty } from '../schemas.js';
17
17
  import { DocumentManagementObservationService } from './document-management-observation.service.js';
18
- import { enumTypeKey } from './enum-type-key.js';
19
18
  import { DocumentManagementSingleton } from './singleton.js';
20
19
  const documentPropertyValueValidators = {
21
20
  [DocumentPropertyDataType.Text]: (value) => isString(value) || isNull(value),
@@ -30,6 +29,18 @@ let DocumentPropertyService = class DocumentPropertyService extends Transactiona
30
29
  #documentTypePropertyRepository = injectRepository(DocumentTypeProperty);
31
30
  #observationService = inject(DocumentManagementObservationService);
32
31
  repository = injectRepository(DocumentProperty);
32
+ #propertyCache = new Map();
33
+ invalidateCache(tenantId) {
34
+ this.#propertyCache.delete(tenantId);
35
+ }
36
+ async getPropertyId(tenantId, key) {
37
+ const cache = await this.#getPropertyCache(tenantId);
38
+ const id = cache.get(key);
39
+ if (isUndefined(id)) {
40
+ throw new NotFoundError(`Document property with key "${key}" not found for tenant "${tenantId}".`);
41
+ }
42
+ return id;
43
+ }
33
44
  documentProperties = this.session.$with('documentProperties').as((qb) => qb
34
45
  .select({
35
46
  documentId: autoAlias(document.id),
@@ -55,6 +66,7 @@ let DocumentPropertyService = class DocumentPropertyService extends Transactiona
55
66
  return {
56
67
  id: property.id,
57
68
  tenantId: property.tenantId,
69
+ key: property.key,
58
70
  label: property.label,
59
71
  dataType: property.dataType,
60
72
  typeIds,
@@ -66,7 +78,7 @@ let DocumentPropertyService = class DocumentPropertyService extends Transactiona
66
78
  tenantId: data.tenantId,
67
79
  label: data.label,
68
80
  dataType: data.dataType,
69
- metadata: { attributes: { [enumTypeKey]: data.enumKey } },
81
+ key: data.key ?? null,
70
82
  });
71
83
  }
72
84
  async updateProperty(tenantId, id, update) {
@@ -120,6 +132,15 @@ let DocumentPropertyService = class DocumentPropertyService extends Transactiona
120
132
  this.#observationService.documentChange(document.id, tx);
121
133
  });
122
134
  }
135
+ async #getPropertyCache(tenantId) {
136
+ let cache = this.#propertyCache.get(tenantId);
137
+ if (isUndefined(cache)) {
138
+ const properties = await this.#documentPropertyRepository.loadManyByQuery({ tenantId, key: { $neq: null } });
139
+ cache = new Map(properties.map((property) => [property.key, property.id]));
140
+ this.#propertyCache.set(tenantId, cache);
141
+ }
142
+ return cache;
143
+ }
123
144
  };
124
145
  DocumentPropertyService = __decorate([
125
146
  DocumentManagementSingleton()
@@ -56,7 +56,8 @@ let DocumentValidationService = DocumentValidationService_1 = class DocumentVali
56
56
  if (isNull(document.typeId)) {
57
57
  throw new BadRequestError('Document has no type');
58
58
  }
59
- const workflow = await this.#documentWorkflowService.initiateWorkflow(document.tenantId, documentId, DocumentWorkflowStep.Validation);
59
+ const latestWorkflow = await this.#documentWorkflowService.loadLatestWorkflow(tenantId, documentId);
60
+ const workflow = await this.#documentWorkflowService.initiateWorkflow(document.tenantId, documentId, DocumentWorkflowStep.Validation, latestWorkflow?.skipAi ?? false);
60
61
  const typeValidations = await this.#documentTypeValidationService.loadManyByQuery({ tenantId, typeId: document.typeId });
61
62
  for (const typeValidation of typeValidations) {
62
63
  const validationDefinition = await this.#validationDefinitionService.loadByQuery({ tenantId, id: typeValidation.validationId });
@@ -2,7 +2,7 @@ import type { AfterResolveContext } from '../../../injector/index.js';
2
2
  import { afterResolve } from '../../../injector/interfaces.js';
3
3
  import { Transactional } from '../../../orm/server/index.js';
4
4
  import type { OneOrMany } from '../../../types/index.js';
5
- import { DocumentWorkflow, DocumentWorkflowStep } from '../../models/document-workflow.model.js';
5
+ import { DocumentWorkflow, DocumentWorkflowState, DocumentWorkflowStep } from '../../models/document-workflow.model.js';
6
6
  export declare class DocumentWorkflowService extends Transactional {
7
7
  #private;
8
8
  private readonly documentService;
@@ -11,8 +11,8 @@ export declare class DocumentWorkflowService extends Transactional {
11
11
  loadLatestWorkflow(tenantId: string, documentId: string): Promise<DocumentWorkflow>;
12
12
  loadLatestWorkflows(tenantId: string, documentIds: string[]): Promise<DocumentWorkflow[]>;
13
13
  loadWorkflows(tenantId: string, documentId: OneOrMany<string>): Promise<DocumentWorkflow[]>;
14
- proceedWorkflow(tenantId: string, documentId: string, userId: string): Promise<void>;
15
- initiateWorkflow(tenantId: string, documentId: string, step: DocumentWorkflowStep): Promise<DocumentWorkflow>;
14
+ proceedWorkflow(tenantId: string, documentId: string, userId: string, targetState: DocumentWorkflowState): Promise<void>;
15
+ initiateWorkflow(tenantId: string, documentId: string, step: DocumentWorkflowStep, skipAi: boolean): Promise<DocumentWorkflow>;
16
16
  private setWorkflowState;
17
17
  private processWorkflowJob;
18
18
  private processClassificationWorkflow;
@@ -16,7 +16,6 @@ import { injectRepository, injectTransactional, Transactional } from '../../../o
16
16
  import { TaskProcessResult, TaskQueue } from '../../../task-queue/task-queue.js';
17
17
  import { toArray } from '../../../utils/array/array.js';
18
18
  import { currentTimestamp } from '../../../utils/date-time.js';
19
- import { _throw } from '../../../utils/throw.js';
20
19
  import { isNotNull, isNull } from '../../../utils/type-guards.js';
21
20
  import { and, desc, eq, inArray } from 'drizzle-orm';
22
21
  import { DocumentAssignmentScope } from '../../models/document-assignment-scope.model.js';
@@ -61,28 +60,48 @@ let DocumentWorkflowService = DocumentWorkflowService_1 = class DocumentWorkflow
61
60
  async loadWorkflows(tenantId, documentId) {
62
61
  return await this.repository.loadManyByQuery({ tenantId, documentId: { $in: toArray(documentId) } }, { order: { 'documentId': 'asc', 'metadata.createTimestamp': 'desc' } });
63
62
  }
64
- async proceedWorkflow(tenantId, documentId, userId) {
63
+ async proceedWorkflow(tenantId, documentId, userId, targetState) {
65
64
  await this.transaction(async (tx) => {
66
65
  const workflow = await this.withTransaction(tx).loadLatestWorkflow(tenantId, documentId);
67
- if (workflow.state != DocumentWorkflowState.Review) {
68
- throw new BadRequestError('Current workflow is not in review state.');
66
+ const canProceed = (workflow.state == DocumentWorkflowState.Review) || (workflow.skipAi && (workflow.state == DocumentWorkflowState.Pending));
67
+ if (!canProceed) {
68
+ throw new BadRequestError('Current workflow is not in a state that can be proceeded.');
69
+ }
70
+ if ((workflow.state == DocumentWorkflowState.Review) && (targetState != DocumentWorkflowState.Completed)) {
71
+ throw new BadRequestError('Can only proceed to completed state from review.');
72
+ }
73
+ if ((targetState != DocumentWorkflowState.Review) && (targetState != DocumentWorkflowState.Completed)) {
74
+ throw new BadRequestError('Invalid target state.');
69
75
  }
70
76
  if (isNotNull(workflow.completeUserId)) {
71
77
  throw new BadRequestError('Latest workflow is already completed.');
72
78
  }
73
- await this.repository.withTransaction(tx).update(workflow.id, { state: DocumentWorkflowState.Completed, completeUserId: userId });
74
- await match(workflow.step)
75
- .with(DocumentWorkflowStep.Classification, () => _throw(new BadRequestError('Proceeding from classification occurs automatically.')))
76
- .with(DocumentWorkflowStep.Extraction, async () => await this.withTransaction(tx).initiateWorkflow(tenantId, documentId, DocumentWorkflowStep.Assignment))
77
- .with(DocumentWorkflowStep.Assignment, async () => await this.withTransaction(tx).initiateWorkflow(tenantId, documentId, DocumentWorkflowStep.Validation))
78
- .with(DocumentWorkflowStep.Validation, () => { })
79
- .exhaustive();
79
+ await this.repository.withTransaction(tx).update(workflow.id, {
80
+ state: targetState,
81
+ completeUserId: (targetState == DocumentWorkflowState.Completed) ? userId : undefined,
82
+ completeTimestamp: (targetState == DocumentWorkflowState.Completed) ? currentTimestamp() : undefined,
83
+ });
84
+ if (targetState == DocumentWorkflowState.Completed) {
85
+ await match(workflow.step)
86
+ .with(DocumentWorkflowStep.Classification, async () => {
87
+ if (!workflow.skipAi) {
88
+ throw new BadRequestError('Proceeding from classification occurs automatically.');
89
+ }
90
+ await this.withTransaction(tx).initiateWorkflow(tenantId, documentId, DocumentWorkflowStep.Extraction, workflow.skipAi);
91
+ })
92
+ .with(DocumentWorkflowStep.Extraction, async () => await this.withTransaction(tx).initiateWorkflow(tenantId, documentId, DocumentWorkflowStep.Assignment, workflow.skipAi))
93
+ .with(DocumentWorkflowStep.Assignment, async () => await this.withTransaction(tx).initiateWorkflow(tenantId, documentId, DocumentWorkflowStep.Validation, workflow.skipAi))
94
+ .with(DocumentWorkflowStep.Validation, () => { })
95
+ .exhaustive();
96
+ }
80
97
  this.#observationService.documentChange(workflow.id, tx);
81
98
  });
82
99
  }
83
- async initiateWorkflow(tenantId, documentId, step) {
84
- const workflow = await this.repository.insert({ tenantId, documentId, step, state: 'pending', failReason: null, completeTimestamp: null, completeUserId: null });
85
- await this.#taskQueue.enqueue('workflow', { workflowId: workflow.id });
100
+ async initiateWorkflow(tenantId, documentId, step, skipAi) {
101
+ const workflow = await this.repository.insert({ tenantId, documentId, step, state: 'pending', failReason: null, completeTimestamp: null, completeUserId: null, skipAi });
102
+ if (!skipAi) {
103
+ await this.#taskQueue.enqueue('workflow', { workflowId: workflow.id });
104
+ }
86
105
  this.#observationService.documentChange(workflow.id, this.session);
87
106
  return workflow;
88
107
  }
@@ -104,7 +123,7 @@ let DocumentWorkflowService = DocumentWorkflowService_1 = class DocumentWorkflow
104
123
  if (workflow.step == DocumentWorkflowStep.Classification) {
105
124
  // no need for after classification review. Automatically start extraction.
106
125
  await this.setWorkflowState(workflow.id, DocumentWorkflowState.Completed);
107
- await this.initiateWorkflow(workflow.tenantId, workflow.documentId, DocumentWorkflowStep.Extraction);
126
+ await this.initiateWorkflow(workflow.tenantId, workflow.documentId, DocumentWorkflowStep.Extraction, workflow.skipAi);
108
127
  }
109
128
  else {
110
129
  await this.setWorkflowState(workflow.id, DocumentWorkflowState.Review);
@@ -5,7 +5,7 @@ import type { CreateDocumentParameters, SetDocumentPropertyParameters, UpdateDoc
5
5
  export declare class DocumentService extends Transactional {
6
6
  #private;
7
7
  readonly repository: import("../../../orm/server/index.js").EntityRepository<Document>;
8
- create(tenantId: string, { typeId, title, subtitle, date, summary, tags, approval, comment, originalFileName, assignment, properties, metadata }: TypedOmit<CreateDocumentParameters, 'uploadId'>, contentSource: Uint8Array<ArrayBuffer> | ReadableStream<Uint8Array<ArrayBuffer>> | {
8
+ create(tenantId: string, { typeId, title, subtitle, date, summary, tags, approval, comment, originalFileName, assignment, properties, skipAi, skipWorkflow, metadata }: TypedOmit<CreateDocumentParameters, 'uploadId'>, contentSource: Uint8Array<ArrayBuffer> | ReadableStream<Uint8Array<ArrayBuffer>> | {
9
9
  uploadId: string;
10
10
  uploadKey: string;
11
11
  }): Promise<Document>;
@@ -18,6 +18,7 @@ import { readableStreamFromPromise } from '../../../utils/stream/from-promise.js
18
18
  import { tryIgnoreLogAsync } from '../../../utils/try-ignore.js';
19
19
  import { isDefined, isNotReadableStream, isNotUint8Array, isUndefined } from '../../../utils/type-guards.js';
20
20
  import { Document, DocumentApproval, DocumentAssignmentScope, DocumentAssignmentTask, DocumentWorkflowStep } from '../../models/index.js';
21
+ import { DocumentManagementConfiguration } from '../module.js';
21
22
  import { DocumentCollectionService } from './document-collection.service.js';
22
23
  import { DocumentFileService } from './document-file.service.js';
23
24
  import { DocumentManagementObservationService } from './document-management-observation.service.js';
@@ -27,6 +28,7 @@ import { DocumentTagService } from './document-tag.service.js';
27
28
  import { DocumentWorkflowService } from './document-workflow.service.js';
28
29
  import { DocumentManagementSingleton } from './singleton.js';
29
30
  let DocumentService = DocumentService_1 = class DocumentService extends Transactional {
31
+ #configuration = inject(DocumentManagementConfiguration);
30
32
  #documentFileService = injectTransactional(DocumentFileService);
31
33
  #documentTagService = injectTransactional(DocumentTagService);
32
34
  #requestService = injectTransactional(DocumentRequestService);
@@ -38,7 +40,7 @@ let DocumentService = DocumentService_1 = class DocumentService extends Transact
38
40
  #observationService = inject(DocumentManagementObservationService);
39
41
  #logger = inject(Logger, DocumentService_1.name);
40
42
  repository = injectRepository(Document);
41
- async create(tenantId, { typeId, title, subtitle, date, summary, tags, approval, comment, originalFileName, assignment, properties, metadata }, contentSource) {
43
+ async create(tenantId, { typeId, title, subtitle, date, summary, tags, approval, comment, originalFileName, assignment, properties, skipAi, skipWorkflow, metadata }, contentSource) {
42
44
  const document = await this.transaction(async (tx) => {
43
45
  const isUpload = isNotUint8Array(contentSource) && isNotReadableStream(contentSource);
44
46
  const document = await this.repository.withTransaction(tx).insert({
@@ -74,7 +76,10 @@ let DocumentService = DocumentService_1 = class DocumentService extends Transact
74
76
  await this.#documentPropertyService.withTransaction(tx).setPropertyValues(document, properties);
75
77
  }
76
78
  await this.withTransaction(tx).createAssignment(document, assignment, tx);
77
- await this.#workflowService.withTransaction(tx).initiateWorkflow(tenantId, document.id, DocumentWorkflowStep.Classification);
79
+ if (skipWorkflow != true) {
80
+ const effectiveSkipAi = this.#configuration.skipAi ?? skipAi ?? false;
81
+ await this.#workflowService.withTransaction(tx).initiateWorkflow(tenantId, document.id, DocumentWorkflowStep.Classification, effectiveSkipAi);
82
+ }
78
83
  return document;
79
84
  });
80
85
  this.#observationService.documentChange(document.id);
@@ -1,5 +1,11 @@
1
1
  import { DocumentCategory, DocumentType } from '../models/index.js';
2
+ import { DocumentPropertyView } from './document-management.view-model.js';
2
3
  export declare class DocumentCategoryView extends DocumentCategory {
3
4
  children: DocumentCategoryView[];
4
5
  types: DocumentType[];
5
6
  }
7
+ export declare class CategoriesAndTypesData {
8
+ categories: DocumentCategory[];
9
+ types: DocumentType[];
10
+ properties: DocumentPropertyView[];
11
+ }
@@ -9,6 +9,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
9
9
  };
10
10
  import { Array, deferred } from '../../schema/index.js';
11
11
  import { DocumentCategory, DocumentType } from '../models/index.js';
12
+ import { DocumentPropertyView } from './document-management.view-model.js';
12
13
  export class DocumentCategoryView extends DocumentCategory {
13
14
  children;
14
15
  types;
@@ -21,3 +22,20 @@ __decorate([
21
22
  Array(DocumentType),
22
23
  __metadata("design:type", Array)
23
24
  ], DocumentCategoryView.prototype, "types", void 0);
25
+ export class CategoriesAndTypesData {
26
+ categories;
27
+ types;
28
+ properties;
29
+ }
30
+ __decorate([
31
+ Array(DocumentCategory),
32
+ __metadata("design:type", Array)
33
+ ], CategoriesAndTypesData.prototype, "categories", void 0);
34
+ __decorate([
35
+ Array(DocumentType),
36
+ __metadata("design:type", Array)
37
+ ], CategoriesAndTypesData.prototype, "types", void 0);
38
+ __decorate([
39
+ Array(DocumentPropertyView),
40
+ __metadata("design:type", Array)
41
+ ], CategoriesAndTypesData.prototype, "properties", void 0);
@@ -41,6 +41,7 @@ export declare class DocumentRequestView extends DocumentRequest {
41
41
  export declare class DocumentPropertyView implements TypedOmit<DocumentProperty, 'metadata'> {
42
42
  id: string;
43
43
  tenantId: string;
44
+ key: string | null;
44
45
  label: string;
45
46
  dataType: DocumentPropertyDataType;
46
47
  typeIds: string[];
@@ -134,6 +134,7 @@ __decorate([
134
134
  export class DocumentPropertyView {
135
135
  id;
136
136
  tenantId;
137
+ key;
137
138
  label;
138
139
  dataType;
139
140
  typeIds;
@@ -146,6 +147,10 @@ __decorate([
146
147
  StringProperty({ nullable: true }),
147
148
  __metadata("design:type", String)
148
149
  ], DocumentPropertyView.prototype, "tenantId", void 0);
150
+ __decorate([
151
+ StringProperty({ nullable: true }),
152
+ __metadata("design:type", Object)
153
+ ], DocumentPropertyView.prototype, "key", void 0);
149
154
  __decorate([
150
155
  StringProperty(),
151
156
  __metadata("design:type", String)
@@ -46,6 +46,8 @@ export declare const createDocumentParametersSchema: import("../../schema/index.
46
46
  }> | undefined;
47
47
  }[] | undefined;
48
48
  tags?: string[] | undefined;
49
+ skipAi?: boolean | undefined;
50
+ skipWorkflow?: boolean | undefined;
49
51
  metadata?: Partial<{
50
52
  attributes: import("../../orm/index.js").HasDefault<import("../../orm/index.js").Json<import("../../orm/index.js").EntityMetadataAttributes>>;
51
53
  }> | undefined;
@@ -232,6 +234,10 @@ export declare const addOrArchiveDocumentToOrFromCollectionParametersSchema: imp
232
234
  attributes: import("../../orm/index.js").HasDefault<import("../../orm/index.js").Json<import("../../orm/index.js").EntityMetadataAttributes>>;
233
235
  }> | undefined;
234
236
  }>;
237
+ export declare const proceedDocumentWorkflowParametersSchema: import("../../schema/index.js").ObjectSchema<{
238
+ id: string;
239
+ state: "error" | "pending" | "running" | "completed" | "review" | "failed";
240
+ }>;
235
241
  export type MetadataParameter = SchemaOutput<typeof metadataParameterObjectSchema>;
236
242
  export type LoadDataParameters = SchemaOutput<typeof loadDataParametersSchema>;
237
243
  export type CreateCollectionParameters = SchemaOutput<typeof createCollectionParametersSchema>;
@@ -257,3 +263,4 @@ export type AddOrArchiveDocumentToOrFromCollectionParameters = SchemaOutput<type
257
263
  export type UpdateDocumentParameters = SchemaOutput<typeof updateDocumentParametersSchema>;
258
264
  export type UpdateDocumentRequestParameters = SchemaOutput<typeof updateDocumentRequestParametersSchema>;
259
265
  export type DeleteDocumentRequestParameters = SchemaOutput<typeof deleteDocumentRequestParametersSchema>;
266
+ export type ProceedDocumentWorkflowParameters = SchemaOutput<typeof proceedDocumentWorkflowParametersSchema>;
@@ -1,6 +1,6 @@
1
1
  import { EntityMetadata } from '../../orm/index.js';
2
2
  import { array, assign, boolean, enumeration, never, nullable, number, object, omit, oneOrMany, optional, partial, pick, string, union } from '../../schema/index.js';
3
- import { Document, DocumentAssignmentTarget, DocumentCategory, DocumentCollection, DocumentCollectionAssignment, DocumentProperty, DocumentPropertyValue, DocumentRequest, DocumentRequestsTemplate, DocumentRequestTemplate, DocumentType, DocumentTypeProperty } from '../models/index.js';
3
+ import { Document, DocumentAssignmentTarget, DocumentCategory, DocumentCollection, DocumentCollectionAssignment, DocumentProperty, DocumentPropertyValue, DocumentRequest, DocumentRequestsTemplate, DocumentRequestTemplate, DocumentType, DocumentTypeProperty, DocumentWorkflowState } from '../models/index.js';
4
4
  export const metadataParameterSchema = optional(partial(pick(EntityMetadata, 'attributes')));
5
5
  export const metadataParameterObjectSchema = object({ metadata: metadataParameterSchema });
6
6
  export const setDocumentPropertyParametersSchema = assign(pick(DocumentPropertyValue, ['propertyId']), object({ value: union(string(), number(), boolean(), nullable(never())) }), metadataParameterObjectSchema);
@@ -19,6 +19,8 @@ export const createDocumentParametersSchema = assign(partial(pick(Document, ['ty
19
19
  })),
20
20
  tags: optional(array(string())),
21
21
  properties: optional(array(setDocumentPropertyParametersSchema)),
22
+ skipAi: optional(boolean()),
23
+ skipWorkflow: optional(boolean()),
22
24
  }), metadataParameterObjectSchema);
23
25
  export const updateDocumentParametersSchema = assign(pick(Document, ['id']), partial(pick(Document, ['title', 'subtitle', 'date', 'comment', 'typeId'])), object({
24
26
  tags: optional(array(string())),
@@ -53,3 +55,7 @@ export const rejectDocumentRequestParametersSchema = assign(pick(DocumentRequest
53
55
  export const createDocumentPropertyParametersSchema = assign(pick(DocumentProperty, ['label', 'dataType']), metadataParameterObjectSchema);
54
56
  export const assignPropertyToTypeParametersSchema = assign(pick(DocumentTypeProperty, ['typeId', 'propertyId']), metadataParameterObjectSchema);
55
57
  export const addOrArchiveDocumentToOrFromCollectionParametersSchema = assign(pick(DocumentCollectionAssignment, ['collectionId', 'documentId']), metadataParameterObjectSchema);
58
+ export const proceedDocumentWorkflowParametersSchema = object({
59
+ id: string(),
60
+ state: enumeration(DocumentWorkflowState),
61
+ });
@@ -7,6 +7,7 @@ export declare class EnrichedDocumentCategory implements TypedOmit<DocumentCateg
7
7
  #private;
8
8
  readonly id: string;
9
9
  readonly tenantId: string;
10
+ readonly key: string | null;
10
11
  readonly label: string;
11
12
  readonly parent: EnrichedDocumentCategory | null;
12
13
  readonly helper: {
@@ -16,6 +16,7 @@ export class EnrichedDocumentCategory {
16
16
  #data;
17
17
  id;
18
18
  tenantId;
19
+ key;
19
20
  label;
20
21
  parent;
21
22
  helper = lazyObject({
@@ -52,6 +53,7 @@ export class EnrichedDocumentCategory {
52
53
  this.#data = data;
53
54
  this.id = category.id;
54
55
  this.tenantId = category.tenantId;
56
+ this.key = category.key;
55
57
  this.label = category.label;
56
58
  this.parent = parent;
57
59
  }
@@ -7,6 +7,7 @@ export declare class EnrichedDocumentType implements TypedOmit<DocumentType, 'ca
7
7
  #private;
8
8
  readonly id: string;
9
9
  readonly tenantId: string;
10
+ readonly key: string | null;
10
11
  readonly label: string;
11
12
  readonly category: EnrichedDocumentCategory;
12
13
  readonly helper: {
@@ -14,6 +14,7 @@ export class EnrichedDocumentType {
14
14
  #data;
15
15
  id;
16
16
  tenantId;
17
+ key;
17
18
  label;
18
19
  category;
19
20
  helper = lazyObject({
@@ -26,6 +27,7 @@ export class EnrichedDocumentType {
26
27
  this.#data = data;
27
28
  this.id = type.id;
28
29
  this.tenantId = type.tenantId;
30
+ this.key = type.key;
29
31
  this.label = type.label;
30
32
  this.category = category;
31
33
  }