added DD-AM role in roles also aligned with role mapping for onboarding flow

This commit is contained in:
laxmanhalaki 2026-04-24 08:35:26 +05:30
parent 837be9bce1
commit c6b7b79021
5 changed files with 46 additions and 19 deletions

View File

@ -23,7 +23,8 @@ const rolesToSeed = [
{ roleCode: ROLES.CEO, roleName: 'CEO', category: 'LEADERSHIP', description: 'Chief Executive Officer' },
{ roleCode: ROLES.SPARES_MANAGER, roleName: 'Spares Manager', category: 'DEPARTMENT', description: 'Spares Department Clearance' },
{ roleCode: ROLES.SERVICE_MANAGER, roleName: 'Service Manager', category: 'DEPARTMENT', description: 'Service Department Clearance' },
{ roleCode: ROLES.ACCOUNTS_MANAGER, roleName: 'Accounts Manager', category: 'DEPARTMENT', description: 'Accounts Department Clearance' }
{ roleCode: ROLES.ACCOUNTS_MANAGER, roleName: 'Accounts Manager', category: 'DEPARTMENT', description: 'Accounts Department Clearance' },
{ roleCode: ROLES.DD_AM, roleName: 'DD-AM', category: 'SALES', description: 'Dealer Development Area Manager' }
];
async function seedRoles() {

View File

@ -31,7 +31,8 @@ async function seed() {
{ roleCode: 'FDD', roleName: 'FDD Team', category: 'EXTERNAL' },
{ roleCode: 'Legal Admin', roleName: 'Legal Admin', category: 'DEPARTMENT' },
{ roleCode: 'CEO', roleName: 'CEO', category: 'NATIONAL' },
{ roleCode: 'CCO', roleName: 'CCO', category: 'NATIONAL' }
{ roleCode: 'CCO', roleName: 'CCO', category: 'NATIONAL' },
{ roleCode: 'DD-AM', roleName: 'Dealer Development Area Manager', category: 'AREA' }
];
for (const r of roles) {
@ -139,7 +140,8 @@ async function seed() {
{ email: 'manav@royalenfield.com', name: 'manav', role: 'ZBH', zone: 'North Zone' },
{ email: 'piyush@royalenfield.com', name: 'piyush', role: 'DD-ZM', zone: 'North Zone' },
{ email: 'manish@royalenfield.com', name: 'manish', role: 'RBM', zone: 'North Zone' },
{ email: 'abhishek@royalenfield.com', name: 'abhishek', role: 'ASM', district: 'South Delhi' }
{ email: 'abhishek@royalenfield.com', name: 'abhishek', role: 'ASM', district: 'South Delhi' },
{ email: 'bharghav@gmail.com', name: 'Bharghav', role: 'DD-AM', district: 'South Delhi' }
];
for (const m of frontendMocks) {
const assignment: any = {};

View File

@ -384,12 +384,12 @@ export const createUser = async (req: AuthRequest, res: Response) => {
if (Array.isArray(assignments) && assignments.length > 0) {
await upsertUserAssignments(user.id, assignments, req.user?.id);
} else if (districts && Array.isArray(districts) && roleCode === 'ASM') {
const targetRole = await Role.findOne({ where: { roleCode: 'ASM' } });
} else if (districts && Array.isArray(districts) && ['ASM', 'DD-AM'].includes(roleCode)) {
const targetRole = await Role.findOne({ where: { roleCode } });
if (targetRole) {
for (const distId of districts) {
const sampleDistrict = await db.District.findByPk(distId);
const managerCode = await resolveManagerCode(targetRole.id, 'ASM', null);
const managerCode = await resolveManagerCode(targetRole.id, roleCode, null);
await db.UserRole.create({
userId: user.id,
roleId: targetRole.id,
@ -551,16 +551,20 @@ export const updateUser = async (req: AuthRequest, res: Response) => {
if (Array.isArray(assignments)) {
await upsertUserAssignments(id as string, assignments, req.user?.id);
} else if (districts && Array.isArray(districts) && roleCode === 'ASM') {
const targetRole = await Role.findOne({ where: { roleCode: 'ASM' } });
if (!targetRole) throw new Error(`ASM role not found`);
} else if (districts && Array.isArray(districts) && ['ASM', 'DD-AM'].includes(roleCode)) {
const targetRole = await Role.findOne({ where: { roleCode } });
if (!targetRole) throw new Error(`${roleCode} role not found`);
await db.UserRole.destroy({ where: { userId: id, roleId: targetRole.id } });
if (roleCode === 'ASM') {
await db.District.update({ asmId: null, asmCode: null }, { where: { asmId: id } });
} else {
await db.District.update({ ddAmId: null, ddAmCode: null }, { where: { ddAmId: id } });
}
for (const distId of districts) {
const sampleDistrict = await db.District.findByPk(distId);
const managerCode = await resolveManagerCode(targetRole.id, 'ASM', null);
const managerCode = await resolveManagerCode(targetRole.id, roleCode, null);
await db.UserRole.create({
userId: id,
roleId: targetRole.id,

View File

@ -887,7 +887,7 @@ export const getASMs = async (req: Request, res: Response) => {
try {
const asms = await db.User.findAll({
where: {
roleCode: { [db.Sequelize.Op.in]: ['ASM', 'AREA SALES MANAGER'] },
roleCode: { [db.Sequelize.Op.in]: ['ASM', 'AREA SALES MANAGER', 'DD-AM', ROLES.DD_AM] },
isActive: true
},
include: [
@ -896,7 +896,7 @@ export const getASMs = async (req: Request, res: Response) => {
as: 'userRoles',
where: { isActive: true },
required: false,
include: [{ model: db.Role, as: 'role', where: { roleCode: 'ASM' } }]
include: [{ model: db.Role, as: 'role', where: { roleCode: { [db.Sequelize.Op.in]: ['ASM', 'DD-AM', ROLES.DD_AM] } } }]
},
{
model: db.District,
@ -906,15 +906,29 @@ export const getASMs = async (req: Request, res: Response) => {
{ model: db.Region, as: 'region', attributes: ['id', 'name'] },
{ model: db.Zone, as: 'zone', attributes: ['id', 'name'] }
]
},
{
model: db.District,
as: 'managedDdAmDistricts',
include: [
{ model: db.State, as: 'state', attributes: ['id', 'name'] },
{ model: db.Region, as: 'region', attributes: ['id', 'name'] },
{ model: db.Zone, as: 'zone', attributes: ['id', 'name'] }
]
}
],
order: [['fullName', 'ASC']]
});
const result = (asms || []).map((u: any) => {
const districts = u.managedAsmDistricts || [];
const asmRoleAssignment = (u.userRoles || []).find((r: any) => r.role?.roleCode === 'ASM');
const asmCode = asmRoleAssignment?.managerCode || u.employeeId;
const asmDistricts = u.managedAsmDistricts || [];
const ddAmDistricts = u.managedDdAmDistricts || [];
const districts = [...asmDistricts, ...ddAmDistricts];
const roleAssignment = (u.userRoles || []).find((r: any) =>
['ASM', 'DD-AM'].includes(r.role?.roleCode)
);
const managerCode = roleAssignment?.managerCode || u.employeeId;
const zoneSet = new Set();
const regionSet = new Set();
@ -943,7 +957,8 @@ export const getASMs = async (req: Request, res: Response) => {
email: u.email,
phone: u.mobileNumber,
employeeId: u.employeeId,
asmCode: asmCode || 'N/A',
asmCode: managerCode || 'N/A',
roleCode: u.roleCode,
status: u.status,
zoneId: zones[0]?.id || '',
zoneName: zones[0]?.name || 'Unassigned',

View File

@ -683,8 +683,13 @@ const assignStageEvaluators = async (appIdOrId: string) => {
// --- INTERVIEWS ---
// --- GROUND STAKEHOLDERS (Area / District Level) ---
// SRS §9.3.4: ASM is responsible for ground opportunity identification and field validation.
if (district.asmId) evaluatorMappings['DD'] = [{ id: district.asmId, role: 'ASM' }];
// SRS §9.3.4: DD-AM is responsible for ground opportunity identification and field validation in onboarding.
// Falls back to ASM if DD-AM is not assigned for this district.
if (district.ddAmId) {
evaluatorMappings['DD'] = [{ id: district.ddAmId, role: 'DD-AM' }];
} else if (district.asmId) {
evaluatorMappings['DD'] = [{ id: district.asmId, role: 'ASM' }];
}
// Level 1: DD-ZM (District manager) + RBM (Region manager)
if (district.zmId) evaluatorMappings[1].push({ id: district.zmId, role: 'DD-ZM' });