From 3303c213ce995dcd61e2fee2e4dcc972f29d865f Mon Sep 17 00:00:00 2001 From: Denis Bykhov Date: Wed, 17 Sep 2025 09:50:04 +0500 Subject: [PATCH] Fix processes mixin work (#9876) Signed-off-by: Denis Bykhov --- models/server-process/src/index.ts | 2 +- .../process-resources/src/functions.ts | 61 ++++++++++++++++--- server-plugins/process-resources/src/utils.ts | 32 ++++++---- 3 files changed, 75 insertions(+), 20 deletions(-) diff --git a/models/server-process/src/index.ts b/models/server-process/src/index.ts index 3e74c4a094..9cc3d90c7b 100644 --- a/models/server-process/src/index.ts +++ b/models/server-process/src/index.ts @@ -269,7 +269,7 @@ export function createModel (builder: Builder): void { builder.createDoc(serverCore.class.Trigger, core.space.Model, { trigger: serverProcess.trigger.OnCardUpdate, txMatch: { - _class: core.class.TxUpdateDoc, + _class: { $in: [core.class.TxUpdateDoc, core.class.TxMixin] }, objectClass: cardPlugin.class.Card } }) diff --git a/server-plugins/process-resources/src/functions.ts b/server-plugins/process-resources/src/functions.ts index e0a1f0c500..83e9fd1fc9 100644 --- a/server-plugins/process-resources/src/functions.ts +++ b/server-plugins/process-resources/src/functions.ts @@ -14,7 +14,19 @@ // import cardPlugin, { Card, MasterTag, Tag } from '@hcengineering/card' -import core, { Association, Data, Doc, generateId, matchQuery, Ref, Relation, Tx } from '@hcengineering/core' +import core, { + Association, + checkMixinKey, + Data, + Doc, + generateId, + getObjectValue, + matchQuery, + Ref, + Relation, + splitMixinUpdate, + Tx +} from '@hcengineering/core' import process, { Execution, ExecutionContext, @@ -74,7 +86,9 @@ export function OnCardUpdateCheck ( context: Record ): boolean { if (context.card === undefined) return false - const res = matchQuery([context.card], params, context.card._class, control.client.getHierarchy(), true) + const process = control.client.getModel().findObject(execution.process) + if (process === undefined) return false + const res = matchQuery([context.card], params, process.masterTag, control.client.getHierarchy(), true) return res.length > 0 } @@ -121,16 +135,49 @@ export async function UpdateCard ( if (Object.keys(params).length === 0) throw processError(process.error.RequiredParamsNotProvided, { params: 'ANY' }) const target = control.cache.get(execution.card) if (target === undefined) throw processError(process.error.ObjectNotFound, { _id: execution.card }) + const hierarchy = control.client.getHierarchy() + const _process = control.client.getModel().findObject(execution.process) + if (_process === undefined) throw processError(process.error.ObjectNotFound, { _id: execution.process }) const update: Record = {} const prevValue: Record = {} for (const key in params) { - prevValue[key] = target[key] + const prevKey = checkMixinKey(key, _process.masterTag, hierarchy) + prevValue[key] = getObjectValue(prevKey, target) update[key] = (params as any)[key] } - const res: Tx[] = [control.client.txFactory.createTxUpdateDoc(target._class, target.space, target._id, update)] - const rollback: Tx[] = [ - control.client.txFactory.createTxUpdateDoc(target._class, target.space, target._id, prevValue) - ] + + const res: Tx[] = [] + const rollback: Tx[] = [] + if (hierarchy.isMixin(_process.masterTag)) { + const baseClass = hierarchy.getBaseClass(target._class) + const byClass = splitMixinUpdate(control.client.getHierarchy(), update, _process.masterTag, baseClass) + for (const it of byClass) { + if (hierarchy.isMixin(it[0])) { + res.push(control.client.txFactory.createTxMixin(target._id, baseClass, target.space, it[0], it[1])) + const rollbackData: Record = {} + for (const key in it[1]) { + rollbackData[key] = prevValue[key] + } + if (Object.keys(rollbackData).length > 0) { + rollback.push( + control.client.txFactory.createTxMixin(target._id, baseClass, target.space, it[0], rollbackData) + ) + } + } else { + res.push(control.client.txFactory.createTxUpdateDoc(baseClass, target.space, target._id, it[1])) + const rollbackData: Record = {} + for (const key in it[1]) { + rollbackData[key] = prevValue[key] + } + if (Object.keys(rollbackData).length > 0) { + rollback.push(control.client.txFactory.createTxUpdateDoc(baseClass, target.space, target._id, rollbackData)) + } + } + } + } else { + res.push(control.client.txFactory.createTxUpdateDoc(target._class, target.space, target._id, update)) + rollback.push(control.client.txFactory.createTxUpdateDoc(target._class, target.space, target._id, prevValue)) + } return { txes: res, rollback, context: null } } diff --git a/server-plugins/process-resources/src/utils.ts b/server-plugins/process-resources/src/utils.ts index f1ebda3d36..9195db7e97 100644 --- a/server-plugins/process-resources/src/utils.ts +++ b/server-plugins/process-resources/src/utils.ts @@ -13,7 +13,7 @@ // limitations under the License. // -import core, { ArrOf, Doc, getObjectValue, RefTo } from '@hcengineering/core' +import core, { ArrOf, checkMixinKey, Doc, getObjectValue, RefTo } from '@hcengineering/core' import { getEmbeddedLabel, getResource } from '@hcengineering/platform' import process, { Execution, @@ -65,10 +65,18 @@ export async function getContextValue (value: any, control: ProcessControl, exec } } +function getValue (control: ProcessControl, execution: Execution, rawKey: string, card: Doc): any { + const hierarchy = control.client.getHierarchy() + const _process = control.client.getModel().findObject(execution.process) + if (_process === undefined) throw processError(process.error.ObjectNotFound, { _id: execution.process }) + const key = checkMixinKey(rawKey, _process.masterTag, hierarchy) + return getObjectValue(key, card) +} + function getAttributeValue (control: ProcessControl, execution: Execution, context: SelectedContext): any { const card = control.cache.get(execution.card) if (card !== undefined) { - const val = getObjectValue(context.key, card) + const val = getValue(control, execution, context.key, card) if (val == null) { const attr = control.client.getHierarchy().findAttribute(card._class, context.key) throw processError( @@ -111,7 +119,7 @@ async function getNestedValue ( if (card === undefined) throw processError(process.error.ObjectNotFound, { _id: execution.card }, {}, true) const attr = control.client.getHierarchy().findAttribute(card._class, context.path) if (attr === undefined) throw processError(process.error.AttributeNotExists, { key: context.path }) - const nestedValue = getObjectValue(context.path, card) + const nestedValue = getValue(control, execution, context.path, card) if (nestedValue === undefined) throw processError(process.error.EmptyAttributeContextValue, {}, { attr: attr.label }) const parentType = attr.type._class === core.class.ArrOf ? (attr.type as ArrOf).of : attr.type const targetClass = parentType._class === core.class.RefTo ? (parentType as RefTo).to : parentType._class @@ -132,8 +140,8 @@ async function getNestedValue ( const f = await getResource(funcImpl.func) const reduced = await f(target, {}, control, execution) const val = Array.isArray(reduced) - ? reduced.map((v) => getObjectValue(context.key, v)) - : getObjectValue(context.key, reduced) + ? reduced.map((v) => getValue(control, execution, context.key, v)) + : getValue(control, execution, context.key, reduced) if (val == null) { throw processError( process.error.EmptyRelatedObjectValue, @@ -145,8 +153,8 @@ async function getNestedValue ( } const val = Array.isArray(target) && target.length > 1 - ? target.map((v) => getObjectValue(context.key, v)) - : getObjectValue(context.key, target[0]) + ? target.map((v) => getValue(control, execution, context.key, v)) + : getValue(control, execution, context.key, target[0]) if (val == null) { throw processError( process.error.EmptyRelatedObjectValue, @@ -187,8 +195,8 @@ async function getRelationValue ( const f = await getResource(funcImpl.func) const reduced = await f(target, {}, control, execution) const val = Array.isArray(reduced) - ? reduced.map((v) => getObjectValue(context.key, v)) - : getObjectValue(context.key, reduced) + ? reduced.map((v) => getValue(control, execution, context.key, v)) + : getValue(control, execution, context.key, reduced) if (val == null) { throw processError( process.error.EmptyRelatedObjectValue, @@ -200,8 +208,8 @@ async function getRelationValue ( } const val = Array.isArray(target) && target.length > 1 - ? target.map((v) => getObjectValue(context.key, v)) - : getObjectValue(context.key, target[0]) + ? target.map((v) => getValue(control, execution, context.key, v)) + : getValue(control, execution, context.key, target[0]) if (val == null) { throw processError( process.error.EmptyRelatedObjectValue, @@ -269,7 +277,7 @@ async function getExecutionContextValue ( if (processContext !== undefined) { const contextVal = await control.client.findOne(processContext?._class, { _id: userContext }) if (contextVal !== undefined) { - const val = getObjectValue(context.key, contextVal) + const val = getValue(control, execution, context.key, contextVal) return val } }