Re_Backend/docs/STEP3_APPROVER_ANALYSIS.md

10 KiB

Step 3 (Department Lead Approval) - User Addition Flow Analysis

Overview

This document analyzes how Step 3 approvers (Department Lead) are added to the dealer claim workflow, covering both frontend and backend implementation.


Backend Implementation

1. Request Creation Flow (dealerClaim.service.ts)

Entry Point: createClaimRequest()

  • Location: Re_Backend/src/services/dealerClaim.service.ts:37
  • Parameters:
    • userId: Initiator's user ID
    • claimData: Includes optional selectedManagerEmail for user selection

Step 3 Approver Resolution Process:

Phase 1: Pre-Validation (Before Creating Records)

// Lines 67-87: Resolve Department Lead BEFORE creating workflow
let departmentLead: User | null = null;

if (claimData.selectedManagerEmail) {
  // User selected a manager from multiple options
  departmentLead = await this.userService.ensureUserExists({
    email: claimData.selectedManagerEmail,
  });
} else {
  // Search Okta using manager displayName from initiator's user record
  departmentLead = await this.resolveDepartmentLeadFromManager(initiator);
  
  // If no manager found, throw error BEFORE creating any records
  if (!departmentLead) {
    throw new Error(`No reporting manager found...`);
  }
}

Phase 2: Approval Level Creation

// Line 136: Create approval levels with pre-resolved department lead
await this.createClaimApprovalLevels(
  workflowRequest.requestId, 
  userId, 
  claimData.dealerEmail, 
  claimData.selectedManagerEmail, 
  departmentLead  // Pre-resolved to avoid re-searching
);

2. Approval Level Creation (createClaimApprovalLevels())

Location: Re_Backend/src/services/dealerClaim.service.ts:253

Step 3 Configuration:

// Lines 310-318: Step 3 definition
{
  level: 3, 
  name: 'Department Lead Approval', 
  tatHours: 72, 
  isAuto: false,
  approverType: 'department_lead' as const,
  approverId: departmentLead?.userId || null,
  approverEmail: departmentLead?.email || initiator.manager || 'deptlead@royalenfield.com',
}

Approver Resolution Logic:

// Lines 405-417: Department Lead resolution
else if (step.approverType === 'department_lead') {
  if (finalDepartmentLead) {
    approverId = finalDepartmentLead.userId;
    approverName = finalDepartmentLead.displayName || finalDepartmentLead.email || 'Department Lead';
    approverEmail = finalDepartmentLead.email;
  } else {
    // This should never happen as we validate manager before creating records
    throw new Error('Department lead not found...');
  }
}

Database Record Creation:

// Lines 432-454: Create ApprovalLevel record
await ApprovalLevel.create({
  requestId,
  levelNumber: 3,
  levelName: 'Department Lead Approval',
  approverId: approverId,  // Department Lead's userId
  approverEmail,
  approverName,
  tatHours: 72,
  status: ApprovalStatus.PENDING,  // Will be activated when Step 2 is approved
  isFinalApprover: false,
  // ... other fields
});

3. Department Lead Resolution Methods

Method 1: resolveDepartmentLeadFromManager() (Primary)

  • Location: Re_Backend/src/services/dealerClaim.service.ts:622
  • Flow:
    1. Get manager displayName from initiator's User record
    2. Search Okta directory by displayName using userService.searchOktaByDisplayName()
    3. If 0 matches: Return null (fallback to legacy method)
    4. If 1 match: Create user in DB if needed, return User object
    5. If multiple matches: Throw error with MULTIPLE_MANAGERS_FOUND code and list of managers

Method 2: resolveDepartmentLead() (Fallback/Legacy)

  • Location: Re_Backend/src/services/dealerClaim.service.ts:699
  • Priority Order:
    1. User with MANAGEMENT role in same department
    2. User with designation containing "Lead"/"Head"/"Manager" in same department
    3. User matching initiator.manager email field
    4. Any user in same department (excluding initiator)
    5. Any user with "Department Lead" designation (across all departments)
    6. Any user with MANAGEMENT role (across all departments)
    7. Any user with ADMIN role (across all departments)

4. Participant Creation

Location: Re_Backend/src/services/dealerClaim.service.ts:463

  • Department Lead is automatically added as a participant when approval levels are created
  • Participant type: APPROVER
  • Allows department lead to view, comment, and approve the request

Frontend Implementation

1. Request Creation (ClaimManagementWizard.tsx)

Location: Re_Figma_Code/src/dealer-claim/components/request-creation/ClaimManagementWizard.tsx

Current Implementation:

  • No UI for selecting Step 3 approver during creation
  • Step 3 approver is automatically resolved by backend based on:
    • Initiator's manager field
    • Department hierarchy
    • Role-based lookup

Form Data Structure:

// Lines 61-75: Form data structure
const [formData, setFormData] = useState({
  activityName: '',
  activityType: '',
  dealerCode: '',
  // ... other fields
  // Note: No selectedManagerEmail field in wizard
});

Submission:

// Lines 152-216: handleSubmit()
const claimData = {
  ...formData,
  templateType: 'claim-management',
  // selectedManagerEmail is NOT included in current wizard
  // Backend will auto-resolve department lead
};

