platform/models/controlled-documents/src/migration.ts
Alexey Zinoviev c55e6f00b0
EZQMS-1145: Fixes doc import tool (#6204)
* EZQMS-1145: Fixes doc import tool
Signed-off-by: Alexey Zinoviev <alexey.zinoviev@xored.com>
2024-08-01 12:05:07 +07:00

315 lines
9.0 KiB
TypeScript

//
// Copyright @ 2022-2023 Hardcore Engineering Inc.
//
import { type Data, type Ref, TxOperations, generateId, DOMAIN_TX, getCollaborativeDoc } from '@hcengineering/core'
import {
createDefaultSpace,
createOrUpdate,
tryMigrate,
tryUpgrade,
type MigrateOperation,
type MigrationClient,
type MigrationUpgradeClient
} from '@hcengineering/model'
import core from '@hcengineering/model-core'
import tags from '@hcengineering/tags'
import {
type ChangeControl,
type DocumentCategory,
DocumentState,
documentsId,
createDocumentTemplate,
type ControlledDocument,
createChangeControl
} from '@hcengineering/controlled-documents'
import documents from './index'
async function createTemplatesSpace (tx: TxOperations): Promise<void> {
const existingSpace = await tx.findOne(documents.class.DocumentSpace, {
_id: documents.space.UnsortedTemplates
})
if (existingSpace === undefined) {
await tx.createDoc(
documents.class.DocumentSpace,
core.space.Space,
{
name: 'Unsorted templates',
description: 'Unsorted templates',
private: false,
archived: false,
autoJoin: true,
members: [],
type: documents.spaceType.DocumentSpaceType
},
documents.space.UnsortedTemplates
)
}
}
async function createQualityDocumentsSpace (tx: TxOperations): Promise<void> {
const existingSpace = await tx.findOne(documents.class.OrgSpace, {
_id: documents.space.QualityDocuments
})
if (existingSpace === undefined) {
await tx.createDoc(
documents.class.OrgSpace,
core.space.Space,
{
name: 'Quality documents',
description: "Space for organization's quality documents",
private: true,
archived: false,
members: [],
autoJoin: true,
owners: [],
type: documents.spaceType.DocumentSpaceType
},
documents.space.QualityDocuments
)
}
}
async function fixChangeControlsForDocs (tx: TxOperations): Promise<void> {
const defaultCCSpec: Data<ChangeControl> = {
description: '',
reason: '',
impact: '',
impactedDocuments: []
}
const controlledDocuments = await tx.findAll(
documents.class.ControlledDocument,
{},
{ lookup: { changeControl: documents.class.ChangeControl } }
)
for (const cdoc of controlledDocuments) {
const existingCC = await tx.findOne(documents.class.ChangeControl, { _id: cdoc.changeControl })
if (existingCC !== undefined) {
continue
}
const newCc = await tx.createDoc(
documents.class.ChangeControl,
cdoc.space,
defaultCCSpec,
cdoc.changeControl?.length > 0 ? cdoc.changeControl : undefined
)
if (cdoc.changeControl === undefined) {
await tx.update(cdoc, { changeControl: newCc })
}
}
}
async function createProductChangeControlTemplate (tx: TxOperations): Promise<void> {
const ccCategory = 'documents:category:DOC - CC' as Ref<DocumentCategory>
const productChangeControlTemplate = await tx.findOne(documents.mixin.DocumentTemplate, {
category: ccCategory
})
if (productChangeControlTemplate === undefined) {
const ccRecordId = generateId<ChangeControl>()
const ccRecord: Data<ChangeControl> = {
description: '',
reason: 'New template creation',
impact: '',
impactedDocuments: []
}
const seq = await tx.findOne(documents.class.Sequence, {
_id: documents.sequence.Templates
})
if (seq === undefined) {
return
}
const { success } = await createDocumentTemplate(
tx,
documents.class.ControlledDocument,
documents.space.QualityDocuments,
documents.mixin.DocumentTemplate,
documents.ids.NoProject,
undefined,
documents.template.ProductChangeControl as unknown as Ref<ControlledDocument>,
'CC',
{
title: 'Change Control Template for new Product Version',
abstract:
'This Template is to be used to create a Change Control document each time you want to create a new product version.',
changeControl: ccRecordId,
requests: 0,
reviewers: [],
approvers: [],
coAuthors: [],
code: `TMPL-${seq.sequence + 1}`,
seqNumber: 0,
major: 0,
minor: 1,
state: DocumentState.Effective,
sections: 0,
commentSequence: 0,
content: getCollaborativeDoc(generateId())
},
ccCategory,
undefined,
{
title: 'Section 1'
}
)
if (!success) {
return
}
await createChangeControl(tx, ccRecordId, ccRecord, documents.space.QualityDocuments)
}
}
async function createTemplateSequence (tx: TxOperations): Promise<void> {
const templateSeq = await tx.findOne(documents.class.Sequence, {
_id: documents.sequence.Templates
})
if (templateSeq === undefined) {
await tx.createDoc(
documents.class.Sequence,
documents.space.Documents,
{
attachedTo: documents.mixin.DocumentTemplate,
sequence: 0
},
documents.sequence.Templates
)
}
}
async function createDocumentCategories (tx: TxOperations): Promise<void> {
const categories: Pick<Data<DocumentCategory>, 'code' | 'title'>[] = [
{ code: 'CA', title: 'CAPA (Corrective and Preventive Action)' },
{ code: 'CC', title: 'Change Control' },
{ code: 'CE', title: 'Clinical Evaluation, Post-Market Clinical Follow-Up' },
{ code: 'CH', title: 'Complaint Handling & Support' },
{ code: 'CS', title: 'Clincial Studies' },
{ code: 'DC', title: 'Document-Control' },
{ code: 'DI', title: 'Design-Input' },
{ code: 'DT', title: 'Design Transfer' },
{ code: 'HF', title: 'Human Factors' },
{ code: 'HR', title: 'Human Resources' },
{ code: 'HW', title: 'Hardware Development' },
{ code: 'IA', title: 'Internal Audit' },
{ code: 'IM', title: 'Installation & Maintenance' },
{ code: 'IS', title: 'Infrastructure' },
{ code: 'LA', title: 'Labeling' },
{ code: 'MA', title: 'Marketing' },
{ code: 'MR', title: 'Management Review' },
{ code: 'PD', title: 'Product Development' },
{ code: 'PM', title: 'Post-Market Surveillance' },
{ code: 'PR', title: 'Production' },
{ code: 'PS', title: 'Purchase and Supplier Management' },
{ code: 'PSA', title: 'Product Safety' },
{ code: 'QM', title: 'Quality Manual' },
{ code: 'RM', title: 'Risk Management' },
{ code: 'RU', title: 'Regulatory Update' },
{ code: 'SA', title: 'Sales and Marketing' },
{ code: 'SU', title: 'Support' },
{ code: 'SW', title: 'Software Development' },
{ code: 'TF', title: 'Technical File, Product Release' },
{ code: 'VI', title: 'Vigilance' },
{ code: 'VV', title: 'Verification & Validation' },
{ code: 'CM', title: 'Client Management' }
]
await Promise.all(
categories.map((c) =>
createOrUpdate(
tx,
documents.class.DocumentCategory,
documents.space.QualityDocuments,
{ ...c, attachments: 0 },
((documents.category.DOC as string) + ' - ' + c.code) as Ref<DocumentCategory>
)
)
)
}
async function createTagCategories (tx: TxOperations): Promise<void> {
await createOrUpdate(
tx,
tags.class.TagCategory,
core.space.Workspace,
{
icon: tags.icon.Tags,
label: 'Labels',
targetClass: documents.class.Document,
tags: [],
default: true
},
documents.category.Other
)
await createOrUpdate(
tx,
tags.class.TagCategory,
core.space.Workspace,
{
icon: tags.icon.Tags,
label: 'Labels',
targetClass: documents.mixin.DocumentTemplate,
tags: [],
default: true
},
documents.category.OtherTemplate
)
}
async function migrateSpaceTypes (client: MigrationClient): Promise<void> {
await client.update(
DOMAIN_TX,
{
_class: core.class.TxCreateDoc,
objectClass: core.class.SpaceType,
'attributes.descriptor': documents.descriptor.DocumentSpaceType
},
{
$set: {
objectClass: documents.class.DocumentSpaceType
}
}
)
}
export const documentsOperation: MigrateOperation = {
async migrate (client: MigrationClient): Promise<void> {
await tryMigrate(client, documentsId, [
{
state: 'migrateSpaceTypes',
func: migrateSpaceTypes
}
])
},
async upgrade (state: Map<string, Set<string>>, client: () => Promise<MigrationUpgradeClient>): Promise<void> {
await tryUpgrade(state, client, documentsId, [
{
state: 'init-documents',
func: async (client) => {
const tx = new TxOperations(client, core.account.System)
await createDefaultSpace(client, documents.space.Documents, { name: 'Documents', description: 'Documents' })
await createQualityDocumentsSpace(tx)
await createTemplatesSpace(tx)
await createTemplateSequence(tx)
await createTagCategories(tx)
await createDocumentCategories(tx)
await fixChangeControlsForDocs(tx)
await createProductChangeControlTemplate(tx)
}
}
])
}
}