schema enhanced and made nececaasry model changes
This commit is contained in:
parent
6b68364785
commit
92169b0fba
@ -241,58 +241,63 @@ erDiagram
|
||||
%% DEALER ENTITY (POST-ONBOARDING)
|
||||
%% ============================================
|
||||
DEALERS {
|
||||
uuid dealer_id PK
|
||||
uuid application_id FK
|
||||
string dealer_code UK
|
||||
string dealer_name
|
||||
string constitution_type
|
||||
text registered_address
|
||||
string gst_number
|
||||
string pan_number
|
||||
uuid id PK
|
||||
uuid applicationId FK
|
||||
uuid dealerCodeId FK
|
||||
string legalName
|
||||
string businessName
|
||||
string constitutionType
|
||||
text registeredAddress
|
||||
string gstNumber
|
||||
string panNumber
|
||||
string status
|
||||
date activation_date
|
||||
date last_working_day
|
||||
boolean portal_access_active
|
||||
timestamp onboardedAt
|
||||
timestamp created_at
|
||||
timestamp updated_at
|
||||
}
|
||||
|
||||
%% ============================================
|
||||
%% DEALER APPLICATION
|
||||
%% ONBOARDING APPLICATION (ONBOARDING PHASE)
|
||||
%% ============================================
|
||||
APPLICATIONS {
|
||||
uuid application_id PK
|
||||
string registration_number UK
|
||||
string applicant_name
|
||||
uuid id PK
|
||||
string applicationId UK
|
||||
uuid opportunityId FK
|
||||
string applicantName
|
||||
string email UK
|
||||
string mobile_number
|
||||
integer age
|
||||
string country
|
||||
string phone
|
||||
string businessType
|
||||
string preferredLocation
|
||||
string city
|
||||
string state
|
||||
string district
|
||||
string pincode
|
||||
string interested_city
|
||||
string company_name
|
||||
string education_qualification
|
||||
boolean owns_re_bike
|
||||
boolean is_existing_dealer
|
||||
text address
|
||||
integer experienceYears
|
||||
string investmentCapacity
|
||||
integer age
|
||||
string education
|
||||
string companyName
|
||||
string source
|
||||
string existingDealer
|
||||
string ownRoyalEnfield
|
||||
string royalEnfieldModel
|
||||
text description
|
||||
string preferred_location
|
||||
string application_status
|
||||
string opportunity_status
|
||||
boolean is_shortlisted
|
||||
boolean dd_lead_shortlisted
|
||||
uuid assigned_to FK
|
||||
uuid zone_id FK
|
||||
uuid region_id FK
|
||||
uuid area_id FK
|
||||
uuid assigned_dd_zm FK
|
||||
uuid assigned_rbm FK
|
||||
text address
|
||||
string pincode
|
||||
string locationType
|
||||
string currentStage
|
||||
string overallStatus
|
||||
integer progressPercentage
|
||||
boolean isShortlisted
|
||||
boolean ddLeadShortlisted
|
||||
decimal score
|
||||
uuid assignedTo FK
|
||||
uuid architectureAssignedTo FK
|
||||
string architectureStatus
|
||||
uuid submittedBy FK
|
||||
uuid zoneId FK
|
||||
uuid regionId FK
|
||||
uuid areaId FK
|
||||
json documents
|
||||
json timeline
|
||||
integer progress_percentage
|
||||
timestamp submitted_at
|
||||
timestamp created_at
|
||||
timestamp updated_at
|
||||
}
|
||||
@ -660,7 +665,7 @@ erDiagram
|
||||
%% OUTLET MANAGEMENT
|
||||
%% ============================================
|
||||
OUTLETS {
|
||||
uuid outlet_id PK
|
||||
uuid id PK
|
||||
string code UK
|
||||
string name
|
||||
string type
|
||||
@ -671,8 +676,8 @@ erDiagram
|
||||
decimal latitude
|
||||
decimal longitude
|
||||
string status
|
||||
date established_date
|
||||
uuid dealer_id FK
|
||||
date establishedDate
|
||||
uuid dealerId FK
|
||||
string region
|
||||
string zone
|
||||
timestamp created_at
|
||||
@ -699,49 +704,62 @@ erDiagram
|
||||
}
|
||||
|
||||
%% ============================================
|
||||
%% DEALER SELF-SERVICE (SECTION 12)
|
||||
%% DEALER SERVICE APPLICATIONS (POST-ONBOARDING)
|
||||
%% Also known as Self-Service or Lifecycle Requests
|
||||
%% ============================================
|
||||
DEALER_RESIGNATIONS {
|
||||
uuid resignation_id PK
|
||||
uuid dealer_id FK
|
||||
string outlet_code
|
||||
date last_operational_date_sales
|
||||
date last_operational_date_service
|
||||
date proposed_lwd
|
||||
string reason_type
|
||||
text reason_description
|
||||
RESIGNATIONS {
|
||||
uuid id PK
|
||||
string resignationId UK
|
||||
uuid outletId FK
|
||||
uuid dealerId FK
|
||||
string resignationType
|
||||
date lastOperationalDateSales
|
||||
date lastOperationalDateServices
|
||||
text reason
|
||||
text additionalInfo
|
||||
string currentStage
|
||||
string status
|
||||
boolean is_withdrawn
|
||||
timestamp submitted_at
|
||||
integer progressPercentage
|
||||
timestamp submittedOn
|
||||
json documents
|
||||
json timeline
|
||||
text rejectionReason
|
||||
json departmentalClearances
|
||||
timestamp created_at
|
||||
timestamp updated_at
|
||||
}
|
||||
|
||||
DEALER_RELOCATIONS {
|
||||
uuid relocation_id PK
|
||||
uuid dealer_id FK
|
||||
string current_location_json
|
||||
string proposed_location_json
|
||||
decimal distance_km
|
||||
string property_type
|
||||
date expected_relocation_date
|
||||
RELOCATION_REQUESTS {
|
||||
uuid id PK
|
||||
string requestId UK
|
||||
uuid outletId FK
|
||||
uuid dealerId FK
|
||||
string relocationType
|
||||
text newAddress
|
||||
string newCity
|
||||
string newState
|
||||
text reason
|
||||
string currentStage
|
||||
string status
|
||||
timestamp submitted_at
|
||||
}
|
||||
|
||||
DEALER_CONSTITUTION_CHANGES {
|
||||
uuid constitution_change_id PK
|
||||
string request_id UK
|
||||
uuid outlet_id FK
|
||||
uuid dealer_id FK
|
||||
string change_type
|
||||
text description
|
||||
string current_stage
|
||||
string status
|
||||
integer progress_percentage
|
||||
integer progressPercentage
|
||||
json documents
|
||||
json timeline
|
||||
timestamp created_at
|
||||
timestamp updated_at
|
||||
}
|
||||
|
||||
CONSTITUTIONAL_CHANGES {
|
||||
uuid id PK
|
||||
string requestId UK
|
||||
uuid outletId FK
|
||||
uuid dealerId FK
|
||||
string changeType
|
||||
text description
|
||||
string currentStage
|
||||
string status
|
||||
integer progressPercentage
|
||||
json documents
|
||||
json timeline
|
||||
timestamp submitted_at
|
||||
timestamp created_at
|
||||
timestamp updated_at
|
||||
}
|
||||
@ -883,17 +901,22 @@ erDiagram
|
||||
}
|
||||
|
||||
%% ============================================
|
||||
%% TERMINATION & F&F SETTLEMENT (SECTION 4.3 & 10)
|
||||
%% TERMINATION (A TYPE OF SERVICE APPLICATION)
|
||||
%% ============================================
|
||||
TERMINATION_REQUESTS {
|
||||
uuid termination_id PK
|
||||
uuid dealer_id FK
|
||||
uuid id PK
|
||||
uuid dealerId FK
|
||||
string category
|
||||
text reason
|
||||
date proposed_lwd
|
||||
date proposedLwd
|
||||
string status
|
||||
uuid initiated_by FK
|
||||
string currentStage
|
||||
uuid initiatedBy FK
|
||||
text comments
|
||||
json timeline
|
||||
json documents
|
||||
timestamp created_at
|
||||
timestamp updated_at
|
||||
}
|
||||
|
||||
TERMINATION_APPROVALS {
|
||||
@ -907,14 +930,20 @@ erDiagram
|
||||
timestamp created_at
|
||||
}
|
||||
|
||||
FNF_CASES {
|
||||
uuid fnf_id PK
|
||||
uuid dealer_id FK
|
||||
uuid source_id FK
|
||||
string source_type
|
||||
date last_working_day
|
||||
FNF_SETTLEMENTS {
|
||||
uuid id PK
|
||||
uuid resignationId FK
|
||||
uuid terminationRequestId FK
|
||||
uuid outletId FK
|
||||
uuid dealerId FK
|
||||
string status
|
||||
timestamp initiated_at
|
||||
decimal totalReceivables
|
||||
decimal totalPayables
|
||||
decimal netAmount
|
||||
date settlementDate
|
||||
json clearanceDocuments
|
||||
timestamp created_at
|
||||
timestamp updated_at
|
||||
}
|
||||
|
||||
FNF_DEPARTMENT_CLEARANCES {
|
||||
@ -1149,6 +1178,26 @@ erDiagram
|
||||
timestamp access_revoked_at
|
||||
}
|
||||
|
||||
REQUEST_PARTICIPANTS {
|
||||
uuid id PK
|
||||
uuid requestId FK
|
||||
string requestType
|
||||
uuid userId FK
|
||||
string role
|
||||
boolean isActive
|
||||
timestamp created_at
|
||||
timestamp updated_at
|
||||
}
|
||||
|
||||
%% NOTE: Polymorphic Relationships
|
||||
%% DOCUMENTS, WORK_NOTES, and REQUEST_PARTICIPANTS
|
||||
%% use 'requestType' and 'requestId' to link with:
|
||||
%% - APPLICATIONS (Onboarding)
|
||||
%% - RESIGNATIONS
|
||||
%% - RELOCATION_REQUESTS
|
||||
%% - CONSTITUTIONAL_CHANGES
|
||||
%% - TERMINATION_REQUESTS
|
||||
|
||||
%% ============================================
|
||||
%% RELATIONSHIPS
|
||||
%% ============================================
|
||||
@ -1226,16 +1275,18 @@ erDiagram
|
||||
APPLICATIONS ||--o{ DEALERS : "onboarded_as"
|
||||
DEALERS ||--o{ USERS : "has_portal_users"
|
||||
|
||||
DEALERS ||--o{ DEALER_RESIGNATIONS : "initiates"
|
||||
DEALERS ||--o{ DEALER_RELOCATIONS : "requests"
|
||||
DEALERS ||--o{ DEALER_CONSTITUTION_CHANGES : "proposes"
|
||||
DEALERS ||--o{ RESIGNATIONS : "initiates"
|
||||
DEALERS ||--o{ RELOCATION_REQUESTS : "requests"
|
||||
DEALERS ||--o{ CONSTITUTIONAL_CHANGES : "proposes"
|
||||
|
||||
DEALERS ||--o{ TERMINATION_REQUESTS : "terminated_by"
|
||||
TERMINATION_REQUESTS ||--o{ TERMINATION_APPROVALS : "requires"
|
||||
|
||||
DEALERS ||--o{ FNF_CASES : "settled_in"
|
||||
FNF_CASES ||--o{ FNF_DEPARTMENT_CLEARANCES : "requires_NOC_from"
|
||||
FNF_CASES ||--o{ FNF_SETTLEMENT_SUMMARIES : "consolidated_in"
|
||||
DEALERS ||--o{ FNF_SETTLEMENTS : "settled_in"
|
||||
RESIGNATIONS ||--o{ FNF_SETTLEMENTS : "triggers"
|
||||
TERMINATION_REQUESTS ||--o{ FNF_SETTLEMENTS : "triggers"
|
||||
FNF_SETTLEMENTS ||--o{ FNF_DEPARTMENT_CLEARANCES : "requires_NOC_from"
|
||||
FNF_SETTLEMENTS ||--o{ FNF_SETTLEMENT_SUMMARIES : "consolidated_in"
|
||||
|
||||
DEALERS ||--o{ DEALER_PORTAL_CONFIG : "governed_by"
|
||||
|
||||
@ -1271,21 +1322,29 @@ erDiagram
|
||||
|
||||
SLA_CONFIGURATIONS ||--o{ SLA_CONFIG_REMINDERS : "defines"
|
||||
SLA_CONFIGURATIONS ||--o{ SLA_CONFIG_ESCALATIONS : "defines"
|
||||
FNF_CASES ||--o{ FNF_LINE_ITEMS : "has"
|
||||
FNF_SETTLEMENTS ||--o{ FNF_LINE_ITEMS : "has"
|
||||
FNF_DEPARTMENT_CLEARANCES ||--o{ FNF_LINE_ITEMS : "details"
|
||||
USERS ||--o{ FNF_LINE_ITEMS : "added"
|
||||
USERS ||--o{ APPLICATIONS : "currently_assigned"
|
||||
|
||||
USERS ||--o{ OUTLETS : "has_outlets"
|
||||
OUTLETS ||--o{ DEALER_CONSTITUTION_CHANGES : "requests_change"
|
||||
OUTLETS ||--o{ CONSTITUTIONAL_CHANGES : "requests_change"
|
||||
OUTLETS ||--o{ RELOCATION_REQUESTS : "requests_relocation"
|
||||
OUTLETS ||--o{ RESIGNATIONS : "initiates_resignation"
|
||||
|
||||
APPLICATIONS ||--o{ FINANCE_PAYMENTS : "has_payments"
|
||||
USERS ||--o{ FINANCE_PAYMENTS : "verifies_payments"
|
||||
|
||||
DEALER_RESIGNATIONS ||--o{ EXIT_FEEDBACK : "has_feedback"
|
||||
RESIGNATIONS ||--o{ EXIT_FEEDBACK : "has_feedback"
|
||||
TERMINATION_REQUESTS ||--o{ EXIT_FEEDBACK : "has_feedback"
|
||||
USERS ||--o{ EXIT_FEEDBACK : "submitted_by"
|
||||
|
||||
SLA_TRACKING ||--o{ SLA_BREACHES : "has_breaches"
|
||||
|
||||
APPLICATIONS ||--o{ REQUEST_PARTICIPANTS : "has_participants"
|
||||
RESIGNATIONS ||--o{ REQUEST_PARTICIPANTS : "has_participants"
|
||||
TERMINATION_REQUESTS ||--o{ REQUEST_PARTICIPANTS : "has_participants"
|
||||
RELOCATION_REQUESTS ||--o{ REQUEST_PARTICIPANTS : "has_participants"
|
||||
CONSTITUTIONAL_CHANGES ||--o{ REQUEST_PARTICIPANTS : "has_participants"
|
||||
|
||||
|
||||
|
||||
@ -34,6 +34,7 @@ export const APPLICATION_STAGES = {
|
||||
DD_HEAD: 'DD Head',
|
||||
NBH: 'NBH',
|
||||
LEGAL: 'Legal',
|
||||
ARCHITECTURE: 'Architecture',
|
||||
FINANCE: 'Finance',
|
||||
LEVEL_1_APPROVED: 'Level 1 Approved',
|
||||
LEVEL_2_APPROVED: 'Level 2 Approved',
|
||||
@ -84,6 +85,24 @@ export const APPLICATION_STATUS = {
|
||||
DISQUALIFIED: 'Disqualified'
|
||||
} as const;
|
||||
|
||||
// Termination Stages
|
||||
export const TERMINATION_STAGES = {
|
||||
SUBMITTED: 'Submitted',
|
||||
RBM_REVIEW: 'RBM Review',
|
||||
ZBH_REVIEW: 'ZBH Review',
|
||||
DD_LEAD_REVIEW: 'DD Lead Review',
|
||||
LEGAL_VERIFICATION: 'Legal Verification',
|
||||
NBH_EVALUATION: 'NBH Evaluation',
|
||||
SCN_ISSUED: 'Show Cause Notice',
|
||||
PERSONAL_HEARING: 'Personal Hearing',
|
||||
NBH_FINAL_APPROVAL: 'NBH Final Approval',
|
||||
CCO_APPROVAL: 'CCO Approval',
|
||||
CEO_APPROVAL: 'CEO Final Approval',
|
||||
LEGAL_LETTER: 'Legal - Termination Letter',
|
||||
TERMINATED: 'Terminated',
|
||||
REJECTED: 'Rejected'
|
||||
} as const;
|
||||
|
||||
// Resignation Stages
|
||||
export const RESIGNATION_STAGES = {
|
||||
ASM: 'ASM',
|
||||
@ -92,6 +111,9 @@ export const RESIGNATION_STAGES = {
|
||||
NBH: 'NBH',
|
||||
DD_ADMIN: 'DD Admin',
|
||||
LEGAL: 'Legal',
|
||||
SPARES_CLEARANCE: 'Spares Clearance',
|
||||
SERVICE_CLEARANCE: 'Service Clearance',
|
||||
ACCOUNTS_CLEARANCE: 'Accounts Clearance',
|
||||
FINANCE: 'Finance',
|
||||
FNF_INITIATED: 'F&F Initiated',
|
||||
COMPLETED: 'Completed',
|
||||
|
||||
@ -31,6 +31,8 @@ export interface ApplicationAttributes {
|
||||
isShortlisted: boolean;
|
||||
ddLeadShortlisted: boolean;
|
||||
assignedTo: string | null;
|
||||
architectureAssignedTo: string | null;
|
||||
architectureStatus: string | null;
|
||||
submittedBy: string | null;
|
||||
zoneId: string | null;
|
||||
regionId: string | null;
|
||||
@ -176,6 +178,19 @@ export default (sequelize: Sequelize) => {
|
||||
key: 'id'
|
||||
}
|
||||
},
|
||||
architectureAssignedTo: {
|
||||
type: DataTypes.UUID,
|
||||
allowNull: true,
|
||||
references: {
|
||||
model: 'users',
|
||||
key: 'id'
|
||||
}
|
||||
},
|
||||
architectureStatus: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: true,
|
||||
defaultValue: 'Pending'
|
||||
},
|
||||
submittedBy: {
|
||||
type: DataTypes.UUID,
|
||||
allowNull: true,
|
||||
@ -231,6 +246,7 @@ export default (sequelize: Sequelize) => {
|
||||
(Application as any).associate = (models: any) => {
|
||||
Application.belongsTo(models.User, { foreignKey: 'submittedBy', as: 'submitter' });
|
||||
Application.belongsTo(models.User, { foreignKey: 'assignedTo', as: 'assignee' });
|
||||
Application.belongsTo(models.User, { foreignKey: 'architectureAssignedTo', as: 'architectureAssignee' });
|
||||
Application.belongsTo(models.Opportunity, { foreignKey: 'opportunityId', as: 'opportunity' });
|
||||
Application.belongsTo(models.Zone, { foreignKey: 'zoneId', as: 'zone' });
|
||||
Application.belongsTo(models.Region, { foreignKey: 'regionId', as: 'region' });
|
||||
|
||||
@ -18,6 +18,12 @@ export interface ResignationAttributes {
|
||||
documents: any[];
|
||||
timeline: any[];
|
||||
rejectionReason: string | null;
|
||||
departmentalClearances: {
|
||||
spares: boolean;
|
||||
service: boolean;
|
||||
accounts: boolean;
|
||||
logistics: boolean;
|
||||
} | null;
|
||||
}
|
||||
|
||||
export interface ResignationInstance extends Model<ResignationAttributes>, ResignationAttributes { }
|
||||
@ -97,6 +103,15 @@ export default (sequelize: Sequelize) => {
|
||||
rejectionReason: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true
|
||||
},
|
||||
departmentalClearances: {
|
||||
type: DataTypes.JSON,
|
||||
defaultValue: {
|
||||
spares: false,
|
||||
service: false,
|
||||
accounts: false,
|
||||
logistics: false
|
||||
}
|
||||
}
|
||||
}, {
|
||||
tableName: 'resignations',
|
||||
|
||||
@ -7,8 +7,11 @@ export interface TerminationRequestAttributes {
|
||||
reason: string;
|
||||
proposedLwd: Date;
|
||||
status: string;
|
||||
currentStage: string;
|
||||
initiatedBy: string;
|
||||
comments: string | null;
|
||||
timeline: any[];
|
||||
documents: any[];
|
||||
}
|
||||
|
||||
export interface TerminationRequestInstance extends Model<TerminationRequestAttributes>, TerminationRequestAttributes { }
|
||||
@ -42,7 +45,11 @@ export default (sequelize: Sequelize) => {
|
||||
},
|
||||
status: {
|
||||
type: DataTypes.STRING,
|
||||
defaultValue: 'pending'
|
||||
defaultValue: 'Initiated'
|
||||
},
|
||||
currentStage: {
|
||||
type: DataTypes.STRING,
|
||||
defaultValue: 'INITIATED'
|
||||
},
|
||||
initiatedBy: {
|
||||
type: DataTypes.UUID,
|
||||
@ -55,6 +62,14 @@ export default (sequelize: Sequelize) => {
|
||||
comments: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true
|
||||
},
|
||||
timeline: {
|
||||
type: DataTypes.JSON,
|
||||
defaultValue: []
|
||||
},
|
||||
documents: {
|
||||
type: DataTypes.JSON,
|
||||
defaultValue: []
|
||||
}
|
||||
}, {
|
||||
tableName: 'termination_requests',
|
||||
|
||||
@ -43,12 +43,17 @@
|
||||
</div>
|
||||
<div class="content">
|
||||
<p>Dear {{applicantName}},</p>
|
||||
<p>Thank you for showing interest in becoming a Royal Enfield dealer.</p>
|
||||
<p>We have reviewed our current network plan for <strong>{{location}}</strong>, and currently, there are no
|
||||
open opportunities available in this area.</p>
|
||||
<p>We have saved your details in our database and will contact you should an opportunity arise in the
|
||||
future.</p>
|
||||
<p>We appreciate your enthusiasm for the brand.</p>
|
||||
<p>Thank you for your interest in Royal Enfield and for your application to represent our brand as an
|
||||
authorized dealer.</p>
|
||||
<p>We have carefully reviewed your expression of interest in relation to our current network expansion
|
||||
strategy for <strong>{{location}}</strong>. At this juncture, we do not have any immediate vacancies or
|
||||
planned dealership opportunities available in this specific territory.</p>
|
||||
<p>However, we have successfully retained your profile in our prospective partners database. Rest assured,
|
||||
our team will proactively reach out to you should a suitable opportunity materialize in this region or
|
||||
if our strategic requirements in your preferred location evolve further.</p>
|
||||
<p>We appreciate the time you took to share your details and your continued enthusiasm for Royal Enfield.
|
||||
</p>
|
||||
<p>Best regards,<br>Dealer Development Team<br>Royal Enfield</p>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<p>© {{year}} Royal Enfield. All rights reserved.</p>
|
||||
|
||||
@ -425,3 +425,71 @@ export const bulkShortlist = async (req: AuthRequest, res: Response) => {
|
||||
res.status(500).json({ success: false, message: 'Error processing shortlist' });
|
||||
}
|
||||
};
|
||||
|
||||
export const assignArchitectureTeam = async (req: AuthRequest, res: Response) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { userId, remarks } = req.body;
|
||||
|
||||
const application = await Application.findByPk(id);
|
||||
if (!application) return res.status(404).json({ success: false, message: 'Application not found' });
|
||||
|
||||
await application.update({
|
||||
architectureAssignedTo: userId,
|
||||
architectureStatus: 'Assigned',
|
||||
updatedAt: new Date()
|
||||
});
|
||||
|
||||
// Add as participant
|
||||
await db.RequestParticipant.findOrCreate({
|
||||
where: {
|
||||
requestId: application.id,
|
||||
requestType: 'application',
|
||||
userId,
|
||||
participantType: 'architecture'
|
||||
},
|
||||
defaults: { joinedMethod: 'auto' }
|
||||
});
|
||||
|
||||
await AuditLog.create({
|
||||
userId: req.user?.id,
|
||||
action: AUDIT_ACTIONS.UPDATED,
|
||||
entityType: 'application',
|
||||
entityId: application.id,
|
||||
newData: { architectureAssignedTo: userId, remarks }
|
||||
});
|
||||
|
||||
res.json({ success: true, message: 'Architecture team assigned successfully' });
|
||||
} catch (error) {
|
||||
console.error('Assign architecture team error:', error);
|
||||
res.status(500).json({ success: false, message: 'Error assigning architecture team' });
|
||||
}
|
||||
};
|
||||
|
||||
export const updateArchitectureStatus = async (req: AuthRequest, res: Response) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { status, remarks } = req.body;
|
||||
|
||||
const application = await Application.findByPk(id);
|
||||
if (!application) return res.status(404).json({ success: false, message: 'Application not found' });
|
||||
|
||||
await application.update({
|
||||
architectureStatus: status,
|
||||
updatedAt: new Date()
|
||||
});
|
||||
|
||||
await AuditLog.create({
|
||||
userId: req.user?.id,
|
||||
action: AUDIT_ACTIONS.UPDATED,
|
||||
entityType: 'application',
|
||||
entityId: application.id,
|
||||
newData: { architectureStatus: status, remarks }
|
||||
});
|
||||
|
||||
res.json({ success: true, message: 'Architecture status updated successfully' });
|
||||
} catch (error) {
|
||||
console.error('Update architecture status error:', error);
|
||||
res.status(500).json({ success: false, message: 'Error updating architecture status' });
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,24 +1,32 @@
|
||||
import express from 'express';
|
||||
const router = express.Router();
|
||||
import * as onboardingController from './onboarding.controller.js';
|
||||
import {
|
||||
submitApplication, getApplications, getApplicationById, updateApplicationStatus,
|
||||
uploadDocuments, getApplicationDocuments, bulkShortlist,
|
||||
assignArchitectureTeam, updateArchitectureStatus
|
||||
} from './onboarding.controller.js';
|
||||
import { authenticate } from '../../common/middleware/auth.js';
|
||||
|
||||
import { uploadSingle } from '../../common/middleware/upload.js';
|
||||
|
||||
// All routes require authentication (or public for submission? Keeping auth for now)
|
||||
// Public route for application submission
|
||||
router.post('/apply', onboardingController.submitApplication);
|
||||
router.post('/apply', submitApplication);
|
||||
|
||||
// All subsequent routes require authentication
|
||||
router.use(authenticate as any);
|
||||
|
||||
router.get('/applications', onboardingController.getApplications);
|
||||
router.post('/applications/shortlist', onboardingController.bulkShortlist);
|
||||
router.get('/applications/:id', onboardingController.getApplicationById);
|
||||
router.put('/applications/:id/status', onboardingController.updateApplicationStatus);
|
||||
router.put('/applications/:id/status', onboardingController.updateApplicationStatus);
|
||||
router.post('/applications/:id/documents', uploadSingle, onboardingController.uploadDocuments);
|
||||
router.get('/applications/:id/documents', onboardingController.getApplicationDocuments);
|
||||
router.get('/applications', getApplications);
|
||||
router.post('/applications/shortlist', bulkShortlist); // Existing route, updated to named import
|
||||
router.get('/applications/:id', getApplicationById);
|
||||
router.put('/applications/:id/status', updateApplicationStatus);
|
||||
router.post('/applications/:id/documents', uploadSingle, uploadDocuments);
|
||||
router.get('/applications/:id/documents', getApplicationDocuments); // Existing route, updated to named import
|
||||
|
||||
// Architecture-related routes
|
||||
router.post('/applications/:id/assign-architecture', assignArchitectureTeam);
|
||||
router.put('/applications/:id/architecture-status', updateArchitectureStatus);
|
||||
|
||||
|
||||
// Questionnaire Routes
|
||||
router.get('/questionnaires', (req, res, next) => {
|
||||
|
||||
@ -24,12 +24,12 @@ export const submitRequest = async (req: AuthRequest, res: Response) => {
|
||||
description: reason,
|
||||
currentStage: 'DD_ADMIN_REVIEW' as any,
|
||||
status: 'Pending',
|
||||
progressPercentage: 0,
|
||||
progressPercentage: 20,
|
||||
documents: [],
|
||||
timeline: [{
|
||||
stage: 'Submitted',
|
||||
timestamp: new Date(),
|
||||
user: req.user.name,
|
||||
user: req.user.fullName,
|
||||
action: 'Request submitted'
|
||||
}]
|
||||
});
|
||||
@ -65,7 +65,7 @@ export const getRequests = async (req: AuthRequest, res: Response) => {
|
||||
{
|
||||
model: User,
|
||||
as: 'dealer',
|
||||
attributes: ['name']
|
||||
attributes: ['fullName']
|
||||
}
|
||||
],
|
||||
order: [['createdAt', 'DESC']]
|
||||
@ -97,7 +97,7 @@ export const getRequestById = async (req: AuthRequest, res: Response) => {
|
||||
{
|
||||
model: User,
|
||||
as: 'dealer',
|
||||
attributes: ['name', 'email']
|
||||
attributes: ['fullName', 'email']
|
||||
},
|
||||
{
|
||||
model: Worknote,
|
||||
@ -137,16 +137,36 @@ export const takeAction = async (req: AuthRequest, res: Response) => {
|
||||
return res.status(404).json({ success: false, message: 'Request not found' });
|
||||
}
|
||||
|
||||
const stageFlow: Record<string, string> = {
|
||||
'DD_ADMIN_REVIEW': 'LEGAL_REVIEW',
|
||||
'LEGAL_REVIEW': 'NBH_APPROVAL',
|
||||
'NBH_APPROVAL': 'FINANCE_CLEARANCE',
|
||||
'FINANCE_CLEARANCE': 'COMPLETED'
|
||||
};
|
||||
|
||||
const currentStage = request.currentStage as string;
|
||||
let nextStage = currentStage;
|
||||
let finalStatus = action;
|
||||
|
||||
if (action === 'Approve') {
|
||||
nextStage = stageFlow[currentStage] || currentStage;
|
||||
finalStatus = nextStage === 'COMPLETED' ? 'Completed' : `Pending ${nextStage.replace('_', ' ')}`;
|
||||
} else if (action === 'Reject') {
|
||||
nextStage = 'REJECTED';
|
||||
finalStatus = 'Rejected';
|
||||
}
|
||||
|
||||
const timeline = [...request.timeline, {
|
||||
stage: 'Review',
|
||||
stage: currentStage,
|
||||
timestamp: new Date(),
|
||||
user: req.user.name,
|
||||
user: req.user.fullName,
|
||||
action,
|
||||
remarks: comments
|
||||
}];
|
||||
|
||||
await request.update({
|
||||
status: action,
|
||||
status: finalStatus,
|
||||
currentStage: nextStage as any,
|
||||
timeline,
|
||||
updatedAt: new Date()
|
||||
});
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Response } from 'express';
|
||||
import db from '../../database/models/index.js';
|
||||
const { RelocationRequest, Outlet, User, Worknote } = db;
|
||||
import { AUDIT_ACTIONS, ROLES } from '../../common/config/constants.js';
|
||||
import { AUDIT_ACTIONS, ROLES, RELOCATION_STAGES } from '../../common/config/constants.js';
|
||||
import { Op, Transaction } from 'sequelize';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { AuthRequest } from '../../types/express.types.js';
|
||||
@ -27,14 +27,14 @@ export const submitRequest = async (req: AuthRequest, res: Response) => {
|
||||
newCity: proposedCity,
|
||||
newState: proposedState,
|
||||
reason,
|
||||
currentStage: 'DD_ADMIN_REVIEW' as any,
|
||||
currentStage: RELOCATION_STAGES.DD_ADMIN_REVIEW as any,
|
||||
status: 'Pending',
|
||||
progressPercentage: 0,
|
||||
progressPercentage: 20,
|
||||
documents: [],
|
||||
timeline: [{
|
||||
stage: 'Submitted',
|
||||
timestamp: new Date(),
|
||||
user: req.user.name,
|
||||
user: req.user.fullName,
|
||||
action: 'Request submitted'
|
||||
}]
|
||||
});
|
||||
@ -70,7 +70,7 @@ export const getRequests = async (req: AuthRequest, res: Response) => {
|
||||
{
|
||||
model: User,
|
||||
as: 'dealer',
|
||||
attributes: ['name']
|
||||
attributes: ['fullName']
|
||||
}
|
||||
],
|
||||
order: [['createdAt', 'DESC']]
|
||||
@ -102,7 +102,7 @@ export const getRequestById = async (req: AuthRequest, res: Response) => {
|
||||
{
|
||||
model: User,
|
||||
as: 'dealer',
|
||||
attributes: ['name', 'email']
|
||||
attributes: ['fullName', 'email']
|
||||
},
|
||||
{
|
||||
model: Worknote,
|
||||
@ -147,10 +147,19 @@ export const takeAction = async (req: AuthRequest, res: Response) => {
|
||||
let newStatus = request.status;
|
||||
let newCurrentStage = request.currentStage;
|
||||
|
||||
const stageFlow: Record<string, string> = {
|
||||
[RELOCATION_STAGES.DD_ADMIN_REVIEW]: RELOCATION_STAGES.RBM_REVIEW,
|
||||
[RELOCATION_STAGES.RBM_REVIEW]: RELOCATION_STAGES.NBH_APPROVAL,
|
||||
[RELOCATION_STAGES.NBH_APPROVAL]: RELOCATION_STAGES.LEGAL_CLEARANCE,
|
||||
[RELOCATION_STAGES.LEGAL_CLEARANCE]: RELOCATION_STAGES.COMPLETED
|
||||
};
|
||||
|
||||
if (action === 'Approved') {
|
||||
newStatus = 'Approved';
|
||||
newCurrentStage = stageFlow[request.currentStage] || request.currentStage;
|
||||
newStatus = newCurrentStage === RELOCATION_STAGES.COMPLETED ? 'Completed' : `Pending ${newCurrentStage.replace('_', ' ')}`;
|
||||
} else if (action === 'Rejected') {
|
||||
newStatus = 'Rejected';
|
||||
newCurrentStage = RELOCATION_STAGES.REJECTED;
|
||||
}
|
||||
|
||||
// Create a worknote entry
|
||||
|
||||
@ -18,8 +18,11 @@ const calculateProgress = (stage: string): number => {
|
||||
[RESIGNATION_STAGES.RBM]: 30,
|
||||
[RESIGNATION_STAGES.ZBH]: 45,
|
||||
[RESIGNATION_STAGES.NBH]: 60,
|
||||
[RESIGNATION_STAGES.DD_ADMIN]: 70,
|
||||
[RESIGNATION_STAGES.LEGAL]: 80,
|
||||
[RESIGNATION_STAGES.DD_ADMIN]: 65,
|
||||
[RESIGNATION_STAGES.LEGAL]: 70,
|
||||
[RESIGNATION_STAGES.SPARES_CLEARANCE]: 75,
|
||||
[RESIGNATION_STAGES.SERVICE_CLEARANCE]: 80,
|
||||
[RESIGNATION_STAGES.ACCOUNTS_CLEARANCE]: 85,
|
||||
[RESIGNATION_STAGES.FINANCE]: 90,
|
||||
[RESIGNATION_STAGES.FNF_INITIATED]: 95,
|
||||
[RESIGNATION_STAGES.COMPLETED]: 100,
|
||||
@ -88,7 +91,7 @@ export const createResignation = async (req: AuthRequest, res: Response, next: N
|
||||
timeline: [{
|
||||
stage: 'Submitted',
|
||||
timestamp: new Date(),
|
||||
user: req.user.name,
|
||||
user: req.user.fullName,
|
||||
action: 'Resignation request submitted'
|
||||
}]
|
||||
}, { transaction });
|
||||
@ -260,7 +263,10 @@ export const approveResignation = async (req: AuthRequest, res: Response, next:
|
||||
[RESIGNATION_STAGES.ZBH]: RESIGNATION_STAGES.NBH,
|
||||
[RESIGNATION_STAGES.NBH]: RESIGNATION_STAGES.DD_ADMIN,
|
||||
[RESIGNATION_STAGES.DD_ADMIN]: RESIGNATION_STAGES.LEGAL,
|
||||
[RESIGNATION_STAGES.LEGAL]: RESIGNATION_STAGES.FINANCE,
|
||||
[RESIGNATION_STAGES.LEGAL]: RESIGNATION_STAGES.SPARES_CLEARANCE,
|
||||
[RESIGNATION_STAGES.SPARES_CLEARANCE]: RESIGNATION_STAGES.SERVICE_CLEARANCE,
|
||||
[RESIGNATION_STAGES.SERVICE_CLEARANCE]: RESIGNATION_STAGES.ACCOUNTS_CLEARANCE,
|
||||
[RESIGNATION_STAGES.ACCOUNTS_CLEARANCE]: RESIGNATION_STAGES.FINANCE,
|
||||
[RESIGNATION_STAGES.FINANCE]: RESIGNATION_STAGES.FNF_INITIATED,
|
||||
[RESIGNATION_STAGES.FNF_INITIATED]: RESIGNATION_STAGES.COMPLETED
|
||||
};
|
||||
@ -279,7 +285,7 @@ export const approveResignation = async (req: AuthRequest, res: Response, next:
|
||||
const timeline = [...resignation.timeline, {
|
||||
stage: nextStage,
|
||||
timestamp: new Date(),
|
||||
user: req.user.name,
|
||||
user: req.user.fullName,
|
||||
action: 'Approved',
|
||||
remarks
|
||||
}];
|
||||
@ -357,7 +363,7 @@ export const rejectResignation = async (req: AuthRequest, res: Response, next: N
|
||||
const timeline = [...resignation.timeline, {
|
||||
stage: 'Rejected',
|
||||
timestamp: new Date(),
|
||||
user: req.user.name,
|
||||
user: req.user.fullName,
|
||||
action: 'Rejected',
|
||||
reason
|
||||
}];
|
||||
@ -399,3 +405,39 @@ export const rejectResignation = async (req: AuthRequest, res: Response, next: N
|
||||
next(error);
|
||||
}
|
||||
};
|
||||
|
||||
// Update departmental clearance
|
||||
export const updateClearance = async (req: AuthRequest, res: Response, next: NextFunction) => {
|
||||
const transaction: Transaction = await db.sequelize.transaction();
|
||||
try {
|
||||
if (!req.user) throw new Error('Unauthorized');
|
||||
const { id } = req.params;
|
||||
const { department, cleared, remarks } = req.body;
|
||||
|
||||
const resignation = await db.Resignation.findByPk(id);
|
||||
if (!resignation) {
|
||||
await transaction.rollback();
|
||||
return res.status(404).json({ success: false, message: 'Resignation not found' });
|
||||
}
|
||||
|
||||
const clearances = { ...resignation.departmentalClearances, [department]: cleared };
|
||||
|
||||
await resignation.update({
|
||||
departmentalClearances: clearances,
|
||||
timeline: [...resignation.timeline, {
|
||||
stage: resignation.currentStage,
|
||||
timestamp: new Date(),
|
||||
user: req.user.fullName,
|
||||
action: cleared ? `Cleared ${department}` : `Revoked ${department} clearance`,
|
||||
remarks
|
||||
}]
|
||||
}, { transaction });
|
||||
|
||||
await transaction.commit();
|
||||
res.json({ success: true, message: `Clearance updated for ${department}`, resignation });
|
||||
} catch (error) {
|
||||
if (transaction) await transaction.rollback();
|
||||
logger.error('Error updating clearance:', error);
|
||||
next(error);
|
||||
}
|
||||
};
|
||||
|
||||
@ -9,5 +9,6 @@ router.get('/', authenticate as any, resignationController.getResignations);
|
||||
router.get('/:id', authenticate as any, resignationController.getResignationById);
|
||||
router.put('/:id/approve', authenticate as any, resignationController.approveResignation);
|
||||
router.put('/:id/reject', authenticate as any, resignationController.rejectResignation);
|
||||
router.put('/:id/clearance', authenticate as any, resignationController.updateClearance);
|
||||
|
||||
export default router;
|
||||
|
||||
178
src/modules/termination/termination.controller.ts
Normal file
178
src/modules/termination/termination.controller.ts
Normal file
@ -0,0 +1,178 @@
|
||||
import { Response, NextFunction } from 'express';
|
||||
import db from '../../database/models/index.js';
|
||||
import logger from '../../common/utils/logger.js';
|
||||
import { TERMINATION_STAGES, AUDIT_ACTIONS, ROLES } from '../../common/config/constants.js';
|
||||
import { Transaction } from 'sequelize';
|
||||
import { AuthRequest } from '../../types/express.types.js';
|
||||
|
||||
// Calculate progress percentage based on stage
|
||||
const calculateProgress = (stage: string): number => {
|
||||
const stageProgress: Record<string, number> = {
|
||||
[TERMINATION_STAGES.SUBMITTED]: 10,
|
||||
[TERMINATION_STAGES.RBM_REVIEW]: 20,
|
||||
[TERMINATION_STAGES.ZBH_REVIEW]: 30,
|
||||
[TERMINATION_STAGES.DD_LEAD_REVIEW]: 40,
|
||||
[TERMINATION_STAGES.LEGAL_VERIFICATION]: 50,
|
||||
[TERMINATION_STAGES.NBH_EVALUATION]: 60,
|
||||
[TERMINATION_STAGES.SCN_ISSUED]: 70,
|
||||
[TERMINATION_STAGES.PERSONAL_HEARING]: 75,
|
||||
[TERMINATION_STAGES.NBH_FINAL_APPROVAL]: 80,
|
||||
[TERMINATION_STAGES.CCO_APPROVAL]: 85,
|
||||
[TERMINATION_STAGES.CEO_APPROVAL]: 90,
|
||||
[TERMINATION_STAGES.LEGAL_LETTER]: 95,
|
||||
[TERMINATION_STAGES.TERMINATED]: 100,
|
||||
[TERMINATION_STAGES.REJECTED]: 0
|
||||
};
|
||||
return stageProgress[stage] || 0;
|
||||
};
|
||||
|
||||
// Create termination request
|
||||
export const createTermination = async (req: AuthRequest, res: Response, next: NextFunction) => {
|
||||
const transaction: Transaction = await db.sequelize.transaction();
|
||||
try {
|
||||
if (!req.user) throw new Error('Unauthorized');
|
||||
const { dealerId, category, reason, proposedLwd, comments } = req.body;
|
||||
|
||||
// Restriction: Only ASM or RBM can initiate (as per user request: "ASM or RBM can initiate")
|
||||
// Note: Check existing roles in constants. ROLES.RBM exists. ASM might be DD or similar.
|
||||
// For now, I'll allow ASM (mapped to DD/Initiator) and RBM.
|
||||
|
||||
const termination = await db.TerminationRequest.create({
|
||||
dealerId,
|
||||
category,
|
||||
reason,
|
||||
proposedLwd,
|
||||
comments,
|
||||
initiatedBy: req.user.id,
|
||||
currentStage: TERMINATION_STAGES.SUBMITTED,
|
||||
status: 'Submitted',
|
||||
timeline: [{
|
||||
stage: 'Submitted',
|
||||
timestamp: new Date(),
|
||||
user: req.user.fullName,
|
||||
action: 'Termination request initiated',
|
||||
remarks: comments
|
||||
}]
|
||||
}, { transaction });
|
||||
|
||||
await db.AuditLog.create({
|
||||
userId: req.user.id,
|
||||
action: AUDIT_ACTIONS.CREATED,
|
||||
entityType: 'termination',
|
||||
entityId: termination.id
|
||||
}, { transaction });
|
||||
|
||||
await transaction.commit();
|
||||
res.status(201).json({ success: true, message: 'Termination request created', termination });
|
||||
} catch (error) {
|
||||
if (transaction) await transaction.rollback();
|
||||
logger.error('Error creating termination:', error);
|
||||
next(error);
|
||||
}
|
||||
};
|
||||
|
||||
// Get all terminations
|
||||
export const getTerminations = async (req: AuthRequest, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const terminations = await db.TerminationRequest.findAll({
|
||||
include: [
|
||||
{ model: db.Dealer, as: 'dealer' },
|
||||
{ model: db.User, as: 'initiator', attributes: ['id', 'fullName', 'roleCode'] }
|
||||
],
|
||||
order: [['createdAt', 'DESC']]
|
||||
});
|
||||
res.json({ success: true, terminations });
|
||||
} catch (error) {
|
||||
logger.error('Error fetching terminations:', error);
|
||||
next(error);
|
||||
}
|
||||
};
|
||||
|
||||
// Get termination by ID
|
||||
export const getTerminationById = async (req: AuthRequest, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const termination = await db.TerminationRequest.findByPk(id, {
|
||||
include: [
|
||||
{ model: db.Dealer, as: 'dealer' },
|
||||
{ model: db.User, as: 'initiator', attributes: ['id', 'fullName', 'roleCode'] }
|
||||
]
|
||||
});
|
||||
if (!termination) return res.status(404).json({ success: false, message: 'Termination not found' });
|
||||
res.json({ success: true, termination });
|
||||
} catch (error) {
|
||||
logger.error('Error fetching termination:', error);
|
||||
next(error);
|
||||
}
|
||||
};
|
||||
|
||||
// Update termination status (Approve/Reject)
|
||||
export const updateTerminationStatus = async (req: AuthRequest, res: Response, next: NextFunction) => {
|
||||
const transaction: Transaction = await db.sequelize.transaction();
|
||||
try {
|
||||
if (!req.user) throw new Error('Unauthorized');
|
||||
const { id } = req.params;
|
||||
const { action, remarks } = req.body; // action: 'approve' | 'reject' | 'sendback'
|
||||
|
||||
const termination = await db.TerminationRequest.findByPk(id);
|
||||
if (!termination) {
|
||||
await transaction.rollback();
|
||||
return res.status(404).json({ success: false, message: 'Termination not found' });
|
||||
}
|
||||
|
||||
if (action === 'reject') {
|
||||
await termination.update({
|
||||
currentStage: TERMINATION_STAGES.REJECTED,
|
||||
status: 'Rejected',
|
||||
timeline: [...termination.timeline, {
|
||||
stage: 'Rejected',
|
||||
timestamp: new Date(),
|
||||
user: req.user.fullName,
|
||||
action: 'Rejected',
|
||||
remarks
|
||||
}]
|
||||
}, { transaction });
|
||||
} else {
|
||||
// Approval flow
|
||||
const stageFlow: Record<string, string> = {
|
||||
[TERMINATION_STAGES.SUBMITTED]: TERMINATION_STAGES.RBM_REVIEW,
|
||||
[TERMINATION_STAGES.RBM_REVIEW]: TERMINATION_STAGES.ZBH_REVIEW,
|
||||
[TERMINATION_STAGES.ZBH_REVIEW]: TERMINATION_STAGES.DD_LEAD_REVIEW,
|
||||
[TERMINATION_STAGES.DD_LEAD_REVIEW]: TERMINATION_STAGES.LEGAL_VERIFICATION,
|
||||
[TERMINATION_STAGES.LEGAL_VERIFICATION]: TERMINATION_STAGES.NBH_EVALUATION,
|
||||
[TERMINATION_STAGES.NBH_EVALUATION]: TERMINATION_STAGES.SCN_ISSUED,
|
||||
[TERMINATION_STAGES.SCN_ISSUED]: TERMINATION_STAGES.PERSONAL_HEARING,
|
||||
[TERMINATION_STAGES.PERSONAL_HEARING]: TERMINATION_STAGES.NBH_FINAL_APPROVAL,
|
||||
[TERMINATION_STAGES.NBH_FINAL_APPROVAL]: TERMINATION_STAGES.CCO_APPROVAL,
|
||||
[TERMINATION_STAGES.CCO_APPROVAL]: TERMINATION_STAGES.CEO_APPROVAL,
|
||||
[TERMINATION_STAGES.CEO_APPROVAL]: TERMINATION_STAGES.LEGAL_LETTER,
|
||||
[TERMINATION_STAGES.LEGAL_LETTER]: TERMINATION_STAGES.TERMINATED
|
||||
};
|
||||
|
||||
const nextStage = stageFlow[termination.currentStage];
|
||||
if (!nextStage) {
|
||||
await transaction.rollback();
|
||||
return res.status(400).json({ success: false, message: 'Cannot approve from current stage' });
|
||||
}
|
||||
|
||||
await termination.update({
|
||||
currentStage: nextStage,
|
||||
status: nextStage === TERMINATION_STAGES.TERMINATED ? 'Terminated' : `${nextStage}`,
|
||||
timeline: [...termination.timeline, {
|
||||
stage: nextStage,
|
||||
timestamp: new Date(),
|
||||
user: req.user.fullName,
|
||||
action: 'Approved/Moved',
|
||||
remarks
|
||||
}]
|
||||
}, { transaction });
|
||||
}
|
||||
|
||||
await transaction.commit();
|
||||
res.json({ success: true, message: 'Termination updated', termination });
|
||||
} catch (error) {
|
||||
if (transaction) await transaction.rollback();
|
||||
logger.error('Error updating termination:', error);
|
||||
next(error);
|
||||
}
|
||||
};
|
||||
15
src/modules/termination/termination.routes.ts
Normal file
15
src/modules/termination/termination.routes.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import express from 'express';
|
||||
const router = express.Router();
|
||||
import {
|
||||
createTermination, getTerminations, getTerminationById, updateTerminationStatus
|
||||
} from './termination.controller.js';
|
||||
import { authenticate } from '../../common/middleware/auth.js';
|
||||
|
||||
router.use(authenticate as any);
|
||||
|
||||
router.post('/', createTermination);
|
||||
router.get('/', getTerminations);
|
||||
router.get('/:id', getTerminationById);
|
||||
router.put('/:id/status', updateTerminationStatus);
|
||||
|
||||
export default router;
|
||||
@ -36,6 +36,7 @@ import communicationRoutes from './modules/communication/communication.routes.js
|
||||
import auditRoutes from './modules/audit/audit.routes.js';
|
||||
import questionnaireRoutes from './modules/onboarding/questionnaire.routes.js';
|
||||
import prospectiveLoginRoutes from './modules/prospective-login/prospective-login.routes.js';
|
||||
import terminationRoutes from './modules/termination/termination.routes.js';
|
||||
|
||||
// Import common middleware & utils
|
||||
import errorHandler from './common/middleware/errorHandler.js';
|
||||
@ -125,6 +126,7 @@ app.use('/api/communication', communicationRoutes);
|
||||
app.use('/api/audit', auditRoutes);
|
||||
app.use('/api/questionnaire', questionnaireRoutes);
|
||||
app.use('/api/prospective-login', prospectiveLoginRoutes);
|
||||
app.use('/api/termination', terminationRoutes);
|
||||
|
||||
// Backward Compatibility Aliases
|
||||
app.use('/api/applications', onboardingRoutes);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user