2. Request Detail View (RequestDetail.tsx)

Location: Re_Figma_Code/src/dealer-claim/pages/RequestDetail.tsx

Step 3 Approver Detection:

// Lines 147-173: Finding Step 3 approver
const step3Level = approvalFlow.find((level: any) => 
  (level.step || level.levelNumber || level.level_number) === 3
) || approvals.find((level: any) => 
  (level.levelNumber || level.level_number) === 3
);

const deptLeadUserId = step3Level?.approverId || step3Level?.approver_id || step3Level?.approver?.userId;
const deptLeadEmail = (step3Level?.approverEmail || '').toLowerCase().trim();

// User is department lead if they match Step 3 approver
const isDeptLead = (deptLeadUserId && deptLeadUserId === currentUserId) || 
                   (deptLeadEmail && currentUserEmail && deptLeadEmail === currentUserEmail);

Add Approver Functionality:

  • Lines 203-217, 609, 621, 688, 701, 711: References to handleAddApprover and AddApproverModal
  • Note: This appears to be generic approver addition (for other workflow types), not specifically for Step 3
  • Step 3 approver is fixed and cannot be changed after request creation

3. Workflow Tab (WorkflowTab.tsx)

Location: Re_Figma_Code/src/dealer-claim/components/request-detail/WorkflowTab.tsx

Step 3 Action Button Visibility:

// Lines 1109-1126: Step 3 approval button
{step.step === 3 && (() => {
  // Find step 3 from approvalFlow to get approverEmail
  const step3Level = approvalFlow.find((l: any) => (l.step || l.levelNumber || l.level_number) === 3);
  const step3ApproverEmail = (step3Level?.approverEmail || '').toLowerCase();
  const isStep3ApproverByEmail = step3ApproverEmail && userEmail === step3ApproverEmail;
  return isStep3ApproverByEmail || isStep3Approver || isCurrentApprover;
})() && (
  <Button onClick={() => setShowIOApprovalModal(true)}>
    Approve and Organise IO
  </Button>
)}

Step 3 Approval Handler:

// Lines 535-583: handleIOApproval()
// 1. Finds Step 3 levelId from approval levels
// 2. Updates IO details (ioNumber, ioRemark)
// 3. Approves Step 3 using approveLevel() API
// 4. Moves workflow to Step 4 (auto-processed)

Key Findings

Current Flow Summary:

  1. Request Creation:

    • User creates claim request via ClaimManagementWizard
    • No UI for selecting Step 3 approver
    • Backend automatically resolves department lead using:
      • Initiator's manager displayName → Okta search
      • Fallback to legacy resolution methods
  2. Multiple Managers Scenario:

    • If Okta search returns multiple managers:
      • Backend throws MULTIPLE_MANAGERS_FOUND error
      • Error includes list of manager options
      • Frontend needs to handle this (currently not implemented in wizard)
  3. Approval Level Creation:

    • Step 3 approver is fixed at request creation
    • Stored in ApprovalLevel table with:
      • levelNumber: 3
      • approverId: Department Lead's userId
      • approverEmail: Department Lead's email
      • status: PENDING (activated when Step 2 is approved)
  4. After Request Creation:

    • Step 3 approver cannot be changed via UI
    • Generic AddApproverModal exists but is not used for Step 3
    • Step 3 approver is determined by backend logic only

Limitations:

  1. No User Selection During Creation:

    • Wizard doesn't allow user to select/override Step 3 approver
    • If multiple managers found, error handling not implemented in frontend
  2. No Post-Creation Modification:

    • No UI to change Step 3 approver after request is created
    • Would require backend API to update ApprovalLevel.approverId
  3. Fixed Resolution Logic:

    • Department lead resolution is hardcoded in backend
    • No configuration or override mechanism

Potential Enhancement Areas

  1. Frontend: Add manager selection UI in wizard when multiple managers found
  2. Frontend: Add "Change Approver" option for Step 3 (if allowed by business rules)
  3. Backend: Add API endpoint to update Step 3 approver after request creation
  4. Backend: Add configuration for department lead resolution rules
  5. Both: Handle MULTIPLE_MANAGERS_FOUND error gracefully in frontend

Backend:

  • Re_Backend/src/services/dealerClaim.service.ts - Main service
  • Re_Backend/src/controllers/dealerClaim.controller.ts - API endpoints
  • Re_Backend/src/services/user.service.ts - User/Okta integration
  • Re_Backend/src/models/ApprovalLevel.ts - Database model

Frontend:

  • Re_Figma_Code/src/dealer-claim/components/request-creation/ClaimManagementWizard.tsx - Request creation
  • Re_Figma_Code/src/dealer-claim/pages/RequestDetail.tsx - Request detail view
  • Re_Figma_Code/src/dealer-claim/components/request-detail/WorkflowTab.tsx - Workflow display
  • Re_Figma_Code/src/dealer-claim/components/request-detail/modals/DeptLeadIOApprovalModal.tsx - Step 3 approval modal

Documentation:

  • Re_Backend/docs/CLAIM_MANAGEMENT_APPROVER_MAPPING.md - Approver mapping rules