Subversion Repositories SmartDukaan

Rev

Rev 37130 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 37130 Rev 37353
Line 72... Line 72...
72
import java.time.format.DateTimeFormatter;
72
import java.time.format.DateTimeFormatter;
73
import java.time.temporal.TemporalAdjusters;
73
import java.time.temporal.TemporalAdjusters;
74
import java.util.*;
74
import java.util.*;
75
import java.util.HashSet;
75
import java.util.HashSet;
76
import java.util.Map.Entry;
76
import java.util.Map.Entry;
-
 
77
import java.util.concurrent.ThreadLocalRandom;
77
import java.util.stream.Collectors;
78
import java.util.stream.Collectors;
78
 
79
 
79
@Controller
80
@Controller
80
@Transactional(rollbackFor = Throwable.class)
81
@Transactional(rollbackFor = Throwable.class)
81
public class LeadController {
82
public class LeadController {
82
    private static final Logger LOGGER = LogManager.getLogger(LeadController.class);
83
    private static final Logger LOGGER = LogManager.getLogger(LeadController.class);
83
 
84
 
84
    /** Source/createdBy label for leads captured by the AI assistant. */
85
    /** Source/createdBy label for leads captured by the AI assistant. */
85
    private static final String AI_LEAD_SOURCE = "AI Assistant";
86
    private static final String AI_LEAD_SOURCE = "AI Assistant";
86
 
87
 
-
 
88
    /**
-
 
89
     * Assignee used for AI leads only when no active Sales L1 can be resolved from cs.position.
-
 
90
     * Same auth id the web capture has always routed to, so intake never fails on an empty pool.
-
 
91
     */
-
 
92
    private static final int AI_LEAD_FALLBACK_ASSIGNEE = 53;
-
 
93
 
87
    @Autowired
94
    @Autowired
88
    private ResponseSender<?> responseSender;
95
    private ResponseSender<?> responseSender;
89
 
96
 
90
    @Value("${ai.lead.intake.token}")
97
    @Value("${ai.lead.intake.token}")
91
    private String aiLeadIntakeToken;
98
    private String aiLeadIntakeToken;
Line 798... Line 805...
798
        String recordingUrl = aiLeadRequest.getRecordingUrl();
805
        String recordingUrl = aiLeadRequest.getRecordingUrl();
799
        if (recordingUrl != null && !recordingUrl.trim().isEmpty()) {
806
        if (recordingUrl != null && !recordingUrl.trim().isEmpty()) {
800
            lead.setRecordingUrl(recordingUrl.trim());
807
            lead.setRecordingUrl(recordingUrl.trim());
801
        }
808
        }
802
 
809
 
803
        // Auto-assign using the same routing the public web capture uses today
810
        // Auto-assign to a randomly picked active Sales L1 so AI leads spread across the field team
804
        lead.setAssignTo(53);
811
        lead.setAssignTo(resolveAiLeadAssignee());
805
        lead.setAuthId(lead.getAssignTo());
812
        lead.setAuthId(lead.getAssignTo());
806
 
813
 
807
        lead.setCreatedTimestamp(LocalDateTime.now());
814
        lead.setCreatedTimestamp(LocalDateTime.now());
808
        lead.setUpdatedTimestamp(LocalDateTime.now());
815
        lead.setUpdatedTimestamp(LocalDateTime.now());
809
        leadRepository.persist(lead);
816
        leadRepository.persist(lead);
Line 811... Line 818...
811
        LOGGER.info("AI lead intake: created lead id={} for mobile {}", lead.getId(), mobile);
818
        LOGGER.info("AI lead intake: created lead id={} for mobile {}", lead.getId(), mobile);
812
        return responseSender.ok(lead.getId());
819
        return responseSender.ok(lead.getId());
813
 
820
 
814
    }
821
    }
815
 
822
 
-
 
823
    /**
-
 
824
     * Picks the owner for an incoming AI lead: a uniformly random <b>active</b> Sales L1 from
-
 
825
     * cs.position (category {@link ProfitMandiConstants#TICKET_CATEGORY_SALES}, escalation L1).
-
 
826
     * <p>
-
 
827
     * Sales L1 is the same position that drives Lead Management visibility, so the chosen user sees
-
 
828
     * the lead in their own list and their L2/L3 managers see it in their downline. Inactive users
-
 
829
     * are filtered out here because {@code getAuthUserByCategoryId(int, EscalationType)} does not
-
 
830
     * filter on active, and an inactive owner would strand the lead. Ids are already distinct per
-
 
831
     * user, so holding several regional positions does not raise a person's odds of being picked.
-
 
832
     */
-
 
833
    private int resolveAiLeadAssignee() {
-
 
834
        List<AuthUser> salesL1 = csService.getAuthUserByCategoryId(
-
 
835
                ProfitMandiConstants.TICKET_CATEGORY_SALES, EscalationType.L1);
-
 
836
 
-
 
837
        List<AuthUser> eligible = salesL1 == null ? Collections.<AuthUser>emptyList()
-
 
838
                : salesL1.stream()
-
 
839
                        .filter(x -> Boolean.TRUE.equals(x.isActive()))
-
 
840
                        .collect(Collectors.toList());
-
 
841
 
-
 
842
        if (eligible.isEmpty()) {
-
 
843
            LOGGER.warn("AI lead intake: no active Sales L1 in cs.position, falling back to auth id {}",
-
 
844
                    AI_LEAD_FALLBACK_ASSIGNEE);
-
 
845
            return AI_LEAD_FALLBACK_ASSIGNEE;
-
 
846
        }
-
 
847
 
-
 
848
        AuthUser assignee = eligible.get(ThreadLocalRandom.current().nextInt(eligible.size()));
-
 
849
        LOGGER.info("AI lead intake: assigned to Sales L1 {} ({}) picked from {} eligible",
-
 
850
                assignee.getId(), assignee.getFullName(), eligible.size());
-
 
851
        return assignee.getId();
-
 
852
    }
-
 
853
 
816
    @RequestMapping(value = "/getPartnersList", method = RequestMethod.GET)
854
    @RequestMapping(value = "/getPartnersList", method = RequestMethod.GET)
817
    @ApiImplicitParams({@ApiImplicitParam(name = "Auth-Token", value = "Auth-Token", required = true, dataType = "string", paramType = "header")})
855
    @ApiImplicitParams({@ApiImplicitParam(name = "Auth-Token", value = "Auth-Token", required = true, dataType = "string", paramType = "header")})
818
    public ResponseEntity<?> getPartners(HttpServletRequest request, @RequestParam(name = "gmailId") String gmailId)
856
    public ResponseEntity<?> getPartners(HttpServletRequest request, @RequestParam(name = "gmailId") String gmailId)
819
            throws ProfitMandiBusinessException {
857
            throws ProfitMandiBusinessException {
820
 
858