EQMS-1560: fix & migrate duplicate active review/approval requests in qms

Signed-off-by: Victor Ilyushchenko <alt13ri@gmail.com>
This commit is contained in:
Victor Ilyushchenko 2025-05-22 15:37:40 +03:00
parent 8452c1f650
commit 17fef533e4
No known key found for this signature in database
GPG Key ID: CEC5BF115E7283DF
2 changed files with 74 additions and 2 deletions

View File

@ -16,8 +16,10 @@ import {
type ControlledDocument,
createChangeControl,
createDocumentTemplate,
type DocumentApprovalRequest,
type DocumentCategory,
type DocumentMeta,
type DocumentReviewRequest,
documentsId,
DocumentState,
type ProjectMeta
@ -54,6 +56,8 @@ import tags from '@hcengineering/tags'
import { compareDocumentVersions } from '@hcengineering/controlled-documents/src'
import { makeRank } from '@hcengineering/rank'
import documents, { DOMAIN_DOCUMENTS } from './index'
import { DOMAIN_REQUEST } from '@hcengineering/model-request'
import { RequestStatus } from '@hcengineering/request'
async function createTemplatesSpace (tx: TxOperations): Promise<void> {
const existingSpace = await tx.findOne(documents.class.DocumentSpace, {
@ -467,6 +471,50 @@ async function migrateInvalidDocumentState (client: MigrationClient): Promise<vo
await client.bulk(DOMAIN_DOCUMENTS, operations)
}
async function migrateCancelDuplicateActiveRequests (client: MigrationClient): Promise<void> {
const reviews = await client.find<DocumentReviewRequest>(DOMAIN_REQUEST, {
_class: documents.class.DocumentReviewRequest,
status: RequestStatus.Active
})
const approvals = await client.find<DocumentApprovalRequest>(DOMAIN_REQUEST, {
_class: documents.class.DocumentApprovalRequest,
status: RequestStatus.Active
})
const requests = [...reviews, ...approvals]
const requestsByDoc = new Map<Ref<ControlledDocument>, (DocumentApprovalRequest | DocumentReviewRequest)[]>()
for (const request of requests) {
const attachedTo = request.attachedTo as Ref<ControlledDocument>
const entry = requestsByDoc.get(attachedTo)
if (entry === undefined) {
requestsByDoc.set(attachedTo, [request])
} else {
entry.push(request)
}
}
const requestsToCancel: (DocumentApprovalRequest | DocumentReviewRequest)[] = []
for (const entry of requestsByDoc.entries()) {
const requests = entry[1]
if (requests.length < 2) continue
requestsToCancel.push(...requests.slice(1))
}
const operations: {
filter: MigrationDocumentQuery<DocumentApprovalRequest | DocumentReviewRequest>
update: MigrateUpdate<DocumentApprovalRequest | DocumentReviewRequest>
}[] = []
for (const doc of requestsToCancel) {
operations.push({
filter: { _id: doc._id },
update: { status: RequestStatus.Cancelled }
})
}
await client.bulk(DOMAIN_REQUEST, operations)
}
export const documentsOperation: MigrateOperation = {
async migrate (client: MigrationClient, mode): Promise<void> {
await tryMigrate(mode, client, documentsId, [
@ -500,6 +548,10 @@ export const documentsOperation: MigrateOperation = {
{
state: 'migrateInvalidDocumentState',
func: migrateInvalidDocumentState
},
{
state: 'migrateCancelDuplicateActiveRequests',
func: migrateCancelDuplicateActiveRequests
}
])
},

View File

@ -280,8 +280,22 @@ async function createRequest<T extends Doc> (
approveTx: Tx,
rejectedTx?: Tx,
areAllApprovesRequired = true
): Promise<Ref<Request>> {
return await client.addCollection(reqClass, space, attachedTo, attachedToClass, 'requests', {
): Promise<Ref<Request> | undefined> {
const sequentialRequestClassGroup = [documents.class.DocumentReviewRequest, documents.class.DocumentApprovalRequest]
const ops = client.apply('create-qms-doc-request')
if (sequentialRequestClassGroup.includes(reqClass)) {
for (const _class of sequentialRequestClassGroup) {
ops.notMatch(_class, {
attachedTo,
attachedToClass,
status: RequestStatus.Active
})
}
}
const ref = await ops.addCollection(reqClass, space, attachedTo, attachedToClass, 'requests', {
requested: users,
approved: [],
tx: approveTx,
@ -289,6 +303,12 @@ async function createRequest<T extends Doc> (
status: RequestStatus.Active,
requiredApprovesCount: areAllApprovesRequired ? users.length : 1
})
const commit = await ops.commit()
if (commit.result) {
return ref
}
}
async function getActiveRequest (