fix: proper hr members update (#10977)

Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com>
This commit is contained in:
Alexander Onnikov
2026-07-14 17:28:54 +07:00
committed by GitHub
parent ca2010fb63
commit 293bc91888
8 changed files with 187 additions and 66 deletions
+89 -12
View File
@@ -63,6 +63,44 @@ async function getOldDepartment (
return lastDepartment
}
async function getOldDepartmentParent (
currentTx: TxUpdateDoc<Department>,
control: TriggerControl
): Promise<Ref<Department> | undefined> {
const updateTxes = await control.findAll<TxUpdateDoc<Department>>(
control.ctx,
core.class.TxUpdateDoc,
{
objectId: currentTx.objectId,
objectClass: currentTx.objectClass
},
{ sort: { modifiedOn: SortingOrder.Ascending } }
)
let parent: Ref<Department> | undefined
for (const tx of updateTxes) {
if (tx._id === currentTx._id) break
if (tx.operations.parent !== undefined) {
parent = tx.operations.parent
}
}
if (parent !== undefined) return parent
const createTxes = await control.findAll<TxCreateDoc<Department>>(
control.ctx,
core.class.TxCreateDoc,
{
objectId: currentTx.objectId,
objectClass: currentTx.objectClass
},
{ sort: { modifiedOn: SortingOrder.Ascending } }
)
return createTxes[0]?.attributes.parent
}
async function buildHierarchy (_id: Ref<Department>, control: TriggerControl): Promise<Department[]> {
const res: Department[] = []
const ancestors = new Map<Ref<Department>, Ref<Department>>()
@@ -82,7 +120,7 @@ async function buildHierarchy (_id: Ref<Department>, control: TriggerControl): P
}
}
function exlude (first: Ref<Department>[], second: Ref<Department>[]): Ref<Department>[] {
function exclude (first: Ref<Department>[], second: Ref<Department>[]): Ref<Department>[] {
const set = new Set(first)
const res: Ref<Department>[] = []
for (const department of second) {
@@ -96,16 +134,18 @@ function exlude (first: Ref<Department>[], second: Ref<Department>[]): Ref<Depar
function getTxes (
factory: TxFactory,
employees: Ref<Employee>[],
added: Ref<Department>[],
added: Department[],
removed?: Ref<Department>[]
): Tx[] {
const pushTxes = added
.map((dep) =>
employees.map((emp) =>
factory.createTxUpdateDoc(hr.class.Department, core.space.Workspace, dep, {
$push: { members: emp }
})
)
employees
.filter((emp) => !dep.members.includes(emp))
.map((emp) =>
factory.createTxUpdateDoc(hr.class.Department, core.space.Workspace, dep._id, {
$push: { members: emp }
})
)
)
.flat()
if (removed === undefined) return pushTxes
@@ -146,22 +186,58 @@ export async function OnDepartmentStaff (txes: Tx[], control: TriggerControl): P
)
)
}
continue
}
const push = (await buildHierarchy(departmentId, control)).map((p) => p._id)
const push = await buildHierarchy(departmentId, control)
if (lastDepartment === undefined) {
result.push(...getTxes(control.txFactory, [employee], push))
} else {
let removed = (await buildHierarchy(lastDepartment, control)).map((p) => p._id)
const added = exlude(removed, push)
removed = exlude(push, removed)
result.push(...getTxes(control.txFactory, [employee], added, removed))
const removedDepartments = await buildHierarchy(lastDepartment, control)
const removed = removedDepartments.map((p) => p._id)
const pushIds = push.map((p) => p._id)
const added = push.filter((p) => !removed.includes(p._id))
const removedIds = exclude(pushIds, removed)
result.push(...getTxes(control.txFactory, [employee], added, removedIds))
}
}
}
return result
}
/**
* @public
*/
export async function OnDepartmentUpdate (txes: Tx[], control: TriggerControl): Promise<Tx[]> {
const result: Tx[] = []
for (const tx of txes) {
const ctx = tx as TxUpdateDoc<Department>
if (ctx.operations.parent === undefined) continue
const department = await control.findAll(control.ctx, hr.class.Department, { _id: ctx.objectId })
const currentDepartment = department[0]
if (currentDepartment === undefined) continue
const members = currentDepartment.members
if (members.length === 0) continue
const oldParent = await getOldDepartmentParent(ctx, control)
if (oldParent === ctx.operations.parent) continue
const newParent = currentDepartment.parent
const oldHierarchy = oldParent !== undefined ? await buildHierarchy(oldParent, control) : []
const newHierarchy = newParent !== undefined ? await buildHierarchy(newParent, control) : []
const oldHierarchyIds = oldHierarchy.map((p) => p._id)
const newHierarchyIds = newHierarchy.map((p) => p._id)
const added = newHierarchy.filter((p) => !oldHierarchyIds.includes(p._id))
const removed = oldHierarchy.filter((p) => !newHierarchyIds.includes(p._id)).map((p) => p._id)
result.push(...getTxes(control.txFactory, members, added, removed))
}
return result
}
/**
* @public
*/
@@ -438,6 +514,7 @@ export default async () => ({
OnRequestUpdate,
OnRequestRemove,
OnDepartmentStaff,
OnDepartmentUpdate,
OnDepartmentRemove,
OnEmployeeDeactivate,
OnPublicHolidayCreate
+1
View File
@@ -31,6 +31,7 @@ export default plugin(serverHrId, {
OnEmployee: '' as Resource<TriggerFunc>,
OnEmployeeDeactivate: '' as Resource<TriggerFunc>,
OnDepartmentStaff: '' as Resource<TriggerFunc>,
OnDepartmentUpdate: '' as Resource<TriggerFunc>,
OnDepartmentRemove: '' as Resource<TriggerFunc>,
OnRequestCreate: '' as Resource<TriggerFunc>,
OnRequestUpdate: '' as Resource<TriggerFunc>,