rez_core 2.2.148 → 2.2.150

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rez_core",
3
- "version": "2.2.148",
3
+ "version": "2.2.150",
4
4
  "description": "",
5
5
  "author": "",
6
6
  "private": false,
@@ -1,3 +1,4 @@
1
+ import { log } from 'console';
1
2
  import {
2
3
  Controller,
3
4
  Get,
@@ -24,7 +25,10 @@ export class ViewMasterController {
24
25
  @Query('entity_type') entityType: string,
25
26
  @Query('type') type: string,
26
27
  @Res() res: Response,
28
+ @Req() req: Request & { user: any },
27
29
  ) {
30
+ const loggedInUser = req.user.userData;
31
+
28
32
  try {
29
33
  if (!entityType || !type) {
30
34
  return res.status(HttpStatus.BAD_REQUEST).json({
@@ -32,4 +32,7 @@ export class ActionEntity extends BaseEntity {
32
32
 
33
33
  @Column({ nullable: true })
34
34
  user_id: number;
35
+
36
+ @Column({ type: 'varchar', nullable: true })
37
+ assignment_type: string;
35
38
  }
@@ -189,7 +189,7 @@ export class StageMovementRepository {
189
189
  ac.code AS action_category_code,
190
190
  arm.form_id
191
191
  FROM cr_wf_action a
192
- INNER JOIN cr_wf_stage_action_mapping m ON a.id = m.action_id
192
+ LEFT JOIN cr_wf_stage_action_mapping m ON a.id = m.action_id
193
193
  LEFT JOIN cr_wf_action_category ac ON a.action_category = ac.id
194
194
  LEFT JOIN cr_wf_action_resources_mapping arm ON m.id = arm.stg_act_mapping_id
195
195
  WHERE m.stage_id = ?
@@ -341,11 +341,11 @@ export class TaskService extends EntityServiceImpl {
341
341
  body.action_id,
342
342
  );
343
343
 
344
- if (body.reason_code && body.remark) {
344
+ if (body.reason_code || body.remark) {
345
345
  await this.createSystemNote(
346
346
  {
347
- reason_code: body.reason_code,
348
- remark: body.remark,
347
+ reason_code: body.reason_code!,
348
+ remark: body.remark || '',
349
349
  mapped_entity_id: body.mapped_entity_id,
350
350
  stage_id: body.stage_id,
351
351
  action_id: body.action_id,
@@ -10,6 +10,7 @@ import { ActionDataService } from './action-data.service';
10
10
  import { TaskService } from './task.service';
11
11
  import { ACTIVITY_CATEGORIES } from '../repository/activity-log.repository';
12
12
  import { ActivityLogService } from './activity-log.service';
13
+ import { EntityModificationService } from './entity-modification.service';
13
14
 
14
15
  @Injectable()
15
16
  export class WorkflowMetaService extends EntityServiceImpl {
@@ -23,6 +24,8 @@ export class WorkflowMetaService extends EntityServiceImpl {
23
24
  private readonly taskService: TaskService,
24
25
  @Inject('ActivityLogService')
25
26
  private readonly activityLogService: ActivityLogService,
27
+ @Inject('EntityModificationService')
28
+ private readonly modificationService: EntityModificationService,
26
29
  ) {
27
30
  super();
28
31
  }
@@ -151,6 +154,18 @@ export class WorkflowMetaService extends EntityServiceImpl {
151
154
  mapped_entity_type,
152
155
  );
153
156
 
157
+ await this.taskService.createSystemNote(
158
+ {
159
+ reason_code: firstStage.reason_code,
160
+ remark: firstStage.remark,
161
+ mapped_entity_id,
162
+ stage_id: firstStage.id,
163
+ action_id: firstStage.id,
164
+ stage_group_id: stageGroup.id,
165
+ },
166
+ loggedInUser,
167
+ );
168
+
154
169
  return `Initialized workflow with first stage (Stage ID: ${firstStage.id}).`;
155
170
  }
156
171
 
@@ -257,6 +272,16 @@ export class WorkflowMetaService extends EntityServiceImpl {
257
272
  return 'No actions found for this stage.';
258
273
  }
259
274
 
275
+ // check whether first action's action_category is owner_assignment and assignment_type is AUTO_ASSIGN
276
+ const firstAction = actions[0];
277
+ let actionCategory = await this.dataSource.query(
278
+ `SELECT code FROM cr_wf_action_category WHERE id = ${Number(firstAction.action_category)}`,
279
+ );
280
+
281
+ let assignmentType = await this.dataSource.query(
282
+ `SELECT value FROM cr_list_master_items WHERE id = ${Number(firstAction.assignment_type)}`,
283
+ );
284
+
260
285
  // save in action data
261
286
  await this.actionDataService.saveActionData(
262
287
  actions,
@@ -272,5 +297,266 @@ export class WorkflowMetaService extends EntityServiceImpl {
272
297
  mapped_entity_id,
273
298
  mapped_entity_type,
274
299
  );
300
+
301
+ if (
302
+ actionCategory[0]?.code == 'OWAS' &&
303
+ assignmentType[0]?.value == 'round_robin'
304
+ ) {
305
+ console.log('Auto-assigning owner based on round-robin assignment type');
306
+ await this.assignLead(
307
+ loggedInUser,
308
+ mapped_entity_id,
309
+ mapped_entity_type,
310
+ stage_id,
311
+ actions,
312
+ );
313
+ }
314
+ }
315
+
316
+ async updateLeadOwner(entityData, loggedInUser) {
317
+ let { lead_id, lead_owner, stage_id, entity_type } = entityData;
318
+ let updatedData = {
319
+ id: lead_id,
320
+ lead_owner: lead_owner,
321
+ entity_type: entity_type,
322
+ };
323
+ entityData = updatedData;
324
+
325
+ this.modificationService.logModification(
326
+ {
327
+ entity_type: 'ENMD',
328
+ mapped_entity_type: entity_type,
329
+ mapped_entity_id: lead_id,
330
+ attribute_key: 'lead_owner',
331
+ new_value: lead_owner,
332
+ old_value: entityData.lead_owner,
333
+ remarks: entityData.remarks,
334
+ reason_code: entityData.reason_code,
335
+ stage_id: stage_id,
336
+ action_id: entityData.action_id,
337
+ },
338
+ loggedInUser,
339
+ );
340
+
341
+ const leadData: any = await this.getEntityData(
342
+ 'LEAD',
343
+ lead_id,
344
+ loggedInUser,
345
+ );
346
+
347
+ const unassignedListMasterItemData = await this.dataSource.query(
348
+ `SELECT name, id
349
+ FROM cr_list_master_items
350
+ WHERE listtype = "LEST" AND organization_id = ?
351
+ AND value IN (?, ?)`,
352
+ [loggedInUser.organization_id, 'unassigned', 'active'],
353
+ );
354
+
355
+ // Find the IDs explicitly
356
+ const unassignedId = unassignedListMasterItemData.find(
357
+ (item) => item.name.toLowerCase() === 'unassigned',
358
+ )?.id;
359
+
360
+ const activeId = unassignedListMasterItemData.find(
361
+ (item) => item.name.toLowerCase() === 'active',
362
+ )?.id;
363
+
364
+ // Use unassignedId for comparison
365
+ if (leadData?.lead_status === unassignedId) {
366
+ leadData.lead_status = activeId;
367
+ }
368
+
369
+ const result = await super.updateEntity(
370
+ {
371
+ ...entityData,
372
+ status: leadData?.lead_status,
373
+ lead_status: leadData?.lead_status,
374
+ },
375
+ loggedInUser,
376
+ );
377
+
378
+ await this.dataSource.query(
379
+ `UPDATE cr_wf_action_data SET user_id =?
380
+ WHERE mapped_entity_id=?
381
+ AND mapped_entity_type = ?
382
+ AND stage_id = ?
383
+ AND (is_current = 'Y' OR is_current IS NULL)
384
+ `,
385
+ [lead_owner, lead_id, entity_type, stage_id],
386
+ );
387
+
388
+ await this.dataSource.query(
389
+ `UPDATE cr_lead_meeting SET user_id=?
390
+ WHERE stage_id = ?
391
+ AND lead_id = ?
392
+ AND (status='scheduled' OR status='rescheduled')
393
+ `,
394
+ [lead_owner, stage_id, lead_id],
395
+ );
396
+
397
+ const taskRows = await this.dataSource.query(
398
+ `SELECT id,status FROM cr_wf_task_data
399
+ WHERE mapped_entity_id = ?
400
+ AND mapped_entity_type = ?
401
+ AND stage_id = ?`,
402
+ [lead_id, entity_type, stage_id],
403
+ );
404
+
405
+ for (const task of taskRows) {
406
+ const statusRows = await this.dataSource.query(
407
+ `SELECT value FROM cr_list_master_items
408
+ WHERE id = ? AND organization_id = ?`,
409
+ [task.status, loggedInUser.organization_id],
410
+ );
411
+
412
+ const statusName = statusRows[0]?.value?.toLowerCase() || '';
413
+ if (
414
+ ['todo', 'in_progress'].includes(statusName) ||
415
+ statusName === 'todo'
416
+ ) {
417
+ await this.dataSource.query(
418
+ `UPDATE cr_wf_task_data SET user_id = ?, task_owner = ? WHERE id = ?`,
419
+ [lead_owner, lead_owner, task.id],
420
+ );
421
+ }
422
+ }
423
+
424
+ const leadOwnerName = await this.dataSource.query(
425
+ `SELECT name FROM cr_user WHERE id = ?`,
426
+ [entityData?.lead_owner],
427
+ );
428
+
429
+ try {
430
+ const logData = {
431
+ mapped_entity_id: lead_id,
432
+ mapped_entity_type: 'LEAD',
433
+ title: 'Owner Assigned',
434
+ description: leadData?.lead_owner
435
+ ? `${leadOwnerName[0]?.name} reassigned as Lead owner.`
436
+ : `${leadOwnerName[0]?.name} assigned as Lead owner.`,
437
+ action: 'assign',
438
+ category: ACTIVITY_CATEGORIES.ASSIGN,
439
+ appcode: loggedInUser.appcode,
440
+ };
441
+
442
+ await this.activityLogService.logActivity(logData, loggedInUser);
443
+ } catch (error) {
444
+ console.error(
445
+ 'Failed to log activity for meeting:',
446
+ error?.message || error,
447
+ );
448
+ // Logging should not block main flow
449
+ }
450
+ return result;
451
+ }
452
+
453
+ async assignLead(
454
+ loggedInUser: UserData,
455
+ mapped_entity_id: number,
456
+ mapped_entity_type: string,
457
+ stage_id: number,
458
+ actions: any[],
459
+ ): Promise<number> {
460
+ const { organization_id, level_id, level_type } = loggedInUser;
461
+
462
+ // 1) Get eligible owners (distinct + stable ordering)
463
+ const owners: Array<{ id: number }> = await this.dataSource.query(
464
+ `
465
+ SELECT DISTINCT u.id
466
+ FROM cr_user u
467
+ JOIN cr_user_role_mapping urm ON u.id = urm.user_id
468
+ JOIN cr_role r ON urm.role_id = r.id
469
+ JOIN cr_module_access ma ON ma.role_code = r.code
470
+ WHERE urm.organization_id = ?
471
+ AND urm.level_id = ?
472
+ AND urm.level_type = ?
473
+ AND urm.appcode = 'CRM'
474
+ AND ma.appcode = 'CRM'
475
+ AND ma.module_code = 'lead_crm_sch'
476
+ AND ma.access_flag = 1
477
+ AND ma.action_type = 'LEAD_OWNER'
478
+ ORDER BY u.id ASC
479
+ `,
480
+ [organization_id, Number(level_id), level_type],
481
+ );
482
+
483
+ if (!owners?.length) throw new Error('No eligible users found');
484
+ const userIds = owners.map((o) => Number(o.id)); // normalize to numbers
485
+
486
+ // 2) Find the last assigned *eligible* owner (use IN (...))
487
+ const placeholders = userIds.map(() => '?').join(',');
488
+ const lastRow: Array<{ lead_owner: number }> = await this.dataSource.query(
489
+ `
490
+ SELECT lead_owner
491
+ FROM crm_lead
492
+ WHERE organization_id = ?
493
+ AND level_id = ?
494
+ AND level_type = ?
495
+ AND lead_owner IN (${placeholders})
496
+ ORDER BY created_date DESC
497
+ LIMIT 1
498
+ `,
499
+ [organization_id, Number(level_id), level_type, ...userIds],
500
+ );
501
+
502
+ const lastAssigned = lastRow.length ? Number(lastRow[0].lead_owner) : null;
503
+
504
+ // 3) Compute next user in round-robin
505
+ const lastIdx = lastAssigned != null ? userIds.indexOf(lastAssigned) : -1;
506
+ const nextIdx = (lastIdx + 1) % userIds.length;
507
+ const nextUser = userIds[nextIdx];
508
+
509
+ //4) Update lead owner in the lead table
510
+ await this.dataSource.query(
511
+ `
512
+ UPDATE crm_lead
513
+ SET lead_owner = ?
514
+ WHERE organization_id = ?
515
+ AND level_id = ?
516
+ AND level_type = ?
517
+ AND lead_owner IS NULL
518
+ ORDER BY created_date ASC
519
+ LIMIT 1
520
+ `,
521
+ [nextUser, organization_id, Number(level_id), level_type],
522
+ );
523
+
524
+ console.log(`Assigning lead to user ID: ${nextUser}`);
525
+
526
+ const firstAction = actions[0];
527
+
528
+ // move task
529
+ await this.taskService.moveTask(loggedInUser, {
530
+ mapped_entity_type,
531
+ mapped_entity_id,
532
+ stage_id,
533
+ action_id: firstAction.id,
534
+ });
535
+
536
+ // if it has only one action then move next stage
537
+ if (actions.length == 1) {
538
+ console.log(
539
+ 'Only one action present and it is owner assignment. Moving to next stage.',
540
+ );
541
+ await this.moveToNextStage(
542
+ mapped_entity_type,
543
+ mapped_entity_id,
544
+ loggedInUser,
545
+ );
546
+ }
547
+
548
+ // update lead owner status
549
+ await this.updateLeadOwner(
550
+ {
551
+ lead_id: mapped_entity_id,
552
+ lead_owner: nextUser,
553
+ stage_id: stage_id,
554
+ entity_type: mapped_entity_type,
555
+ action_id: firstAction.id,
556
+ },
557
+ loggedInUser,
558
+ );
559
+
560
+ return nextUser;
275
561
  }
276
562
  }