| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common';
- import { PlantationNodeData, Worker, Task } from './plantation-node-data.interface';
- import { TreeNode, TreeService } from 'src/services/tree.service';
- @Injectable()
- export class PlantationTreeService extends TreeService<PlantationNodeData> {
- private workerIndex: Map<string, Worker> = new Map();
- // plantation-tree.service.ts (constructor only)
- constructor() {
- super({
- id: 'root',
- data: {
- id: 'root',
- name: 'Plantation Root',
- type: 'ROOT', // <-- ensure ROOT here
- status: 'ACTIVE',
- workers: [],
- },
- });
- }
- /** 🔍 Find a node by name (case-insensitive) */
- findNodeByName(name: string): TreeNode<PlantationNodeData> | undefined {
- let found: TreeNode<PlantationNodeData> | undefined;
- this.traverseTree(node => {
- if (node.data.name.toLowerCase() === name.toLowerCase()) found = node;
- });
- return found;
- }
- /** 👷 Assign worker to ZONE or BLOCK (not TREE), propagates upward */
- assignWorker(nodeId: string, worker: Worker): TreeNode<PlantationNodeData> {
- // 1️⃣ Check uniqueness globally
- if (this.workerIndex.has(worker.id)) {
- throw new BadRequestException(`Worker ID ${worker.id} already exists`);
- }
- const node = this.root.first(n => n.model.id === nodeId);
- if (!node) throw new NotFoundException(`Node ${nodeId} not found`);
- if (!node.model.data.workers) node.model.data.workers = [];
- node.model.data.workers.push(worker);
- // 2️⃣ Propagate upward to ancestors
- let current = node.parent;
- while (current) {
- if (!current.model.data.workers) current.model.data.workers = [];
- const parentHasWorker = current.model.data.workers.some(w => w.id === worker.id);
- if (!parentHasWorker) current.model.data.workers.push(worker);
- current = current.parent;
- }
- // 3️⃣ Update global index
- this.workerIndex.set(worker.id, worker);
- return node.model;
- }
- /** 🌳 Assign tree to an existing worker (must exist in ancestor chain) */
- assignTreeToWorker(treeId: string, workerId: string): TreeNode<PlantationNodeData> {
- const treeNode = this.root.first(n => n.model.id === treeId);
- if (!treeNode) throw new NotFoundException(`Tree node ${treeId} not found`);
- if (treeNode.model.data.type !== 'TREE') {
- throw new BadRequestException(`Only TREE nodes can be assigned to workers`);
- }
- // Search upward for worker existence
- let current = treeNode.parent;
- let foundWorker: Worker | null = null;
- while (current) {
- const worker = current.model.data.workers?.find(w => w.id === workerId);
- if (worker) {
- foundWorker = worker;
- break;
- }
- current = current.parent;
- }
- if (!foundWorker) {
- throw new NotFoundException(`Worker ${workerId} not found in ancestor hierarchy`);
- }
- // Assign minimal worker data to tree node
- treeNode.model.data.workers = [
- {
- id: foundWorker.id,
- name: foundWorker.name,
- personCode: foundWorker.personCode,
- role: foundWorker.role,
- DOB: foundWorker.DOB,
- age: foundWorker.age,
- nationality: foundWorker.nationality,
- },
- ];
- return treeNode.model;
- }
- /** 📋 Assign a task to a worker under a node */
- assignTaskToWorkerById(workerId: string, task: Task): Worker {
- const worker = this.workerIndex.get(workerId);
- if (!worker) throw new NotFoundException(`Worker ${workerId} not found`);
- if (!worker.assignedTasks) worker.assignedTasks = [];
- worker.assignedTasks.push(task);
- return worker;
- }
- /** 🌲 Recursively collect all workers under a node (aggregated view) */
- getWorkersUnderNode(nodeId: string): Worker[] {
- const start = this.root.first(n => n.model.id === nodeId);
- if (!start) throw new NotFoundException(`Node ${nodeId} not found`);
- const workers: Worker[] = [];
- start.walk(n => {
- if (n.model.data.workers) workers.push(...n.model.data.workers);
- return true;
- });
- return workers;
- }
- /** ✅ Update node metadata safely */
- updateMetadata(nodeId: string, metadata: Record<string, any>) {
- const node = this.root.first(n => n.model.id === nodeId);
- if (!node) throw new NotFoundException(`Node ${nodeId} not found`);
- node.model.data.metadata = { ...node.model.data.metadata, ...metadata };
- return node.model;
- }
- getWorkerById(workerId: string): Worker {
- const worker = this.workerIndex.get(workerId);
- if (!worker) throw new NotFoundException(`Worker ${workerId} not found`);
- return worker;
- }
- }
|