Approve requests (#10486)

Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
Denis Bykhov
2026-02-04 16:51:02 +05:00
committed by GitHub
parent 2bdf82d608
commit 773fee05be
45 changed files with 1496 additions and 60 deletions
@@ -29,11 +29,13 @@ import core, {
Relation,
splitMixinUpdate,
Tx,
TxCreateDoc,
TxProcessor,
Type,
TypeNumber
} from '@hcengineering/core'
import process, {
ApproveRequest,
Execution,
ExecutionContext,
ExecutionStatus,
@@ -392,6 +394,124 @@ export async function RunSubProcess (
return { txes: res, rollback, context: resultContext }
}
export async function RequestApproval (
params: MethodParams<ApproveRequest>,
execution: Execution,
control: ProcessControl,
results: UserResult[] | undefined
): Promise<ExecuteResult> {
if (params.title === undefined) throw processError(process.error.RequiredParamsNotProvided, { params: 'title' })
if (params.user === undefined) throw processError(process.error.RequiredParamsNotProvided, { params: 'user' })
const group = generateId()
const res: TxCreateDoc<ApproveRequest>[] = []
const rollback: Tx[] = []
for (const user of Array.isArray(params.user) ? params.user : [params.user]) {
const id = generateId<ApproveRequest>()
const tx = control.client.txFactory.createTxCreateDoc(
process.class.ApproveRequest,
time.space.ToDos,
{
attachedTo: execution.card,
attachedToClass: cardPlugin.class.Card,
collection: 'todos',
workslots: 0,
execution: execution._id,
title: params.title,
user,
description: params.description ?? '',
dueDate: params.dueDate,
priority: params.priority ?? ToDoPriority.NoPriority,
visibility: 'public',
card: execution.card,
doneOn: null,
rank: '',
withRollback: params.withRollback ?? false,
results,
group
},
id
)
res.push(tx)
rollback.push(control.client.txFactory.createTxRemoveDoc(process.class.ApproveRequest, time.space.ToDos, id))
}
return {
txes: res,
rollback,
context: [
{
_id: group,
value: res.map((tx) => TxProcessor.createDoc2Doc(tx, true))
}
]
}
}
export async function ApproveRequestApproved (
control: ProcessControl,
execution: Execution,
params: Record<string, any>,
context: Record<string, any>
): Promise<boolean> {
if (params._id === undefined) return false
const todo = await control.client.findAll(process.class.ApproveRequest, { group: params._id })
return todo.every((t) => t.approved === true)
}
export async function ApproveRequestRejected (
control: ProcessControl,
execution: Execution,
params: Record<string, any>,
context: Record<string, any>
): Promise<boolean> {
if (params._id === undefined) return false
const todo = await control.client.findAll(process.class.ApproveRequest, { group: params._id })
return todo.some((t) => t.approved === false)
}
export async function LockCard (
params: MethodParams<Card>,
execution: Execution,
control: ProcessControl
): Promise<ExecuteResult> {
const res: Tx[] = []
const rollback: Tx[] = []
const tx = control.client.txFactory.createTxUpdateDoc(cardPlugin.class.Card, execution.space, execution.card, {
readonly: true
})
res.push(tx)
rollback.push(
control.client.txFactory.createTxUpdateDoc(cardPlugin.class.Card, execution.space, execution.card, {
readonly: false
})
)
return { txes: res, rollback, context: [] }
}
export async function LockSection (
params: MethodParams<Card>,
execution: Execution,
control: ProcessControl
): Promise<ExecuteResult> {
if (params._id === undefined) throw processError(process.error.RequiredParamsNotProvided, { params: '_id' })
const res: Tx[] = []
const rollback: Tx[] = []
const card = await control.client.findOne(cardPlugin.class.Card, { _id: execution.card })
if (card === undefined) throw processError(process.error.ObjectNotFound, { _id: execution.card })
const readonlySections = card.readonlySections ?? []
const target = params._id as Ref<MasterTag>
readonlySections.push(target)
const tx = control.client.txFactory.createTxUpdateDoc(cardPlugin.class.Card, execution.space, execution.card, {
readonlySections
})
res.push(tx)
rollback.push(
control.client.txFactory.createTxUpdateDoc(cardPlugin.class.Card, execution.space, execution.card, {
$pull: { readonlySections: target }
})
)
return { txes: res, rollback, context: [] }
}
export async function CreateToDo (
params: MethodParams<ProcessToDo>,
execution: Execution,
+50 -3
View File
@@ -39,7 +39,8 @@ import process, {
Step,
Transition,
isUpdateTx,
ProcessCustomEvent
ProcessCustomEvent,
ApproveRequest
} from '@hcengineering/process'
import { QueueTopic, TriggerControl } from '@hcengineering/server-core'
import { ProcessMessage } from '@hcengineering/server-process'
@@ -97,7 +98,12 @@ import {
CheckSubProcessMatch,
CheckTime,
FieldChangedCheck,
EventCheck
EventCheck,
RequestApproval,
ApproveRequestApproved,
ApproveRequestRejected,
LockCard,
LockSection
} from './functions'
import { ToDoCancellRollback, ToDoCloseRollback } from './rollback'
@@ -139,6 +145,42 @@ export async function OnProcessToDoClose (txes: Tx[], control: TriggerControl):
},
control
)
if (todo._class === process.class.ApproveRequest) {
const request = todo as ApproveRequest
if (request.approved === true) {
await putEventToQueue(
{
event: process.trigger.OnApproveRequestApproved,
execution: todo.execution,
createdOn: tx.modifiedOn,
context: {
todo
}
},
control
)
} else if (request.approved === false) {
// remove all other approve requests for this execution
const toRemove = await control.findAll(control.ctx, process.class.ApproveRequest, {
group: request.group,
doneOn: null
})
for (const req of toRemove) {
res.push(control.txFactory.createTxRemoveDoc(req._class, req.space, req._id))
}
await putEventToQueue(
{
event: process.trigger.OnApproveRequestRejected,
execution: todo.execution,
createdOn: tx.modifiedOn,
context: {
todo
}
},
control
)
}
}
}
return res
}
@@ -476,7 +518,12 @@ export default async () => ({
CheckSubProcessesDone,
CheckSubProcessMatch,
CheckTime,
EventCheck
EventCheck,
RequestApproval,
ApproveRequestApproved,
ApproveRequestRejected,
LockCard,
LockSection
},
transform: {
CurrentDate,