mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-13 05:07:43 +02:00
Rollback and custom events preparation (#10298)
Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
@@ -48,18 +48,6 @@ export function defineMethods (builder: Builder): void {
|
||||
process.method.CreateToDo
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
process.class.Trigger,
|
||||
core.space.Model,
|
||||
{
|
||||
label: process.string.OnExecutionStart,
|
||||
icon: process.icon.Process,
|
||||
init: true,
|
||||
requiredParams: []
|
||||
},
|
||||
process.trigger.OnExecutionStart
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
process.class.Method,
|
||||
core.space.Model,
|
||||
|
||||
@@ -16,6 +16,7 @@ import core, {
|
||||
AccountRole,
|
||||
type Class,
|
||||
DOMAIN_MODEL,
|
||||
DOMAIN_TRANSIENT,
|
||||
type Doc,
|
||||
type Domain,
|
||||
type Rank,
|
||||
@@ -48,6 +49,7 @@ import {
|
||||
type CheckFunc,
|
||||
type ContextId,
|
||||
type CreatedContext,
|
||||
type ProcessCustomEvent,
|
||||
type Execution,
|
||||
type ExecutionContext,
|
||||
type ExecutionError,
|
||||
@@ -65,16 +67,17 @@ import {
|
||||
type Transition,
|
||||
type Trigger,
|
||||
type UpdateCriteriaComponent,
|
||||
processId
|
||||
processId,
|
||||
type EventButton
|
||||
} from '@hcengineering/process'
|
||||
import time from '@hcengineering/time'
|
||||
import { type AnyComponent } from '@hcengineering/ui'
|
||||
import { type AttributeCategory } from '@hcengineering/view'
|
||||
import { defineMethods } from './actions'
|
||||
import { defineTriggers } from './triggers'
|
||||
import { defineFunctions } from './functions'
|
||||
import process from './plugin'
|
||||
import { definePermissions } from './permission'
|
||||
import process from './plugin'
|
||||
import { defineTriggers } from './triggers'
|
||||
|
||||
const DOMAIN_PROCESS = 'process' as Domain
|
||||
const DOMAIN_PROCESS_LOG = 'process-log' as Domain
|
||||
@@ -234,6 +237,30 @@ export class TState extends TDoc implements State {
|
||||
rank!: Rank
|
||||
}
|
||||
|
||||
@Model(process.class.ProcessCustomEvent, core.class.Doc, DOMAIN_TRANSIENT)
|
||||
export class TProcessCustomEvent extends TDoc implements ProcessCustomEvent {
|
||||
eventType!: string
|
||||
|
||||
@Prop(TypeRef(process.class.Execution), process.string.Execution)
|
||||
execution!: Ref<Execution>
|
||||
|
||||
@Prop(TypeRef(card.class.Card), card.string.Card)
|
||||
card!: Ref<Card>
|
||||
}
|
||||
|
||||
@Model(process.class.EventButton, core.class.Doc, DOMAIN_PROCESS)
|
||||
export class TEventButton extends TDoc implements EventButton {
|
||||
title!: string
|
||||
|
||||
eventType!: string
|
||||
|
||||
@Prop(TypeRef(process.class.Execution), process.string.Execution)
|
||||
execution!: Ref<Execution>
|
||||
|
||||
@Prop(TypeRef(card.class.Card), card.string.Card)
|
||||
card!: Ref<Card>
|
||||
}
|
||||
|
||||
@Model(process.class.ProcessFunction, core.class.Doc, DOMAIN_MODEL)
|
||||
export class TProcessFunction extends TDoc implements ProcessFunction {
|
||||
of!: Ref<Class<Doc<Space>>>
|
||||
@@ -269,7 +296,9 @@ export function createModel (builder: Builder): void {
|
||||
TTransition,
|
||||
TTrigger,
|
||||
TExecutionLog,
|
||||
TUpdateCriteriaComponent
|
||||
TUpdateCriteriaComponent,
|
||||
TProcessCustomEvent,
|
||||
TEventButton
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
|
||||
@@ -32,6 +32,18 @@ export function defineTriggers (builder: Builder): void {
|
||||
process.trigger.OnToDoClose
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
process.class.Trigger,
|
||||
core.space.Model,
|
||||
{
|
||||
label: process.string.OnExecutionStart,
|
||||
icon: process.icon.Process,
|
||||
init: true,
|
||||
requiredParams: []
|
||||
},
|
||||
process.trigger.OnExecutionStart
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
process.class.Trigger,
|
||||
core.space.Model,
|
||||
@@ -80,6 +92,24 @@ export function defineTriggers (builder: Builder): void {
|
||||
process.trigger.WhenFieldChanges
|
||||
)
|
||||
|
||||
// builder.createDoc(
|
||||
// process.class.Trigger,
|
||||
// core.space.Model,
|
||||
// {
|
||||
// label: process.string.OnEvent,
|
||||
// icon: process.icon.OnEvent,
|
||||
// editor: process.component.OnEventEditor,
|
||||
// presenter: process.component.OnEventPresenter,
|
||||
// requiredParams: [
|
||||
// 'eventType'
|
||||
// ],
|
||||
// checkFunction: process.triggerCheck.OnEventCheck,
|
||||
// init: false,
|
||||
// auto: false
|
||||
// },
|
||||
// process.trigger.OnEvent
|
||||
// )
|
||||
|
||||
builder.createDoc(
|
||||
process.class.Trigger,
|
||||
core.space.Model,
|
||||
|
||||
@@ -61,14 +61,25 @@ export function createModel (builder: Builder): void {
|
||||
})
|
||||
|
||||
builder.mixin(process.trigger.OnCardUpdate, process.class.Trigger, serverProcess.mixin.TriggerImpl, {
|
||||
preventRollback: true,
|
||||
serverCheckFunc: serverProcess.func.MatchCardCheck
|
||||
})
|
||||
|
||||
builder.mixin(process.trigger.WhenFieldChanges, process.class.Trigger, serverProcess.mixin.TriggerImpl, {
|
||||
preventRollback: true,
|
||||
serverCheckFunc: serverProcess.func.FieldChangedCheck
|
||||
})
|
||||
|
||||
builder.mixin(process.trigger.OnExecutionStart, process.class.Trigger, serverProcess.mixin.TriggerImpl, {
|
||||
preventRollback: true
|
||||
})
|
||||
|
||||
// builder.mixin(process.trigger.OnEvent, process.class.Trigger, serverProcess.mixin.TriggerImpl, {
|
||||
// serverCheckFunc: serverProcess.func.EventCheck
|
||||
// })
|
||||
|
||||
builder.mixin(process.trigger.OnTime, process.class.Trigger, serverProcess.mixin.TriggerImpl, {
|
||||
preventRollback: true,
|
||||
serverCheckFunc: serverProcess.func.CheckTime
|
||||
})
|
||||
|
||||
@@ -290,6 +301,22 @@ export function createModel (builder: Builder): void {
|
||||
isAsync: true
|
||||
})
|
||||
|
||||
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
|
||||
trigger: serverProcess.trigger.OnCustomEvent,
|
||||
txMatch: {
|
||||
_class: core.class.TxCreateDoc,
|
||||
objectClass: process.class.ProcessCustomEvent
|
||||
}
|
||||
})
|
||||
|
||||
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
|
||||
trigger: serverProcess.trigger.OnExecutionRemove,
|
||||
txMatch: {
|
||||
_class: core.class.TxRemoveDoc,
|
||||
objectClass: process.class.Execution
|
||||
}
|
||||
})
|
||||
|
||||
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
|
||||
trigger: serverProcess.trigger.OnProcessToDoClose,
|
||||
txMatch: {
|
||||
|
||||
@@ -27,5 +27,6 @@ loadMetadata(process.icon, {
|
||||
Start: `${icons}#start`,
|
||||
WhenCardMatches: `${icons}#card-matches`,
|
||||
WhenFieldChanges: `${icons}#field-change`,
|
||||
Time: `${icons}#time`
|
||||
Time: `${icons}#time`,
|
||||
OnEvent: `${icons}#start`
|
||||
})
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
import { getCurrentEmployee } from '@hcengineering/contact'
|
||||
import { getEmbeddedLabel } from '@hcengineering/platform'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { Execution, ExecutionStatus, ProcessToDo } from '@hcengineering/process'
|
||||
import { EventButton, Execution, ExecutionStatus, ProcessToDo } from '@hcengineering/process'
|
||||
import { Button } from '@hcengineering/ui'
|
||||
import process from '../plugin'
|
||||
|
||||
@@ -25,6 +25,18 @@
|
||||
|
||||
let docs: Execution[] = []
|
||||
let todos: ProcessToDo[] = []
|
||||
let actions: EventButton[] = []
|
||||
|
||||
const buttonsQuery = createQuery()
|
||||
$: buttonsQuery.query(
|
||||
process.class.EventButton,
|
||||
{
|
||||
card: card._id
|
||||
},
|
||||
(res) => {
|
||||
actions = res
|
||||
}
|
||||
)
|
||||
|
||||
const executionQuery = createQuery()
|
||||
$: executionQuery.query(
|
||||
@@ -60,8 +72,41 @@
|
||||
doneOn: new Date().getTime()
|
||||
})
|
||||
}
|
||||
|
||||
async function performAction (action: EventButton) {
|
||||
await client.createDoc(process.class.ProcessCustomEvent, action.space, {
|
||||
execution: action.execution,
|
||||
eventType: action.eventType,
|
||||
card: card._id
|
||||
})
|
||||
}
|
||||
|
||||
async function performRollback (execution: Execution) {
|
||||
await client.createDoc(process.class.ProcessCustomEvent, execution.space, {
|
||||
execution: execution._id,
|
||||
eventType: 'rollback',
|
||||
card: card._id
|
||||
})
|
||||
}
|
||||
|
||||
function getExecutionLabel (execution: Execution): string {
|
||||
const pr = client.getModel().findObject(execution.process)
|
||||
if (pr !== undefined) {
|
||||
return `${pr.name}: `
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
$: rollbacks = docs.filter((d) => d.rollback.length > 0)
|
||||
</script>
|
||||
|
||||
{#each todos as todo (todo._id)}
|
||||
<Button kind={'primary'} label={getEmbeddedLabel(todo.title)} on:click={() => checkTodo(todo)} />
|
||||
{/each}
|
||||
{#each actions as action (action._id)}
|
||||
<Button kind={'primary'} label={getEmbeddedLabel(action.title)} on:click={() => performAction(action)} />
|
||||
{/each}
|
||||
{#each rollbacks as rollback}
|
||||
{getExecutionLabel(rollback)}
|
||||
<Button kind={'dangerous'} label={process.string.Rollback} on:click={() => performRollback(rollback)} />
|
||||
{/each}
|
||||
|
||||
@@ -85,7 +85,8 @@ import {
|
||||
matchCardCheck,
|
||||
subProcessesDoneCheck,
|
||||
fieldChangesCheck,
|
||||
subProcessMatchCheck
|
||||
subProcessMatchCheck,
|
||||
eventCheck
|
||||
} from './utils'
|
||||
import FieldChangesEditor from './components/settings/FieldChangesEditor.svelte'
|
||||
|
||||
@@ -173,7 +174,8 @@ export default async (): Promise<Resources> => ({
|
||||
SubProcessesDoneCheck: subProcessesDoneCheck,
|
||||
SubProcessMatchCheck: subProcessMatchCheck,
|
||||
ToDo: todoTranstionCheck,
|
||||
Time: timeTransitionCheck
|
||||
Time: timeTransitionCheck,
|
||||
OnEventCheck: eventCheck
|
||||
},
|
||||
function: {
|
||||
ShowDoneQuery: showDoneQuery,
|
||||
|
||||
@@ -68,6 +68,8 @@ export default mergeIds(processId, process, {
|
||||
CardUpdateEditor: '' as AnyComponent,
|
||||
CardUpdatePresenter: '' as AnyComponent,
|
||||
FieldChangesEditor: '' as AnyComponent,
|
||||
OnEventEditor: '' as AnyComponent,
|
||||
OnEventPresenter: '' as AnyComponent,
|
||||
ToDoSettingPresenter: '' as AnyComponent,
|
||||
TimeEditor: '' as AnyComponent,
|
||||
TimePresenter: '' as AnyComponent,
|
||||
@@ -174,6 +176,7 @@ export default mergeIds(processId, process, {
|
||||
WaitUntil: '' as IntlString,
|
||||
WhenCardMatches: '' as IntlString,
|
||||
WhenFieldChanges: '' as IntlString,
|
||||
OnEvent: '' as IntlString,
|
||||
Result: '' as IntlString,
|
||||
RequestResult: '' as IntlString,
|
||||
NoResultRequired: '' as IntlString,
|
||||
|
||||
@@ -617,6 +617,16 @@ export function timeTransitionCheck (
|
||||
return params.value <= Date.now()
|
||||
}
|
||||
|
||||
export function eventCheck (
|
||||
client: Client,
|
||||
execution: Execution,
|
||||
params: Record<string, any>,
|
||||
context: Record<string, any>
|
||||
): boolean {
|
||||
if (params.eventType === undefined) return false
|
||||
return context.eventType === params.eventType
|
||||
}
|
||||
|
||||
export function matchCardCheck (
|
||||
client: Client,
|
||||
execution: Execution,
|
||||
|
||||
@@ -158,6 +158,19 @@ export interface UserResult {
|
||||
type: Type<any>
|
||||
}
|
||||
|
||||
export interface ProcessCustomEvent extends Doc {
|
||||
eventType: string
|
||||
execution: Ref<Execution>
|
||||
card: Ref<Card>
|
||||
}
|
||||
|
||||
export interface EventButton extends Doc {
|
||||
title: string
|
||||
eventType: string
|
||||
execution: Ref<Execution>
|
||||
card: Ref<Card>
|
||||
}
|
||||
|
||||
export interface Method<T extends Doc> extends Doc {
|
||||
label: IntlString
|
||||
objectClass: Ref<Class<T>>
|
||||
@@ -206,12 +219,17 @@ export default plugin(processId, {
|
||||
ProcessFunction: '' as Ref<Class<ProcessFunction>>,
|
||||
Transition: '' as Ref<Class<Transition>>,
|
||||
Trigger: '' as Ref<Class<Trigger>>,
|
||||
ProcessCustomEvent: '' as Ref<Class<ProcessCustomEvent>>,
|
||||
ExecutionLog: '' as Ref<Class<ExecutionLog>>,
|
||||
UpdateCriteriaComponent: '' as Ref<Class<UpdateCriteriaComponent>>
|
||||
UpdateCriteriaComponent: '' as Ref<Class<UpdateCriteriaComponent>>,
|
||||
EventButton: '' as Ref<Class<EventButton>>
|
||||
},
|
||||
method: {
|
||||
RunSubProcess: '' as Ref<Method<Process>>,
|
||||
CreateAction: '' as Ref<Method<EventButton>>,
|
||||
CancellAction: '' as Ref<Method<EventButton>>,
|
||||
CreateToDo: '' as Ref<Method<ProcessToDo>>,
|
||||
CloseToDo: '' as Ref<Method<ProcessToDo>>,
|
||||
UpdateCard: '' as Ref<Method<Card>>,
|
||||
CreateCard: '' as Ref<Method<Card>>,
|
||||
AddRelation: '' as Ref<Method<Association>>,
|
||||
@@ -226,7 +244,8 @@ export default plugin(processId, {
|
||||
OnToDoRemove: '' as Ref<Trigger>,
|
||||
OnExecutionStart: '' as Ref<Trigger>,
|
||||
OnExecutionContinue: '' as Ref<Trigger>,
|
||||
OnTime: '' as Ref<Trigger>
|
||||
OnTime: '' as Ref<Trigger>,
|
||||
OnEvent: '' as Ref<Trigger>
|
||||
},
|
||||
triggerCheck: {
|
||||
ToDo: '' as Resource<CheckFunc>,
|
||||
@@ -234,7 +253,8 @@ export default plugin(processId, {
|
||||
FieldChangedCheck: '' as Resource<CheckFunc>,
|
||||
SubProcessesDoneCheck: '' as Resource<CheckFunc>,
|
||||
SubProcessMatchCheck: '' as Resource<CheckFunc>,
|
||||
Time: '' as Resource<CheckFunc>
|
||||
Time: '' as Resource<CheckFunc>,
|
||||
OnEventCheck: '' as Resource<CheckFunc>
|
||||
},
|
||||
string: {
|
||||
Method: '' as IntlString,
|
||||
@@ -276,7 +296,8 @@ export default plugin(processId, {
|
||||
WaitSubprocesses: '' as Asset,
|
||||
ToDoRemove: '' as Asset,
|
||||
Start: '' as Asset,
|
||||
Time: '' as Asset
|
||||
Time: '' as Asset,
|
||||
OnEvent: '' as Asset
|
||||
},
|
||||
function: {
|
||||
FirstMatchValue: '' as Ref<ProcessFunction>,
|
||||
|
||||
@@ -145,6 +145,16 @@ export function MatchCardCheck (
|
||||
return res.length > 0
|
||||
}
|
||||
|
||||
export function EventCheck (
|
||||
control: ProcessControl,
|
||||
execution: Execution,
|
||||
params: Record<string, any>,
|
||||
context: Record<string, any>
|
||||
): boolean {
|
||||
if (params.eventType === undefined) return false
|
||||
return context.eventType === params.eventType
|
||||
}
|
||||
|
||||
export function FieldChangedCheck (
|
||||
control: ProcessControl,
|
||||
execution: Execution,
|
||||
@@ -299,23 +309,23 @@ export async function AddTag (
|
||||
): Promise<ExecuteResult> {
|
||||
const { _id, props } = params
|
||||
if (_id === undefined) throw processError(process.error.RequiredParamsNotProvided, { params: '_id' })
|
||||
const tagId = _id as Ref<Tag>
|
||||
const res: Tx[] = []
|
||||
const _process = control.client.getModel().findObject(execution.process)
|
||||
if (_process === undefined) throw processError(process.error.ObjectNotFound, { _id: execution.process })
|
||||
const tx = control.client.txFactory.createTxMixin(
|
||||
execution.card,
|
||||
_process.masterTag,
|
||||
core.space.Workspace,
|
||||
_id as Ref<Tag>,
|
||||
props
|
||||
)
|
||||
const tx = control.client.txFactory.createTxMixin(execution.card, _process.masterTag, execution.space, tagId, props)
|
||||
res.push(tx)
|
||||
const card = control.cache.get(execution.card)
|
||||
const cardWithMixin =
|
||||
card !== undefined ? TxProcessor.updateMixin4Doc(control.client.getHierarchy().clone(card), tx) : undefined
|
||||
|
||||
const rollback = control.client.txFactory.createTxUpdateDoc(_process.masterTag, execution.space, execution.card, {
|
||||
$unset: { [tagId]: true }
|
||||
})
|
||||
|
||||
return {
|
||||
txes: res,
|
||||
rollback: undefined,
|
||||
rollback: [rollback],
|
||||
context: [
|
||||
{
|
||||
_id: execution.card,
|
||||
@@ -337,6 +347,7 @@ export async function RunSubProcess (
|
||||
if (target === undefined) throw processError(process.error.ObjectNotFound, { _id: processId })
|
||||
const res: Tx[] = []
|
||||
const resultContext: SuccessExecutionContext[] = []
|
||||
const rollback: Tx[] = []
|
||||
for (const _card of Array.isArray(card) ? card : [card]) {
|
||||
if (target.parallelExecutionForbidden === true) {
|
||||
const currentExecution = await control.client.findAll(process.class.Execution, {
|
||||
@@ -370,13 +381,15 @@ export async function RunSubProcess (
|
||||
_id
|
||||
)
|
||||
|
||||
rollback.push(control.client.txFactory.createTxRemoveDoc(process.class.Execution, core.space.Workspace, _id))
|
||||
|
||||
res.push(tx)
|
||||
resultContext.push({
|
||||
_id,
|
||||
value: TxProcessor.createDoc2Doc(tx, true)
|
||||
})
|
||||
}
|
||||
return { txes: res, rollback: undefined, context: resultContext }
|
||||
return { txes: res, rollback, context: resultContext }
|
||||
}
|
||||
|
||||
export async function CreateToDo (
|
||||
|
||||
@@ -38,7 +38,8 @@ import process, {
|
||||
State,
|
||||
Step,
|
||||
Transition,
|
||||
isUpdateTx
|
||||
isUpdateTx,
|
||||
ProcessCustomEvent
|
||||
} from '@hcengineering/process'
|
||||
import { QueueTopic, TriggerControl } from '@hcengineering/server-core'
|
||||
import { ProcessMessage } from '@hcengineering/server-process'
|
||||
@@ -95,7 +96,8 @@ import {
|
||||
CheckSubProcessesDone,
|
||||
CheckSubProcessMatch,
|
||||
CheckTime,
|
||||
FieldChangedCheck
|
||||
FieldChangedCheck,
|
||||
EventCheck
|
||||
} from './functions'
|
||||
import { ToDoCancellRollback, ToDoCloseRollback } from './rollback'
|
||||
|
||||
@@ -141,6 +143,31 @@ export async function OnProcessToDoClose (txes: Tx[], control: TriggerControl):
|
||||
return res
|
||||
}
|
||||
|
||||
export async function OnCustomEvent (txes: Tx[], control: TriggerControl): Promise<Tx[]> {
|
||||
for (const tx of txes) {
|
||||
if (tx._class !== core.class.TxCreateDoc) continue
|
||||
const createTx = tx as TxCreateDoc<ProcessCustomEvent>
|
||||
if (!control.hierarchy.isDerived(createTx.objectClass, process.class.ProcessCustomEvent)) continue
|
||||
const customEvent = TxProcessor.createDoc2Doc(createTx)
|
||||
const card = await control.findAll(control.ctx, cardPlugin.class.Card, { _id: customEvent.card }, { limit: 1 })
|
||||
if (card.length === 0) continue
|
||||
await putEventToQueue(
|
||||
{
|
||||
event: process.trigger.OnEvent,
|
||||
execution: customEvent.execution,
|
||||
createdOn: tx.modifiedOn,
|
||||
card: customEvent.card,
|
||||
context: {
|
||||
eventType: customEvent.eventType,
|
||||
card
|
||||
}
|
||||
},
|
||||
control
|
||||
)
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
export async function OnExecutionCreate (txes: Tx[], control: TriggerControl): Promise<Tx[]> {
|
||||
for (const tx of txes) {
|
||||
if (tx._class !== core.class.TxCreateDoc) continue
|
||||
@@ -249,6 +276,23 @@ export async function OnStateRemove (txes: Tx[], control: TriggerControl): Promi
|
||||
return res
|
||||
}
|
||||
|
||||
export async function OnExecutionRemove (txes: Tx[], control: TriggerControl): Promise<Tx[]> {
|
||||
const res: Tx[] = []
|
||||
for (const tx of txes) {
|
||||
if (tx._class !== core.class.TxRemoveDoc) continue
|
||||
const cudTx = tx as TxRemoveDoc<Execution>
|
||||
if (!control.hierarchy.isDerived(cudTx.objectClass, process.class.Execution)) continue
|
||||
const todos = await control.findAll(control.ctx, process.class.ProcessToDo, {
|
||||
execution: cudTx.objectId,
|
||||
doneOn: null
|
||||
})
|
||||
for (const todo of todos) {
|
||||
res.push(control.txFactory.createTxRemoveDoc(todo._class, todo.space, todo._id))
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
export async function OnTransition (txes: Tx[], control: TriggerControl): Promise<Tx[]> {
|
||||
const res: Tx[] = []
|
||||
for (const tx of txes) {
|
||||
@@ -400,7 +444,8 @@ export default async () => ({
|
||||
MatchCardCheck,
|
||||
CheckSubProcessesDone,
|
||||
CheckSubProcessMatch,
|
||||
CheckTime
|
||||
CheckTime,
|
||||
EventCheck
|
||||
},
|
||||
transform: {
|
||||
CurrentDate,
|
||||
@@ -454,6 +499,8 @@ export default async () => ({
|
||||
OnExecutionCreate,
|
||||
OnProcessToDoClose,
|
||||
OnProcessToDoRemove,
|
||||
OnExecutionContinue
|
||||
OnExecutionContinue,
|
||||
OnCustomEvent,
|
||||
OnExecutionRemove
|
||||
}
|
||||
})
|
||||
|
||||
@@ -60,7 +60,8 @@ export default plugin(serverProcessId, {
|
||||
FieldChangedCheck: '' as Resource<CheckFunc>,
|
||||
CheckSubProcessesDone: '' as Resource<CheckFunc>,
|
||||
CheckSubProcessMatch: '' as Resource<CheckFunc>,
|
||||
CheckTime: '' as Resource<CheckFunc>
|
||||
CheckTime: '' as Resource<CheckFunc>,
|
||||
EventCheck: '' as Resource<CheckFunc>
|
||||
},
|
||||
transform: {
|
||||
FirstValue: '' as Resource<TransformFunc>,
|
||||
@@ -110,6 +111,8 @@ export default plugin(serverProcessId, {
|
||||
OnExecutionCreate: '' as Resource<TriggerFunc>,
|
||||
OnProcessToDoClose: '' as Resource<TriggerFunc>,
|
||||
OnProcessToDoRemove: '' as Resource<TriggerFunc>,
|
||||
OnExecutionContinue: '' as Resource<TriggerFunc>
|
||||
OnExecutionContinue: '' as Resource<TriggerFunc>,
|
||||
OnCustomEvent: '' as Resource<TriggerFunc>,
|
||||
OnExecutionRemove: '' as Resource<TriggerFunc>
|
||||
}
|
||||
})
|
||||
|
||||
@@ -83,7 +83,7 @@ export async function messageHandler (record: ProcessMessage, ws: WorkspaceUuid,
|
||||
ctx.info('Processing event', { event: record.event, ws, record })
|
||||
if (record.execution !== undefined) {
|
||||
const execution = await control.client.findOne(process.class.Execution, { _id: record.execution })
|
||||
if (execution !== undefined && isActiveExecution(execution, record.event)) {
|
||||
if (execution !== undefined) {
|
||||
await processExecution(control, record, execution)
|
||||
}
|
||||
} else if (record.card !== undefined) {
|
||||
@@ -140,9 +140,7 @@ async function processCardExecutions (control: ProcessControl, record: ProcessMe
|
||||
currentState: { $in: Array.from(states) }
|
||||
})
|
||||
for (const execution of executions) {
|
||||
if (isActiveExecution(execution, record.event)) {
|
||||
await processExecution(control, record, execution)
|
||||
}
|
||||
await processExecution(control, record, execution)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,26 +261,36 @@ async function executeResultSet (
|
||||
}
|
||||
|
||||
async function processExecution (control: ProcessControl, record: ProcessMessage, execution: Execution): Promise<void> {
|
||||
await checkToDoResult(control, record, execution)
|
||||
const transition = await findTransitions(control, record, execution)
|
||||
if (transition !== undefined) {
|
||||
await execute(execution, transition, control)
|
||||
} else {
|
||||
if (record.event === process.trigger.OnToDoRemove) {
|
||||
const rollbackResult = await checkRollback(control, record, execution)
|
||||
if (rollbackResult) return
|
||||
if (isActiveExecution(execution, record.event)) {
|
||||
await checkToDoResult(control, record, execution)
|
||||
const transition = await findTransitions(control, record, execution)
|
||||
if (transition !== undefined) {
|
||||
await execute(execution, transition, control)
|
||||
return
|
||||
} else {
|
||||
control.ctx.info('No transition found for event', {
|
||||
event: record.event,
|
||||
execution: execution._id,
|
||||
state: execution.currentState
|
||||
})
|
||||
}
|
||||
control.ctx.info('No transition found for event', {
|
||||
event: record.event,
|
||||
execution: execution._id,
|
||||
state: execution.currentState
|
||||
})
|
||||
}
|
||||
if (isRollback(record)) {
|
||||
await rollback(control, record, execution)
|
||||
}
|
||||
}
|
||||
|
||||
async function checkRollback (control: ProcessControl, record: ProcessMessage, execution: Execution): Promise<boolean> {
|
||||
const todo = record.context.todo as ProcessToDo
|
||||
if (!todo?.withRollback) return false
|
||||
function isRollback (record: ProcessMessage): boolean {
|
||||
if (record.event === process.trigger.OnEvent && record.context.eventType === 'rollback') {
|
||||
return true
|
||||
}
|
||||
if (record.event === process.trigger.OnToDoRemove && record.context.todo?.withRollback === true) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
async function rollback (control: ProcessControl, record: ProcessMessage, execution: Execution): Promise<void> {
|
||||
const rollbackTxes = execution.rollback.pop() ?? []
|
||||
for (const tx of rollbackTxes) {
|
||||
const timeout = setTimeout(() => {
|
||||
@@ -294,7 +302,6 @@ async function checkRollback (control: ProcessControl, record: ProcessMessage, e
|
||||
await control.client.update(execution, {
|
||||
rollback: execution.rollback
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
async function getTriggerRollback (triggger: TriggerImpl, control: ProcessControl): Promise<Tx | undefined> {
|
||||
@@ -334,6 +341,7 @@ async function executeTransition (
|
||||
_transition: Transition,
|
||||
control: ProcessControl
|
||||
): Promise<void> {
|
||||
let nested = false
|
||||
let transition: Transition | undefined = _transition
|
||||
while (transition !== undefined) {
|
||||
let deep = control.cache.get(execution._id + 'transition') ?? 0
|
||||
@@ -391,7 +399,7 @@ async function executeTransition (
|
||||
if (isError(actionResult)) {
|
||||
errors.push(actionResult)
|
||||
} else {
|
||||
if (actionResult.rollback !== undefined) {
|
||||
if (actionResult.rollback !== undefined && actionResult.rollback.length > 0) {
|
||||
rollback.push(...actionResult.rollback)
|
||||
}
|
||||
res.push(...actionResult.txes)
|
||||
@@ -419,7 +427,14 @@ async function executeTransition (
|
||||
}
|
||||
}
|
||||
if (!disableRollback) {
|
||||
execution.rollback.push(rollback)
|
||||
if (nested) {
|
||||
const last = execution.rollback.pop() ?? []
|
||||
execution.rollback.push([...last, ...rollback])
|
||||
} else {
|
||||
execution.rollback.push(rollback)
|
||||
}
|
||||
} else {
|
||||
execution.rollback = []
|
||||
}
|
||||
const executionUpdate = getDiffUpdate(execution, {
|
||||
currentState: state._id,
|
||||
@@ -452,6 +467,7 @@ async function executeTransition (
|
||||
}
|
||||
TxProcessor.applyUpdate(execution, executionUpdate)
|
||||
transition = await checkNext(control, execution, context)
|
||||
nested = true
|
||||
if (transition === undefined) {
|
||||
await setNextTimers(control, execution)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user