few more bugs fixed and dealer ide ui alignmen and visibibity chabges done F& F made manuall trigger
This commit is contained in:
parent
fb07f7ab61
commit
e99a28b7f7
@ -35,6 +35,8 @@ console.log('✓ Termination stage resolution passed.');
|
||||
console.log('Testing getPreviousStage (Resignation)...');
|
||||
assert.equal(getPreviousStage(REQUEST_TYPES.RESIGNATION, RESIGNATION_STAGES.RBM), RESIGNATION_STAGES.ASM);
|
||||
assert.equal(getPreviousStage(REQUEST_TYPES.RESIGNATION, RESIGNATION_STAGES.ZBH), RESIGNATION_STAGES.RBM);
|
||||
assert.equal(getPreviousStage(REQUEST_TYPES.RESIGNATION, RESIGNATION_STAGES.FNF_INITIATED), RESIGNATION_STAGES.AWAITING_FNF);
|
||||
assert.equal(getPreviousStage(REQUEST_TYPES.RESIGNATION, RESIGNATION_STAGES.DD_ADMIN), RESIGNATION_STAGES.LEGAL);
|
||||
assert.equal(getPreviousStage(REQUEST_TYPES.RESIGNATION, RESIGNATION_STAGES.COMPLETED), RESIGNATION_STAGES.FNF_INITIATED);
|
||||
console.log('✓ Resignation stage resolution passed.');
|
||||
|
||||
|
||||
@ -200,6 +200,8 @@ export const RESIGNATION_STAGES = {
|
||||
DD_LEAD: 'DD Lead',
|
||||
NBH: 'NBH',
|
||||
DD_ADMIN: 'DD Admin',
|
||||
/** Post DD Admin — workflow paused until an authorized user runs Push to F&F (no automatic F&F). */
|
||||
AWAITING_FNF: 'Awaiting F&F',
|
||||
LEGAL: 'Legal',
|
||||
SPARES_CLEARANCE: 'Spares Clearance',
|
||||
SERVICE_CLEARANCE: 'Service Clearance',
|
||||
|
||||
@ -30,6 +30,8 @@ export const getResignationStatusForStage = (stage: string): string => {
|
||||
case RESIGNATION_STAGES.NBH:
|
||||
case RESIGNATION_STAGES.DD_ADMIN:
|
||||
return `${stage} Review`;
|
||||
case RESIGNATION_STAGES.AWAITING_FNF:
|
||||
return 'Awaiting F&F — manual initiation';
|
||||
case RESIGNATION_STAGES.LEGAL:
|
||||
return 'Legal - Resignation Letter';
|
||||
case RESIGNATION_STAGES.FNF_INITIATED:
|
||||
|
||||
@ -39,9 +39,10 @@ export const getPreviousStage = (requestType: string, currentStage: string): str
|
||||
[RESIGNATION_STAGES.ZBH]: RESIGNATION_STAGES.RBM,
|
||||
[RESIGNATION_STAGES.DD_LEAD]: RESIGNATION_STAGES.ZBH,
|
||||
[RESIGNATION_STAGES.NBH]: RESIGNATION_STAGES.DD_LEAD,
|
||||
[RESIGNATION_STAGES.DD_ADMIN]: RESIGNATION_STAGES.NBH,
|
||||
[RESIGNATION_STAGES.LEGAL]: RESIGNATION_STAGES.DD_ADMIN,
|
||||
[RESIGNATION_STAGES.FNF_INITIATED]: RESIGNATION_STAGES.LEGAL,
|
||||
[RESIGNATION_STAGES.LEGAL]: RESIGNATION_STAGES.NBH,
|
||||
[RESIGNATION_STAGES.DD_ADMIN]: RESIGNATION_STAGES.LEGAL,
|
||||
[RESIGNATION_STAGES.AWAITING_FNF]: RESIGNATION_STAGES.DD_ADMIN,
|
||||
[RESIGNATION_STAGES.FNF_INITIATED]: RESIGNATION_STAGES.AWAITING_FNF,
|
||||
[RESIGNATION_STAGES.COMPLETED]: RESIGNATION_STAGES.FNF_INITIATED
|
||||
};
|
||||
return flow[currentStage] || null;
|
||||
|
||||
@ -247,6 +247,7 @@ export async function resolveNextActors(requestId: string, requestType: string,
|
||||
|
||||
// --- Resignation Specific ---
|
||||
'DD Admin': [ROLES.DD_ADMIN],
|
||||
'Awaiting F&F': [ROLES.DD_LEAD, ROLES.DD_HEAD, ROLES.NBH, ROLES.DD_ADMIN],
|
||||
'Spares Clearance': [ROLES.SPARES_MANAGER],
|
||||
'Service Clearance': [ROLES.SERVICE_MANAGER],
|
||||
'Accounts Clearance': [ROLES.ACCOUNTS_MANAGER],
|
||||
|
||||
@ -397,7 +397,8 @@ export const approveResignation = async (req: AuthRequest, res: Response, next:
|
||||
[RESIGNATION_STAGES.DD_LEAD]: RESIGNATION_STAGES.NBH,
|
||||
[RESIGNATION_STAGES.NBH]: RESIGNATION_STAGES.LEGAL,
|
||||
[RESIGNATION_STAGES.LEGAL]: RESIGNATION_STAGES.DD_ADMIN,
|
||||
[RESIGNATION_STAGES.DD_ADMIN]: RESIGNATION_STAGES.FNF_INITIATED, // DD Admin approval moves to F&F initiation
|
||||
// DD Admin approval completes internal review; F&F is started only via explicit Push to F&F.
|
||||
[RESIGNATION_STAGES.DD_ADMIN]: RESIGNATION_STAGES.AWAITING_FNF,
|
||||
[RESIGNATION_STAGES.FNF_INITIATED]: RESIGNATION_STAGES.COMPLETED
|
||||
};
|
||||
|
||||
@ -407,16 +408,16 @@ export const approveResignation = async (req: AuthRequest, res: Response, next:
|
||||
return res.status(400).json({ success: false, message: 'Cannot move to next stage from current state' });
|
||||
}
|
||||
|
||||
// Guard before transition: F&F initiation is allowed only on/after LWD as per SRS §4.2.2.8
|
||||
// F&F records are created only from explicit Push to F&F (targetStage), not from sequential approvals.
|
||||
// LWD gate applies to that manual push (SRS §4.2.2.8).
|
||||
let shouldTriggerFnF = false;
|
||||
if (nextStage === RESIGNATION_STAGES.FNF_INITIATED) {
|
||||
if (nextStage === RESIGNATION_STAGES.FNF_INITIATED && targetOverride) {
|
||||
const today = new Date();
|
||||
const lwdString = resignation.lastOperationalDateServices || resignation.lastOperationalDateSales;
|
||||
const { force } = req.body;
|
||||
|
||||
|
||||
const lwd = lwdString ? new Date(lwdString) : null;
|
||||
if (lwd) {
|
||||
// Clear time for date-only comparison
|
||||
today.setHours(0, 0, 0, 0);
|
||||
lwd.setHours(0, 0, 0, 0);
|
||||
}
|
||||
@ -535,9 +536,14 @@ export const approveResignation = async (req: AuthRequest, res: Response, next:
|
||||
|
||||
await transaction.commit();
|
||||
|
||||
const message = (sourceStage === RESIGNATION_STAGES.LEGAL && nextStage === RESIGNATION_STAGES.LEGAL)
|
||||
? 'Legal stage approved successfully. Use Push to F&F to initiate settlement as per LWD rules.'
|
||||
: 'Resignation approved successfully';
|
||||
let message = 'Resignation approved successfully';
|
||||
if (nextStage === RESIGNATION_STAGES.AWAITING_FNF) {
|
||||
message =
|
||||
'DD Admin approval recorded. Use Push to F&F when ready to create the Full & Final settlement (Last Working Day rules apply).';
|
||||
} else if (sourceStage === RESIGNATION_STAGES.LEGAL && nextStage === RESIGNATION_STAGES.DD_ADMIN) {
|
||||
message =
|
||||
'Legal stage approved successfully. After DD Admin review, use Push to F&F to start settlement when ready.';
|
||||
}
|
||||
|
||||
res.json({ success: true, message, nextStage, resignation });
|
||||
} catch (error) {
|
||||
@ -608,6 +614,7 @@ export const withdrawResignation = async (req: AuthRequest, res: Response, next:
|
||||
const restrictedStages = [
|
||||
RESIGNATION_STAGES.NBH,
|
||||
RESIGNATION_STAGES.DD_ADMIN,
|
||||
RESIGNATION_STAGES.AWAITING_FNF,
|
||||
RESIGNATION_STAGES.LEGAL,
|
||||
RESIGNATION_STAGES.FNF_INITIATED,
|
||||
RESIGNATION_STAGES.COMPLETED
|
||||
@ -1047,10 +1054,15 @@ export const updateResignationStatus = async (req: AuthRequest, res: Response, n
|
||||
}
|
||||
|
||||
// SRS-aligned gate: F&F can start only after Legal completion artifacts.
|
||||
if (resignation.currentStage !== RESIGNATION_STAGES.LEGAL) {
|
||||
const pushAllowedStages = [
|
||||
RESIGNATION_STAGES.AWAITING_FNF,
|
||||
// Legacy rows: acceptance letter uploaded at Legal before DD Admin step completed in older builds
|
||||
RESIGNATION_STAGES.LEGAL
|
||||
];
|
||||
if (!pushAllowedStages.includes(resignation.currentStage as any)) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: `Cannot trigger F&F from ${resignation.currentStage}. Move request to Legal stage first.`
|
||||
message: `Cannot trigger F&F from ${resignation.currentStage}. Complete DD Admin review first (stage must be Awaiting F&F), or use Legal only for legacy cases.`
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -618,24 +618,18 @@ export const updateTerminationStatus = async (req: AuthRequest, res: Response, n
|
||||
transaction
|
||||
});
|
||||
|
||||
// If Terminated, trigger F&F initiation via Workflow Service
|
||||
// SRS REQUIREMENT: F&F settlement process is triggered only on the Last Working Day (LWD)
|
||||
// F&F is never started automatically on termination; authorized users run Push to F&F when ready.
|
||||
if (nextStage === TERMINATION_STAGES.TERMINATED) {
|
||||
const today = new Date();
|
||||
const lwd = new Date(termination.proposedLwd);
|
||||
|
||||
// Clear time components for date-only comparison
|
||||
today.setHours(0, 0, 0, 0);
|
||||
lwd.setHours(0, 0, 0, 0);
|
||||
|
||||
if (today >= lwd) {
|
||||
logger.info(`[TerminationController] LWD reached or passed (${termination.proposedLwd}). Initiating F&F.`);
|
||||
await TerminationWorkflowService.initiateFnF(termination, req.user.id, transaction);
|
||||
} else {
|
||||
logger.info(`[TerminationController] Termination approved but LWD (${termination.proposedLwd}) not yet reached. F&F will be triggered on LWD.`);
|
||||
// Keep parent status aligned while waiting for LWD-triggered F&F
|
||||
await termination.update({ status: 'Awaiting F&F (LWD Pending)' }, { transaction });
|
||||
}
|
||||
const statusAfterTerm =
|
||||
today < lwd ? 'Awaiting F&F (LWD Pending)' : 'Awaiting F&F';
|
||||
await termination.update({ status: statusAfterTerm }, { transaction });
|
||||
logger.info(
|
||||
`[TerminationController] Termination reached TERMINATED. F&F must be started manually (Push to F&F). LWD=${termination.proposedLwd}, status=${statusAfterTerm}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -135,6 +135,7 @@ export class ResignationWorkflowService {
|
||||
[RESIGNATION_STAGES.NBH]: 65,
|
||||
[RESIGNATION_STAGES.LEGAL]: 80,
|
||||
[RESIGNATION_STAGES.DD_ADMIN]: 90,
|
||||
[RESIGNATION_STAGES.AWAITING_FNF]: 92,
|
||||
[RESIGNATION_STAGES.FNF_INITIATED]: 95,
|
||||
[RESIGNATION_STAGES.COMPLETED]: 100,
|
||||
[RESIGNATION_STAGES.REJECTED]: 100
|
||||
@ -157,6 +158,7 @@ export class ResignationWorkflowService {
|
||||
[RESIGNATION_STAGES.NBH]: ROLES.NBH,
|
||||
[RESIGNATION_STAGES.LEGAL]: ROLES.LEGAL_ADMIN,
|
||||
[RESIGNATION_STAGES.DD_ADMIN]: ROLES.DD_ADMIN,
|
||||
[RESIGNATION_STAGES.AWAITING_FNF]: [ROLES.DD_LEAD, ROLES.DD_HEAD, ROLES.NBH, ROLES.DD_ADMIN],
|
||||
[RESIGNATION_STAGES.FNF_INITIATED]: ROLES.DD_ADMIN
|
||||
};
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user