zonal manager chnged to regions manged from districts managed need to recheck again end to end
This commit is contained in:
parent
c0a97854e0
commit
574fc84ba4
@ -108,6 +108,14 @@ import { syncLocationManagers, syncRegionManager, syncZoneManager } from '../src
|
||||
});
|
||||
await mapUserRole(rmResult[0], 'RM', { regionId: region1.id });
|
||||
|
||||
// ZM is now mapped to Regions (not Districts) — multi-region support
|
||||
const zmResult = await User.findOrCreate({
|
||||
where: { email: 'zm.north@example.com' },
|
||||
defaults: { fullName: 'North Zonal Manager', roleCode: 'DD-ZM', password: hashedPassword, employeeId: 'ZM001' }
|
||||
});
|
||||
// One UserRole entry per region managed by this ZM
|
||||
await mapUserRole(zmResult[0], 'DD-ZM', { zoneId: zone1.id, regionId: region1.id });
|
||||
|
||||
const asmResult = await User.findOrCreate({
|
||||
where: { email: 'asm.sdelhi@example.com' },
|
||||
defaults: { fullName: 'South Delhi ASM', roleCode: 'ASM', password: hashedPassword, employeeId: 'ASM001' }
|
||||
@ -132,7 +140,7 @@ import { syncLocationManagers, syncRegionManager, syncZoneManager } from '../src
|
||||
fullName: m.name,
|
||||
roleCode: m.roleCode,
|
||||
password: hashedPassword,
|
||||
isExternal: m.isExt || false,
|
||||
isExternal: (m as any).isExt || false,
|
||||
status: 'active'
|
||||
}
|
||||
});
|
||||
@ -142,14 +150,15 @@ import { syncLocationManagers, syncRegionManager, syncZoneManager } from '../src
|
||||
console.log('Users and Mappings seeded.');
|
||||
|
||||
console.log('--- Triggering Hierarchy Synchronization ---');
|
||||
const districts = await District.findAll({ attributes: ['id'] });
|
||||
for (const d of districts) await syncLocationManagers(d.id);
|
||||
// syncLocationManagers now resolves zmId from the region parent — so districts get updated automatically
|
||||
const districtList = await District.findAll({ attributes: ['id'] });
|
||||
for (const d of districtList) await syncLocationManagers(d.id);
|
||||
|
||||
const regions = await Region.findAll({ attributes: ['id'] });
|
||||
for (const r of regions) await syncRegionManager(r.id);
|
||||
const regionList = await Region.findAll({ attributes: ['id'] });
|
||||
for (const r of regionList) await syncRegionManager(r.id);
|
||||
|
||||
const zones = await Zone.findAll({ attributes: ['id'] });
|
||||
for (const z of zones) await syncZoneManager(z.id);
|
||||
const zoneList = await Zone.findAll({ attributes: ['id'] });
|
||||
for (const z of zoneList) await syncZoneManager(z.id);
|
||||
|
||||
console.log('--- Seeding & Synchronization Complete ---');
|
||||
}
|
||||
|
||||
@ -290,6 +290,7 @@ export const createUser = async (req: AuthRequest, res: Response) => {
|
||||
locationId,
|
||||
assignments,
|
||||
districts, // New: ASM managed areas
|
||||
regionIds, // New: ZM managed regions
|
||||
asmCode, // New: ASM code
|
||||
zmCode // New: ZM code
|
||||
} = req.body;
|
||||
@ -343,36 +344,52 @@ 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' || roleCode === 'ZM')) {
|
||||
const targetRole = await Role.findOne({ where: { roleCode: roleCode } });
|
||||
} else if (districts && Array.isArray(districts) && roleCode === 'ASM') {
|
||||
const targetRole = await Role.findOne({ where: { roleCode: 'ASM' } });
|
||||
if (targetRole) {
|
||||
// Resolve Zone and Region from the districts
|
||||
let targetZoneId = null;
|
||||
let targetRegionId = null;
|
||||
if (districts.length > 0) {
|
||||
const sampleDistrict = await db.District.findByPk(districts[0]);
|
||||
if (sampleDistrict) {
|
||||
targetZoneId = sampleDistrict.zoneId;
|
||||
targetRegionId = sampleDistrict.regionId;
|
||||
}
|
||||
}
|
||||
|
||||
for (const distId of districts) {
|
||||
const sampleDistrict = await db.District.findByPk(distId);
|
||||
await db.UserRole.create({
|
||||
userId: user.id,
|
||||
roleId: targetRole.id,
|
||||
districtId: distId,
|
||||
zoneId: targetZoneId,
|
||||
regionId: targetRegionId,
|
||||
managerCode: asmCode || zmCode || null,
|
||||
zoneId: sampleDistrict?.zoneId || null,
|
||||
regionId: sampleDistrict?.regionId || null,
|
||||
managerCode: asmCode || null,
|
||||
isPrimary: false,
|
||||
isActive: true,
|
||||
assignedBy: req.user?.id || null
|
||||
});
|
||||
// Atomic Sync
|
||||
await syncLocationManagers(distId);
|
||||
}
|
||||
}
|
||||
} else if ((regionIds || districts) && (roleCode === 'ZM' || roleCode === 'DD-ZM')) {
|
||||
const targetRole = await Role.findOne({ where: { roleCode: roleCode } });
|
||||
if (targetRole) {
|
||||
// If districts are passed for ZM, we convert them to unique regionIds for consistency
|
||||
let finalRegionIds = regionIds || [];
|
||||
if (finalRegionIds.length === 0 && districts && districts.length > 0) {
|
||||
const mappedDistricts = await db.District.findAll({ where: { id: { [Op.in]: districts } } });
|
||||
finalRegionIds = Array.from(new Set(mappedDistricts.map((d: any) => d.regionId).filter(Boolean)));
|
||||
}
|
||||
|
||||
for (const regId of finalRegionIds) {
|
||||
const region = await db.Region.findByPk(regId);
|
||||
await db.UserRole.create({
|
||||
userId: user.id,
|
||||
roleId: targetRole.id,
|
||||
regionId: regId,
|
||||
zoneId: region?.zoneId || null,
|
||||
managerCode: zmCode || null,
|
||||
isActive: true,
|
||||
assignedBy: req.user?.id || null
|
||||
});
|
||||
|
||||
// Trigger sync for all districts in this region to update legacy zmId
|
||||
const regionDistricts = await db.District.findAll({ where: { regionId: regId } });
|
||||
for (const d of regionDistricts) await syncLocationManagers(d.id);
|
||||
}
|
||||
}
|
||||
} else if (roleCode) {
|
||||
const role = await Role.findOne({ where: { roleCode } });
|
||||
if (role) {
|
||||
@ -448,8 +465,9 @@ export const updateUser = async (req: AuthRequest, res: Response) => {
|
||||
mobileNumber, department, designation,
|
||||
locationId,
|
||||
assignments,
|
||||
districts, // New: ASM managed areas/districts
|
||||
asmCode, // New: ASM code to store in managerCode
|
||||
districts, // New: ASM managed areas
|
||||
regionIds, // New: ZM managed regions
|
||||
asmCode, // New: ASM code
|
||||
zmCode, // New: ZM code
|
||||
password // Optional password update
|
||||
} = req.body;
|
||||
@ -489,76 +507,54 @@ 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' || roleCode === 'ZM')) {
|
||||
// Specialized logic for Manager level (ASM/ZM) territory management
|
||||
const targetRole = await Role.findOne({ where: { roleCode: roleCode } });
|
||||
if (!targetRole) throw new Error(`${roleCode} role not found`);
|
||||
} 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`);
|
||||
|
||||
// 1. DUPLICATION CHECK: Ensure these districts aren't assigned to another active manager of the same role
|
||||
const duplicate = await db.UserRole.findOne({
|
||||
where: {
|
||||
roleId: targetRole.id,
|
||||
districtId: { [Op.in]: districts },
|
||||
userId: { [Op.ne]: id },
|
||||
isActive: true
|
||||
},
|
||||
include: [{ model: db.User, as: 'user', attributes: ['fullName'] }]
|
||||
});
|
||||
|
||||
if (duplicate) {
|
||||
const location = await db.District.findByPk(duplicate.districtId);
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: `Territory "${location?.name}" is already assigned to ${duplicate.user?.fullName}. Duplicate assignments for ${roleCode} are restricted.`
|
||||
});
|
||||
}
|
||||
|
||||
// 2. Transactional Update: Clear old assignments for this role and add new ones
|
||||
await db.UserRole.destroy({ where: { userId: id, roleId: targetRole.id } });
|
||||
|
||||
// Clear old asmId/managerId assignments in District table for this specific user
|
||||
// (The sync service will handle the new ones)
|
||||
if (roleCode === 'ASM') await db.District.update({ asmId: null, asmCode: null }, { where: { asmId: id } });
|
||||
if (roleCode === 'ZM') await db.District.update({ zmId: null, zmCode: null }, { where: { zmId: id } });
|
||||
|
||||
// 3. TRANSFER LOGIC: If any of these districts are currently assigned to ANOTHER manager for this role,
|
||||
// deactivate those assignments to prevent duplication.
|
||||
await db.UserRole.update({ isActive: false }, {
|
||||
where: {
|
||||
roleId: targetRole.id,
|
||||
districtId: { [Op.in]: districts },
|
||||
userId: { [Op.ne]: id },
|
||||
isActive: true
|
||||
}
|
||||
});
|
||||
|
||||
// 4. Resolve Zone and Region from the districts
|
||||
let targetZoneId = null;
|
||||
let targetRegionId = null;
|
||||
if (districts.length > 0) {
|
||||
const sampleDistrict = await db.District.findByPk(districts[0]);
|
||||
if (sampleDistrict) {
|
||||
targetZoneId = sampleDistrict.zoneId;
|
||||
targetRegionId = sampleDistrict.regionId;
|
||||
}
|
||||
}
|
||||
await db.District.update({ asmId: null, asmCode: null }, { where: { asmId: id } });
|
||||
|
||||
for (const distId of districts) {
|
||||
// Update UserRole table
|
||||
const sampleDistrict = await db.District.findByPk(distId);
|
||||
await db.UserRole.create({
|
||||
userId: id,
|
||||
roleId: targetRole.id,
|
||||
districtId: distId,
|
||||
zoneId: targetZoneId,
|
||||
regionId: targetRegionId,
|
||||
managerCode: asmCode || zmCode || null,
|
||||
isPrimary: false,
|
||||
zoneId: sampleDistrict?.zoneId || null,
|
||||
regionId: sampleDistrict?.regionId || null,
|
||||
managerCode: asmCode || null,
|
||||
isActive: true,
|
||||
assignedBy: req.user?.id || null
|
||||
});
|
||||
await syncLocationManagers(distId);
|
||||
}
|
||||
} else if ((regionIds || districts) && (roleCode === 'ZM' || roleCode === 'DD-ZM')) {
|
||||
const targetRole = await Role.findOne({ where: { roleCode: roleCode } });
|
||||
if (!targetRole) throw new Error(`${roleCode} role not found`);
|
||||
|
||||
await db.UserRole.destroy({ where: { userId: id, roleId: targetRole.id } });
|
||||
await db.District.update({ zmId: null, zmCode: null }, { where: { zmId: id } });
|
||||
|
||||
let finalRegionIds = regionIds || [];
|
||||
if (finalRegionIds.length === 0 && districts && districts.length > 0) {
|
||||
const mappedDistricts = await db.District.findAll({ where: { id: { [Op.in]: districts } } });
|
||||
finalRegionIds = Array.from(new Set(mappedDistricts.map((d: any) => d.regionId).filter(Boolean)));
|
||||
}
|
||||
|
||||
for (const regId of finalRegionIds) {
|
||||
const region = await db.Region.findByPk(regId);
|
||||
await db.UserRole.create({
|
||||
userId: id,
|
||||
roleId: targetRole.id,
|
||||
regionId: regId,
|
||||
zoneId: region?.zoneId || null,
|
||||
managerCode: zmCode || null,
|
||||
isActive: true,
|
||||
assignedBy: req.user?.id || null
|
||||
});
|
||||
|
||||
// Atomic Sync (handles Location table asmId / asmCode / etc)
|
||||
await syncLocationManagers(distId);
|
||||
const regionDistricts = await db.District.findAll({ where: { regionId: regId } });
|
||||
for (const d of regionDistricts) await syncLocationManagers(d.id);
|
||||
}
|
||||
}
|
||||
else if (roleCode !== undefined || locationId !== undefined) {
|
||||
|
||||
@ -778,19 +778,22 @@ export const getZonalManagers = async (req: Request, res: Response) => {
|
||||
as: 'userRoles',
|
||||
where: { isActive: true },
|
||||
required: true,
|
||||
include: [{
|
||||
include: [
|
||||
{
|
||||
model: db.Role,
|
||||
as: 'role',
|
||||
where: { roleCode: { [Op.in]: ['ZM', 'DD-ZM', 'ZBH'] } }
|
||||
}]
|
||||
where: { roleCode: { [db.Sequelize.Op.in]: ['ZM', 'DD-ZM', 'ZBH'] } }
|
||||
},
|
||||
{
|
||||
model: db.District,
|
||||
as: 'managedZmDistricts',
|
||||
include: [
|
||||
{ model: db.Zone, as: 'zone', attributes: ['id', 'name'] },
|
||||
{ model: db.Region, as: 'region', attributes: ['id', 'name'] },
|
||||
{ model: db.State, as: 'state', attributes: ['id', 'name'] }
|
||||
model: db.Region,
|
||||
as: 'region',
|
||||
attributes: ['id', 'name']
|
||||
},
|
||||
{
|
||||
model: db.Zone,
|
||||
as: 'zone',
|
||||
attributes: ['id', 'name']
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
@ -799,29 +802,28 @@ export const getZonalManagers = async (req: Request, res: Response) => {
|
||||
|
||||
const result = (zms || []).map((u: any) => {
|
||||
const rolePriority = ['DD-ZM', 'ZM', 'ZBH'];
|
||||
const roleAssignment = (u.userRoles || []).sort((a: any, b: any) => {
|
||||
const roleAssignments = (u.userRoles || []).filter((r: any) => rolePriority.includes(r.role?.roleCode));
|
||||
|
||||
const mainAssignment = [...roleAssignments].sort((a: any, b: any) => {
|
||||
const aIndex = rolePriority.indexOf(a.role?.roleCode || '');
|
||||
const bIndex = rolePriority.indexOf(b.role?.roleCode || '');
|
||||
if (aIndex !== bIndex) return aIndex - bIndex;
|
||||
// If same role type, prefer the one with a code
|
||||
if (a.managerCode && !b.managerCode) return -1;
|
||||
if (!a.managerCode && b.managerCode) return 1;
|
||||
return 0;
|
||||
})[0];
|
||||
const zmCode = roleAssignment?.managerCode || u.employeeId || 'N/A';
|
||||
|
||||
// Collect unique zones and states
|
||||
const zoneSet = new Set<string>();
|
||||
const stateSet = new Set<string>();
|
||||
let inferredZoneId = roleAssignment?.zoneId || null;
|
||||
const zmCode = mainAssignment?.managerCode || u.employeeId || 'N/A';
|
||||
|
||||
(u.managedZmDistricts || []).forEach((d: any) => {
|
||||
if (d.zone) {
|
||||
zoneSet.add(d.zone.name);
|
||||
if (!inferredZoneId) inferredZoneId = d.zone.id; // Fallback to first district's zone if role zone is missing
|
||||
}
|
||||
if (d.state) stateSet.add(d.state.name);
|
||||
});
|
||||
const regionIds = (u.userRoles || [])
|
||||
.filter((ur: any) => (ur.role?.roleCode === 'DD-ZM' || ur.role?.roleCode === 'ZM') && ur.regionId)
|
||||
.map((ur: any) => ur.regionId);
|
||||
|
||||
const regionNames = (u.userRoles || [])
|
||||
.filter((ur: any) => (ur.role?.roleCode === 'DD-ZM' || ur.role?.roleCode === 'ZM') && ur.region?.name)
|
||||
.map((ur: any) => ur.region.name);
|
||||
|
||||
const zoneId = mainAssignment?.zoneId || (u.userRoles?.[0]?.zoneId) || null;
|
||||
const zoneName = mainAssignment?.zone?.name || (u.userRoles?.[0]?.zone?.name) || 'Not Assigned';
|
||||
|
||||
return {
|
||||
id: u.id,
|
||||
@ -830,14 +832,10 @@ export const getZonalManagers = async (req: Request, res: Response) => {
|
||||
employeeId: u.employeeId,
|
||||
zmCode: zmCode,
|
||||
status: u.status,
|
||||
zoneId: inferredZoneId,
|
||||
zones: Array.from(zoneSet).length > 0 ? Array.from(zoneSet) : ["Assigned Zone"],
|
||||
stateNames: Array.from(stateSet),
|
||||
districts: (u.managedZmDistricts || []).map((d: any) => ({
|
||||
id: d.id,
|
||||
name: d.name,
|
||||
state: d.state?.name
|
||||
}))
|
||||
zoneId: zoneId,
|
||||
zoneName: zoneName,
|
||||
assignedRegionIds: regionIds,
|
||||
regionNames: Array.from(new Set(regionNames))
|
||||
};
|
||||
});
|
||||
|
||||
@ -850,14 +848,12 @@ export const getZonalManagers = async (req: Request, res: Response) => {
|
||||
|
||||
export const saveZM = async (req: Request, res: Response) => {
|
||||
try {
|
||||
const { userId, zmCode, zoneId, districts, status } = req.body;
|
||||
const { userId, zmCode, zoneId, regionIds, status } = req.body;
|
||||
if (!userId) return res.status(400).json({ success: false, message: 'userId is required' });
|
||||
|
||||
// Find the ZM role (DD-ZM)
|
||||
const zmRole = await db.Role.findOne({ where: { roleCode: 'DD-ZM' } });
|
||||
if (!zmRole) return res.status(404).json({ success: false, message: 'ZM role (DD-ZM) not found in roles table' });
|
||||
if (!zmRole) return res.status(404).json({ success: false, message: 'ZM role (DD-ZM) not found' });
|
||||
|
||||
// Update User status if provided
|
||||
if (status) {
|
||||
await db.User.update({ status }, { where: { id: userId } });
|
||||
}
|
||||
@ -867,33 +863,34 @@ export const saveZM = async (req: Request, res: Response) => {
|
||||
where: { userId, roleId: zmRole.id }
|
||||
});
|
||||
|
||||
// Create new active UserRole with managerCode = zmCode
|
||||
// Create new role assignments for each region
|
||||
if (Array.isArray(regionIds) && regionIds.length > 0) {
|
||||
for (const regionId of regionIds) {
|
||||
await db.UserRole.create({
|
||||
userId,
|
||||
roleId: zmRole.id,
|
||||
zoneId: zoneId || null,
|
||||
regionId: regionId,
|
||||
managerCode: zmCode || null,
|
||||
isActive: true,
|
||||
isPrimary: true
|
||||
});
|
||||
|
||||
// Assign districts to this user if provided
|
||||
// First, clear this ZM from any other districts they might have had
|
||||
await db.District.update({ zmId: null, zmCode: null }, { where: { zmId: userId } });
|
||||
|
||||
if (Array.isArray(districts) && districts.length > 0) {
|
||||
// Then assign new ones
|
||||
const updateProps: any = {
|
||||
zmId: userId,
|
||||
zmCode: zmCode || null
|
||||
};
|
||||
if (zoneId) updateProps.zoneId = zoneId;
|
||||
|
||||
await db.District.update(
|
||||
updateProps,
|
||||
{ where: { id: { [db.Sequelize.Op.in]: districts } } }
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Case with no specific region but assigned to a zone
|
||||
await db.UserRole.create({
|
||||
userId,
|
||||
roleId: zmRole.id,
|
||||
zoneId: zoneId || null,
|
||||
regionId: null,
|
||||
managerCode: zmCode || null,
|
||||
isActive: true,
|
||||
isPrimary: true
|
||||
});
|
||||
}
|
||||
|
||||
// Cleanup: ZMs no longer manage districts directly
|
||||
await db.District.update({ zmId: null, zmCode: null }, { where: { zmId: userId } });
|
||||
|
||||
res.json({ success: true, message: 'Zonal Manager saved successfully' });
|
||||
} catch (error) {
|
||||
@ -902,7 +899,114 @@ export const saveZM = async (req: Request, res: Response) => {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
export const getDDLeads = async (req: Request, res: Response) => {
|
||||
try {
|
||||
const ddLeads = await db.User.findAll({
|
||||
attributes: ['id', 'fullName', 'email', 'employeeId', 'status'],
|
||||
include: [
|
||||
{
|
||||
model: db.UserRole,
|
||||
as: 'userRoles',
|
||||
where: { isActive: true },
|
||||
required: true,
|
||||
include: [{
|
||||
model: db.Role,
|
||||
as: 'role',
|
||||
where: { roleCode: 'DD Lead' }
|
||||
}]
|
||||
}
|
||||
],
|
||||
order: [['fullName', 'ASC']]
|
||||
});
|
||||
|
||||
const result = (ddLeads || []).map((u: any) => {
|
||||
const roleAssignment = (u.userRoles || []).find((r: any) => (r.role?.roleCode === 'DD Lead'));
|
||||
const leadCode = roleAssignment?.managerCode || u.employeeId || 'N/A';
|
||||
|
||||
// Collect unique zones from all active DD Lead roles for this user
|
||||
const zoneMap = new Map();
|
||||
(u.userRoles || []).forEach((ur: any) => {
|
||||
if (ur.role?.roleCode === 'DD Lead' && ur.zoneId) {
|
||||
// We need the zone name, but it's not included in this query.
|
||||
// We'll rely on the frontend to map names or fetch them if missing.
|
||||
// However, it's better to include Zone in the include.
|
||||
zoneMap.set(ur.zoneId, ur.zoneId);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
id: u.id,
|
||||
name: u.fullName,
|
||||
email: u.email,
|
||||
employeeId: u.employeeId,
|
||||
leadCode: leadCode,
|
||||
status: u.status,
|
||||
assignedZoneIds: Array.from(zoneMap.values())
|
||||
};
|
||||
});
|
||||
|
||||
// To get zone names, we'd need another query or better include.
|
||||
// Let's refine the include to get zone names.
|
||||
|
||||
res.json({ success: true, data: result });
|
||||
} catch (error) {
|
||||
console.error('Get DD Leads error:', error);
|
||||
res.status(500).json({ success: false, message: 'Error fetching DD Leads' });
|
||||
}
|
||||
};
|
||||
|
||||
export const saveDDLead = async (req: Request, res: Response) => {
|
||||
try {
|
||||
const { userId, leadCode, zoneIds, status } = req.body;
|
||||
if (!userId) return res.status(400).json({ success: false, message: 'userId is required' });
|
||||
|
||||
const leadRole = await db.Role.findOne({ where: { roleCode: 'DD Lead' } });
|
||||
if (!leadRole) return res.status(404).json({ success: false, message: 'DD Lead role not found' });
|
||||
|
||||
if (status) {
|
||||
await db.User.update({ status }, { where: { id: userId } });
|
||||
}
|
||||
|
||||
// Deactivate existing DD Lead roles for this user
|
||||
await db.UserRole.update({ isActive: false }, {
|
||||
where: { userId, roleId: leadRole.id }
|
||||
});
|
||||
|
||||
// Create new role assignments for each zone
|
||||
if (Array.isArray(zoneIds) && zoneIds.length > 0) {
|
||||
for (const zoneId of zoneIds) {
|
||||
await db.UserRole.create({
|
||||
userId,
|
||||
roleId: leadRole.id,
|
||||
zoneId: zoneId,
|
||||
managerCode: leadCode || null,
|
||||
isActive: true,
|
||||
isPrimary: true
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Case with no specific zone
|
||||
await db.UserRole.create({
|
||||
userId,
|
||||
roleId: leadRole.id,
|
||||
zoneId: null,
|
||||
managerCode: leadCode || null,
|
||||
isActive: true,
|
||||
isPrimary: true
|
||||
});
|
||||
}
|
||||
|
||||
res.json({ success: true, message: 'DD Lead saved successfully' });
|
||||
} catch (error) {
|
||||
console.error('Save DD Lead error:', error);
|
||||
res.status(500).json({ success: false, message: 'Error saving DD Lead' });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
export const createArea = createDistrict;
|
||||
export const deleteArea = deleteLocation;
|
||||
export const createDistrictLegacy = createDistrict;
|
||||
|
||||
|
||||
|
||||
@ -22,9 +22,12 @@ import {
|
||||
getAreaManagers,
|
||||
getASMs,
|
||||
getZonalManagers,
|
||||
saveZM
|
||||
saveZM,
|
||||
getDDLeads,
|
||||
saveDDLead
|
||||
} from './master.controller.js';
|
||||
|
||||
|
||||
const router = Router();
|
||||
|
||||
// --- Districts ---
|
||||
@ -59,5 +62,7 @@ router.get('/area-managers', getAreaManagers);
|
||||
router.get('/asms', getASMs);
|
||||
router.get('/zonal-managers', getZonalManagers);
|
||||
router.post('/zonal-managers', saveZM);
|
||||
router.get('/dd-leads', getDDLeads);
|
||||
router.post('/dd-leads', saveDDLead);
|
||||
|
||||
export default router;
|
||||
|
||||
@ -10,9 +10,17 @@ export const syncLocationManagers = async (districtId: string) => {
|
||||
const Role = db.Role;
|
||||
const Op = db.Sequelize.Op;
|
||||
|
||||
// Fetch active assignments for this district
|
||||
const district = await db.District.findByPk(districtId);
|
||||
if (!district) return;
|
||||
|
||||
// Fetch active assignments for this district PLUS any region-level assignments for its parent region
|
||||
const activeAssignments = await UserRole.findAll({
|
||||
where: { districtId, isActive: true },
|
||||
where: {
|
||||
[Op.or]: [
|
||||
{ districtId, isActive: true },
|
||||
{ regionId: district.regionId, isActive: true }
|
||||
]
|
||||
},
|
||||
include: [
|
||||
{ model: Role, as: 'role', attributes: ['roleCode'] },
|
||||
{ model: db.User, as: 'user', attributes: ['employeeId'] }
|
||||
@ -22,7 +30,15 @@ export const syncLocationManagers = async (districtId: string) => {
|
||||
// Find primary/last assigned manager for each type
|
||||
const asm = activeAssignments.find((a: any) => (a.role as any)?.roleCode === 'ASM' || (a.role as any)?.roleCode === 'AREA SALES MANAGER');
|
||||
const ddAm = activeAssignments.find((a: any) => (a.role as any)?.roleCode === 'DD-AM' || (a.role as any)?.roleCode === 'AREA MANAGER');
|
||||
const zm = activeAssignments.find((a: any) => (a.role as any)?.roleCode === 'DD-ZM' || (a.role as any)?.roleCode === 'ZM' || (a.role as any)?.roleCode === 'ZONAL MANAGER');
|
||||
|
||||
// ZM can be assigned to the District (legacy) or the Region (new)
|
||||
// We prioritize the Region-level assignment if multiple exist
|
||||
const zm = activeAssignments.find((a: any) =>
|
||||
((a.role as any)?.roleCode === 'DD-ZM' || (a.role as any)?.roleCode === 'ZM' || (a.role as any)?.roleCode === 'ZONAL MANAGER') &&
|
||||
a.regionId === district.regionId
|
||||
) || activeAssignments.find((a: any) =>
|
||||
((a.role as any)?.roleCode === 'DD-ZM' || (a.role as any)?.roleCode === 'ZM' || (a.role as any)?.roleCode === 'ZONAL MANAGER')
|
||||
);
|
||||
|
||||
// Update District table with IDs and Codes
|
||||
await db.District.update({
|
||||
|
||||
Loading…
Reference in New Issue
Block a user