| Line 1148... |
Line 1148... |
| 1148 |
// gate — those are just routing the lead to another department's queue
|
1148 |
// gate — those are just routing the lead to another department's queue
|
| 1149 |
// and don't carry a beat-day attachment.
|
1149 |
// and don't carry a beat-day attachment.
|
| 1150 |
int assignToId = createLeadActivityRequest.getAssignTo();
|
1150 |
int assignToId = createLeadActivityRequest.getAssignTo();
|
| 1151 |
boolean assigneeIsSales = assignToId > 0
|
1151 |
boolean assigneeIsSales = assignToId > 0
|
| 1152 |
&& positionRepository.hasCategory(assignToId, ProfitMandiConstants.TICKET_CATEGORY_SALES);
|
1152 |
&& positionRepository.hasCategory(assignToId, ProfitMandiConstants.TICKET_CATEGORY_SALES);
|
| - |
|
1153 |
|
| - |
|
1154 |
// BGC L2+ handing an unassigned system-generated lead to a BGC L1 team member
|
| - |
|
1155 |
// is internal routing (no beat-day attached), so the geo-verify gate does not
|
| - |
|
1156 |
// apply. Only fires when the current lead has no assignee yet.
|
| - |
|
1157 |
boolean bgcDirectAssign = assignToId > 0
|
| - |
|
1158 |
&& lead.getAssignTo() == 0
|
| - |
|
1159 |
&& AI_LEAD_SOURCE.equals(lead.getSource())
|
| - |
|
1160 |
&& isBgcAtOrAbove(authUser.getId(), EscalationType.L2, EscalationType.L3, EscalationType.L4, EscalationType.L5)
|
| - |
|
1161 |
&& isBgcL1(assignToId);
|
| - |
|
1162 |
|
| 1153 |
if (createLeadActivityRequest.getStatus() != LeadStatus.notInterested && assigneeIsSales) {
|
1163 |
if (createLeadActivityRequest.getStatus() != LeadStatus.notInterested && assigneeIsSales && !bgcDirectAssign) {
|
| 1154 |
LeadLiveLocation approvedGeo = leadLiveLocationRepository.selectApprovedByLeadId(createLeadActivityRequest.getId());
|
1164 |
LeadLiveLocation approvedGeo = leadLiveLocationRepository.selectApprovedByLeadId(createLeadActivityRequest.getId());
|
| 1155 |
if (approvedGeo == null) {
|
1165 |
if (approvedGeo == null) {
|
| 1156 |
throw new ProfitMandiBusinessException("Lead", "", "Live geo-location for this lead has not been approved yet. Please approve the geo-location before editing.");
|
1166 |
throw new ProfitMandiBusinessException("Lead", "", "Live geo-location for this lead has not been approved yet. Please approve the geo-location before editing.");
|
| 1157 |
}
|
1167 |
}
|
| 1158 |
}
|
1168 |
}
|
| 1159 |
|
1169 |
|
| 1160 |
if (leadDetail == null && !createLeadActivityRequest.getStatus().equals(LeadStatus.notInterested) && leadAuthUser.isActive()) {
|
1170 |
if (leadDetail == null && !createLeadActivityRequest.getStatus().equals(LeadStatus.notInterested) && leadAuthUser.isActive()) {
|
| - |
|
1171 |
if (bgcDirectAssign) {
|
| - |
|
1172 |
// Direct BGC L2 → L1 routing on an unassigned AI lead. AI intake does not
|
| - |
|
1173 |
// seed a lead_detail row (business fields are captured later during field
|
| - |
|
1174 |
// work), so drop in an empty placeholder to satisfy downstream code that
|
| - |
|
1175 |
// treats a null row as "form not yet filled".
|
| - |
|
1176 |
LeadDetail placeholder = new LeadDetail();
|
| 1161 |
|
- |
|
| - |
|
1177 |
placeholder.setLeadId(createLeadActivityRequest.getId());
|
| - |
|
1178 |
placeholder.setCreatedBy(authUser.getId());
|
| - |
|
1179 |
placeholder.setCreatedTimestamp(LocalDateTime.now());
|
| - |
|
1180 |
leadDetailRepository.persist(placeholder);
|
| - |
|
1181 |
} else {
|
| 1162 |
throw new ProfitMandiBusinessException("LeadDetail", "", "Please fill lead detail");
|
1182 |
throw new ProfitMandiBusinessException("LeadDetail", "", "Please fill lead detail");
|
| - |
|
1183 |
}
|
| 1163 |
}
|
1184 |
}
|
| 1164 |
|
1185 |
|
| 1165 |
LeadActivity leadActivity = new LeadActivity();
|
1186 |
LeadActivity leadActivity = new LeadActivity();
|
| 1166 |
leadActivity.setLeadId(createLeadActivityRequest.getId());
|
1187 |
leadActivity.setLeadId(createLeadActivityRequest.getId());
|
| 1167 |
leadActivity.setRemark(createLeadActivityRequest.getRemark());
|
1188 |
leadActivity.setRemark(createLeadActivityRequest.getRemark());
|
| Line 1375... |
Line 1396... |
| 1375 |
} catch (Exception e) {
|
1396 |
} catch (Exception e) {
|
| 1376 |
LOGGER.warn("Lead-assignment mail send failed: {}", e.getMessage());
|
1397 |
LOGGER.warn("Lead-assignment mail send failed: {}", e.getMessage());
|
| 1377 |
}
|
1398 |
}
|
| 1378 |
}
|
1399 |
}
|
| 1379 |
|
1400 |
|
| - |
|
1401 |
// True if the user holds a BGC position at L1.
|
| - |
|
1402 |
private boolean isBgcL1(int userId) {
|
| - |
|
1403 |
return positionRepository.selectPositionByAuthId(userId).stream()
|
| - |
|
1404 |
.anyMatch(p -> p.getCategoryId() == ProfitMandiConstants.TICKET_CATEGORY_BGC
|
| - |
|
1405 |
&& p.getEscalationType() == EscalationType.L1);
|
| - |
|
1406 |
}
|
| - |
|
1407 |
|
| - |
|
1408 |
// True if the user holds a BGC position at any of the given escalation levels.
|
| - |
|
1409 |
private boolean isBgcAtOrAbove(int userId, EscalationType... levels) {
|
| - |
|
1410 |
Set<EscalationType> targetSet = new HashSet<>(Arrays.asList(levels));
|
| - |
|
1411 |
return positionRepository.selectPositionByAuthId(userId).stream()
|
| - |
|
1412 |
.anyMatch(p -> p.getCategoryId() == ProfitMandiConstants.TICKET_CATEGORY_BGC
|
| - |
|
1413 |
&& targetSet.contains(p.getEscalationType()));
|
| - |
|
1414 |
}
|
| - |
|
1415 |
|
| 1380 |
// Returns the user's highest escalation across all positions (or null).
|
1416 |
// Returns the user's highest escalation across all positions (or null).
|
| 1381 |
// Used to gate the chain-mail cap.
|
1417 |
// Used to gate the chain-mail cap.
|
| 1382 |
private com.spice.profitmandi.dao.enumuration.cs.EscalationType highestEscalation(int authUserId) {
|
1418 |
private com.spice.profitmandi.dao.enumuration.cs.EscalationType highestEscalation(int authUserId) {
|
| 1383 |
com.spice.profitmandi.dao.enumuration.cs.EscalationType highest = null;
|
1419 |
com.spice.profitmandi.dao.enumuration.cs.EscalationType highest = null;
|
| 1384 |
try {
|
1420 |
try {
|