Subversion Repositories SmartDukaan

Rev

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

Rev 35617 Rev 35626
Line 4... Line 4...
4
import com.spice.profitmandi.common.model.CustomRetailer;
4
import com.spice.profitmandi.common.model.CustomRetailer;
5
import com.spice.profitmandi.common.model.ProfitMandiConstants;
5
import com.spice.profitmandi.common.model.ProfitMandiConstants;
6
import com.spice.profitmandi.common.util.Utils;
6
import com.spice.profitmandi.common.util.Utils;
7
import com.spice.profitmandi.dao.entity.auth.AuthUser;
7
import com.spice.profitmandi.dao.entity.auth.AuthUser;
8
import com.spice.profitmandi.dao.entity.cs.*;
8
import com.spice.profitmandi.dao.entity.cs.*;
-
 
9
import com.spice.profitmandi.dao.entity.cs.Position;
9
import com.spice.profitmandi.dao.entity.dtr.Document;
10
import com.spice.profitmandi.dao.entity.dtr.Document;
-
 
11
import com.spice.profitmandi.dao.entity.cs.TicketReadStatus.UserType;
10
import com.spice.profitmandi.dao.entity.fofo.ActivityType;
12
import com.spice.profitmandi.dao.entity.fofo.ActivityType;
11
import com.spice.profitmandi.dao.enumuration.cs.EscalationType;
13
import com.spice.profitmandi.dao.enumuration.cs.EscalationType;
12
import com.spice.profitmandi.dao.enumuration.cs.TicketStatus;
14
import com.spice.profitmandi.dao.enumuration.cs.TicketStatus;
13
import com.spice.profitmandi.dao.model.CreatePositionModel;
15
import com.spice.profitmandi.dao.model.CreatePositionModel;
14
import com.spice.profitmandi.dao.repository.auth.AuthRepository;
16
import com.spice.profitmandi.dao.repository.auth.AuthRepository;
Line 449... Line 451...
449
                ticketCategories = ticketCategories.stream()
451
                ticketCategories = ticketCategories.stream()
450
                        .filter(tc -> tc.getId() != ProfitMandiConstants.TICKET_CATEGORY_SALES
452
                        .filter(tc -> tc.getId() != ProfitMandiConstants.TICKET_CATEGORY_SALES
451
                                && tc.getId() != ProfitMandiConstants.TICKET_CATEGORY_RBM)
453
                                && tc.getId() != ProfitMandiConstants.TICKET_CATEGORY_RBM)
452
                        .collect(Collectors.toList());
454
                        .collect(Collectors.toList());
453
            }
455
            }
-
 
456
        } else {
-
 
457
            // For partners/customers: hide categories where ALL subcategories are invisible
-
 
458
            ticketCategories = ticketCategories.stream()
-
 
459
                    .filter(category -> {
-
 
460
                        List<TicketSubCategory> subs = ticketSubCategoryRepository.selectAll(category.getId());
-
 
461
                        // Keep category if at least one subcategory is visible
-
 
462
                        return subs.stream().anyMatch(TicketSubCategory::isVisibility);
-
 
463
                    })
-
 
464
                    .collect(Collectors.toList());
454
        }
465
        }
455
 
466
 
456
        model.addAttribute("roleType", isAdmin);
467
        model.addAttribute("roleType", isAdmin);
457
        model.addAttribute("ticketCategories", ticketCategories);
468
        model.addAttribute("ticketCategories", ticketCategories);
458
        model.addAttribute("isCrmUser", isCrmUser);
469
        model.addAttribute("isCrmUser", isCrmUser);
Line 533... Line 544...
533
        }
544
        }
534
        return "response";
545
        return "response";
535
    }
546
    }
536
 
547
 
537
    @GetMapping(value = "/cs/myticket")
548
    @GetMapping(value = "/cs/myticket")
-
 
549
    public String getTicket(HttpServletRequest request,
-
 
550
                            @RequestParam(name = "orderby", defaultValue = "DESCENDING") SortOrder sortOrder,
-
 
551
                            @RequestParam(name = "ticketStatus", defaultValue = "OPENED") TicketStatus ticketStatus,
-
 
552
                            @RequestParam(name = "ticketSearchType", defaultValue = "") TicketSearchType ticketSearchType,
-
 
553
                            @RequestParam(name = "searchTerm", defaultValue = "0") int searchTerm,
-
 
554
                            @RequestParam(name = "page", defaultValue = "0") int page,
-
 
555
                            @RequestParam(name = "pageSize", defaultValue = "25") int pageSize,
-
 
556
                            @RequestParam(name = "search", required = false) String searchText,
-
 
557
                            Model model) throws ProfitMandiBusinessException {
-
 
558
        populateMyTicketModel(request, sortOrder, ticketStatus, ticketSearchType, searchTerm, page, pageSize, searchText, model);
-
 
559
        return "ticket";
-
 
560
    }
-
 
561
 
-
 
562
    @GetMapping(value = "/cs/myticket-content")
-
 
563
    public String getTicketContent(HttpServletRequest request,
-
 
564
                                   @RequestParam(name = "orderby", defaultValue = "DESCENDING") SortOrder sortOrder,
-
 
565
                                   @RequestParam(name = "ticketStatus", defaultValue = "OPENED") TicketStatus ticketStatus,
-
 
566
                                   @RequestParam(name = "ticketSearchType", defaultValue = "") TicketSearchType ticketSearchType,
-
 
567
                                   @RequestParam(name = "searchTerm", defaultValue = "0") int searchTerm,
-
 
568
                                   @RequestParam(name = "page", defaultValue = "0") int page,
-
 
569
                                   @RequestParam(name = "pageSize", defaultValue = "25") int pageSize,
-
 
570
                                   @RequestParam(name = "search", required = false) String searchText,
-
 
571
                                   Model model) throws ProfitMandiBusinessException {
-
 
572
        populateMyTicketModel(request, sortOrder, ticketStatus, ticketSearchType, searchTerm, page, pageSize, searchText, model);
-
 
573
        return "ticket-content";
-
 
574
    }
-
 
575
 
538
    public String getTicket(HttpServletRequest request, @RequestParam(name = "orderby", defaultValue = "DESCENDING") SortOrder sortOrder, @RequestParam(name = "ticketStatus", defaultValue = "OPENED") TicketStatus ticketStatus, @RequestParam(name = "ticketSearchType", defaultValue = "") TicketSearchType ticketSearchType, @RequestParam(name = "searchTerm", defaultValue = "0") int searchTerm, Model model) throws ProfitMandiBusinessException {
576
    private void populateMyTicketModel(HttpServletRequest request, SortOrder sortOrder, TicketStatus ticketStatus,
-
 
577
                                       TicketSearchType ticketSearchType, int searchTerm, int page, int pageSize,
-
 
578
                                       String searchText, Model model) throws ProfitMandiBusinessException {
539
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
579
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
540
        List<Ticket> tickets = null;
580
        List<Ticket> tickets = null;
541
        List<TicketAssigned> ticketAssigneds = null;
581
        List<TicketAssigned> ticketAssigneds = null;
542
        long size = 0;
582
        long totalRecords = 0;
543
        Map<Integer, AuthUser> authUserIdAndAuthUserMap = null;
583
        Map<Integer, AuthUser> authUserIdAndAuthUserMap = null;
544
        boolean isAdmin = roleManager.isAdmin(new HashSet<>(loginDetails.getRoleIds()));
584
        boolean isAdmin = roleManager.isAdmin(new HashSet<>(loginDetails.getRoleIds()));
545
        AuthUser currentAuthUser = isAdmin ? authRepository.selectByEmailOrMobile(loginDetails.getEmailId()) : null;
585
        AuthUser currentAuthUser = isAdmin ? authRepository.selectByEmailOrMobile(loginDetails.getEmailId()) : null;
546
 
586
 
547
        // Check if user is CRM category - CRM users see ALL tickets to handle partner communications
-
 
548
        boolean isCrmUser = isAdmin && currentAuthUser != null && positionRepository.hasCategory(currentAuthUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_CRM);
587
        boolean isCrmUser = isAdmin && currentAuthUser != null && positionRepository.hasCategory(currentAuthUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_CRM);
549
        // Check if user is Sales category - Sales users can resolve their own Sales tickets
-
 
550
        boolean isSalesUser = isAdmin && currentAuthUser != null && positionRepository.hasCategory(currentAuthUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_SALES);
588
        boolean isSalesUser = isAdmin && currentAuthUser != null && positionRepository.hasCategory(currentAuthUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_SALES);
551
        // Check if user is RBM category - RBM users can resolve their own RBM tickets
-
 
552
        boolean isRbmUser = isAdmin && currentAuthUser != null && positionRepository.hasCategory(currentAuthUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_RBM);
589
        boolean isRbmUser = isAdmin && currentAuthUser != null && positionRepository.hasCategory(currentAuthUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_RBM);
553
 
590
 
-
 
591
        List<Integer> userCategoryIds = isAdmin && currentAuthUser != null
-
 
592
                ? positionRepository.selectCategoryIdsByAuthUserId(currentAuthUser.getId())
-
 
593
                : Collections.emptyList();
-
 
594
 
-
 
595
        int offset = page * pageSize;
-
 
596
 
554
        if (isAdmin) {
597
        if (isAdmin) {
555
            int authUserId = currentAuthUser.getId();
598
            int authUserId = currentAuthUser.getId();
556
 
599
 
557
            if (isCrmUser) {
600
            if (isCrmUser) {
558
                // CRM users see ALL tickets EXCEPT Sales Escalation and RBM Escalation subcategories
601
                Optional<Boolean> resolvedOpt = ticketStatus.equals(TicketStatus.RESOLVED) ? Optional.empty() : Optional.of(TicketStatus.CLOSED.equals(ticketStatus));
559
                if (ticketStatus.equals(TicketStatus.RESOLVED)) {
602
                tickets = ticketRepository.selectAllTicketsPaginated(
560
                    tickets = ticketRepository.selectAllTickets(Optional.empty(), sortOrder, ticketSearchType, searchTerm);
603
                        resolvedOpt, sortOrder, ticketSearchType, searchTerm, searchText,
561
                } else {
-
 
562
                    tickets = ticketRepository.selectAllTickets(Optional.of(TicketStatus.CLOSED.equals(ticketStatus)), sortOrder, ticketSearchType, searchTerm);
-
 
563
                }
-
 
564
 
-
 
565
                // Filter out invisible subcategory tickets for CRM users
604
                        userCategoryIds, offset, pageSize);
566
                Map<Integer, TicketSubCategory> subCategoryMap = ticketSubCategoryRepository.getTicketSubCategoryMap();
-
 
567
                tickets = tickets.stream()
605
                totalRecords = ticketRepository.selectAllTicketsPaginatedCount(
568
                        .filter(t -> {
-
 
569
                            TicketSubCategory subCategory = subCategoryMap.get(t.getSubCategoryId());
606
                        resolvedOpt, ticketSearchType, searchTerm, searchText, userCategoryIds);
570
                            return subCategory != null && subCategory.isVisibility();
-
 
571
                        })
-
 
572
                        .collect(Collectors.toList());
-
 
573
                size = tickets.size();
-
 
574
            } else {
607
            } else {
575
                // Non-CRM admins see only tickets assigned to them
-
 
576
                if (ticketSearchType == null) {
-
 
577
                    if (ticketStatus.equals(TicketStatus.RESOLVED)) {
-
 
578
                        tickets = ticketRepository.selectAllByAssignee(authUserId, Optional.empty(), sortOrder, null, searchTerm);
-
 
579
                        size = ticketRepository.selectAllCountByAssignee(authUserId, Optional.empty(), null, searchTerm);
-
 
580
                    } else {
-
 
581
                        tickets = ticketRepository.selectAllByAssignee(authUserId, Optional.of(TicketStatus.CLOSED.equals(ticketStatus)), sortOrder, null, searchTerm);
-
 
582
                        size = ticketRepository.selectAllCountByAssignee(authUserId, Optional.of(TicketStatus.CLOSED.equals(ticketStatus)), null, searchTerm);
608
                Optional<Boolean> resolvedOpt = ticketStatus.equals(TicketStatus.RESOLVED) ? Optional.empty() : Optional.of(TicketStatus.CLOSED.equals(ticketStatus));
583
                    }
-
 
584
                } else {
-
 
585
                    if (ticketStatus.equals(TicketStatus.RESOLVED)) {
609
                tickets = ticketRepository.selectAllByAssigneePaginated(
586
                        tickets = ticketRepository.selectAllByAssignee(authUserId, Optional.empty(), sortOrder, ticketSearchType, searchTerm);
610
                        authUserId, resolvedOpt, sortOrder, ticketSearchType, searchTerm, searchText,
587
                        size = ticketRepository.selectAllCountByAssignee(authUserId, Optional.empty(), ticketSearchType, searchTerm);
-
 
588
                    } else {
611
                        offset, pageSize);
589
                        tickets = ticketRepository.selectAllByAssignee(authUserId, Optional.of(TicketStatus.CLOSED.equals(ticketStatus)), sortOrder, ticketSearchType, searchTerm);
612
                totalRecords = ticketRepository.selectAllByAssigneePaginatedCount(
590
                        size = ticketRepository.selectAllCountByAssignee(authUserId, Optional.of(TicketStatus.CLOSED.equals(ticketStatus)), ticketSearchType, searchTerm);
613
                        authUserId, resolvedOpt, ticketSearchType, searchTerm, searchText);
591
                    }
-
 
592
                }
-
 
593
            }
614
            }
594
            // LOGGER.info(size + "size");
-
 
-
 
615
 
595
            if (tickets.size() > 0) {
616
            if (tickets.size() > 0) {
596
                ticketAssigneds = ticketAssignedRepository.selectByTicketIds(tickets.stream().map(x -> x.getId()).collect(Collectors.toList()));
617
                ticketAssigneds = ticketAssignedRepository.selectByTicketIds(tickets.stream().map(x -> x.getId()).collect(Collectors.toList()));
597
                authUserIdAndAuthUserMap = csService.getAuthUserIdAndAuthUserMap(ticketAssigneds);
618
                authUserIdAndAuthUserMap = csService.getAuthUserIdAndAuthUserMap(ticketAssigneds);
598
                Map<Integer, CustomRetailer> fofoIdsAndCustomRetailer = csService.getPartnerByFofoIds(tickets);
619
                Map<Integer, CustomRetailer> fofoIdsAndCustomRetailer = csService.getPartnerByFofoIds(tickets);
599
                model.addAttribute("fofoIdsAndCustomRetailer", fofoIdsAndCustomRetailer);
620
                model.addAttribute("fofoIdsAndCustomRetailer", fofoIdsAndCustomRetailer);
600
            }
621
            }
601
 
622
 
602
        } else {
623
        } else {
603
            tickets = ticketRepository.selectAllByCreator(loginDetails.getFofoId(), Optional.of(TicketStatus.OPENED.equals(ticketStatus)), sortOrder);
624
            tickets = ticketRepository.selectAllByCreator(loginDetails.getFofoId(), Optional.of(TicketStatus.OPENED.equals(ticketStatus)), sortOrder);
604
            size = ticketRepository.selectAllCountByCreator(loginDetails.getFofoId(), Optional.of(TicketStatus.OPENED.equals(ticketStatus)));
625
            totalRecords = ticketRepository.selectAllCountByCreator(loginDetails.getFofoId(), Optional.of(TicketStatus.OPENED.equals(ticketStatus)));
605
        }
626
        }
606
        authUserIdAndAuthUserMap = csService.getTicketIdAndAuthUserMapUsingTickets(tickets);
627
        authUserIdAndAuthUserMap = csService.getTicketIdAndAuthUserMapUsingTickets(tickets);
607
        if (authUserIdAndAuthUserMap == null) {
628
        if (authUserIdAndAuthUserMap == null) {
608
            authUserIdAndAuthUserMap = new HashMap<>();
629
            authUserIdAndAuthUserMap = new HashMap<>();
609
        }
630
        }
610
 
631
 
-
 
632
        int totalPages = (int) Math.ceil((double) totalRecords / pageSize);
-
 
633
        if (totalPages == 0) totalPages = 1;
-
 
634
        int startRecord = totalRecords > 0 ? offset + 1 : 0;
-
 
635
        int endRecord = (int) Math.min(offset + pageSize, totalRecords);
-
 
636
 
-
 
637
        model.addAttribute("size", totalRecords);
-
 
638
        model.addAttribute("totalRecords", totalRecords);
-
 
639
        model.addAttribute("currentPage", page);
611
        model.addAttribute("size", size);
640
        model.addAttribute("pageSize", pageSize);
-
 
641
        model.addAttribute("totalPages", totalPages);
-
 
642
        model.addAttribute("startRecord", startRecord);
-
 
643
        model.addAttribute("endRecord", endRecord);
-
 
644
        model.addAttribute("searchText", searchText != null ? searchText : "");
-
 
645
        model.addAttribute("currentPageDisplay", page + 1);
-
 
646
        model.addAttribute("prevPage", page - 1);
-
 
647
        model.addAttribute("nextPage", page + 1);
-
 
648
        model.addAttribute("lastPage", totalPages - 1);
-
 
649
 
612
        model.addAttribute("roleType", isAdmin);
650
        model.addAttribute("roleType", isAdmin);
613
        // isCrmUser already calculated at start of method
-
 
614
        model.addAttribute("isCrmUser", isCrmUser);
651
        model.addAttribute("isCrmUser", isCrmUser);
615
        model.addAttribute("isSalesUser", isSalesUser);
652
        model.addAttribute("isSalesUser", isSalesUser);
616
        model.addAttribute("salesCategoryId", ProfitMandiConstants.TICKET_CATEGORY_SALES);
653
        model.addAttribute("salesCategoryId", ProfitMandiConstants.TICKET_CATEGORY_SALES);
617
        model.addAttribute("isRbmUser", isRbmUser);
654
        model.addAttribute("isRbmUser", isRbmUser);
618
        model.addAttribute("rbmCategoryId", ProfitMandiConstants.TICKET_CATEGORY_RBM);
655
        model.addAttribute("rbmCategoryId", ProfitMandiConstants.TICKET_CATEGORY_RBM);
-
 
656
        model.addAttribute("userCategoryIds", userCategoryIds);
619
 
657
 
620
        List<Integer> subCategoryIds = tickets.stream().map(x -> x.getSubCategoryId()).collect(Collectors.toList());
658
        List<Integer> subCategoryIds = tickets.stream().map(x -> x.getSubCategoryId()).collect(Collectors.toList());
621
        Map<Integer, TicketSubCategory> subCategoryIdAndSubCategoryMap = csService.getSubCategoryIdAndSubCategoryMap(subCategoryIds);
659
        Map<Integer, TicketSubCategory> subCategoryIdAndSubCategoryMap = csService.getSubCategoryIdAndSubCategoryMap(subCategoryIds);
622
        if (subCategoryIdAndSubCategoryMap == null) {
660
        if (subCategoryIdAndSubCategoryMap == null) {
623
            subCategoryIdAndSubCategoryMap = new HashMap<>();
661
            subCategoryIdAndSubCategoryMap = new HashMap<>();
Line 633... Line 671...
633
        Map<Integer, List<Activity>> activityMap = new HashMap<>();
671
        Map<Integer, List<Activity>> activityMap = new HashMap<>();
634
        Map<Integer, List<Activity>> activityMapWithActivityId = new HashMap<>();
672
        Map<Integer, List<Activity>> activityMapWithActivityId = new HashMap<>();
635
        Map<Integer, AuthUser> authUserMap = new HashMap<>();
673
        Map<Integer, AuthUser> authUserMap = new HashMap<>();
636
 
674
 
637
        if (!ticketIds.isEmpty()) {
675
        if (!ticketIds.isEmpty()) {
638
            // Fetch activities once and group by both ticketId and activityId
-
 
639
            List<Activity> allActivities = activityRepository.selectAll(ticketIds);
676
            List<Activity> allActivities = activityRepository.selectAll(ticketIds);
640
            activityMap = allActivities.stream().collect(Collectors.groupingBy(Activity::getTicketId));
677
            activityMap = allActivities.stream().collect(Collectors.groupingBy(Activity::getTicketId));
641
            activityMapWithActivityId = allActivities.stream().collect(Collectors.groupingBy(Activity::getId));
678
            activityMapWithActivityId = allActivities.stream().collect(Collectors.groupingBy(Activity::getId));
642
 
679
 
643
            // Only fetch AuthUsers who created activities (instead of all users)
-
 
644
            Set<Integer> activityCreatorIds = allActivities.stream()
680
            Set<Integer> activityCreatorIds = allActivities.stream()
645
                    .map(Activity::getCreatedBy)
681
                    .map(Activity::getCreatedBy)
646
                    .filter(id -> id > 0)
682
                    .filter(id -> id > 0)
647
                    .collect(Collectors.toSet());
683
                    .collect(Collectors.toSet());
648
            if (!activityCreatorIds.isEmpty()) {
684
            if (!activityCreatorIds.isEmpty()) {
649
                authUserMap = authRepository.selectByIds(new ArrayList<>(activityCreatorIds))
685
                authUserMap = authRepository.selectByIds(new ArrayList<>(activityCreatorIds))
650
                        .stream().collect(Collectors.toMap(AuthUser::getId, x -> x));
686
                        .stream().collect(Collectors.toMap(AuthUser::getId, x -> x));
651
            }
687
            }
652
        }
688
        }
653
 
689
 
-
 
690
        int currentUserId;
-
 
691
        UserType currentUserType;
-
 
692
        if (isAdmin) {
-
 
693
            currentUserId = currentAuthUser.getId();
-
 
694
            currentUserType = UserType.AUTH_USER;
-
 
695
        } else {
-
 
696
            currentUserId = loginDetails.getFofoId();
-
 
697
            currentUserType = UserType.PARTNER;
-
 
698
        }
-
 
699
        Map<Integer, Boolean> unreadMap = csService.getUnreadStatusForTickets(tickets, currentUserId, currentUserType);
-
 
700
        Map<Integer, Activity> lastActivityMap = csService.getLastActivitiesForTickets(ticketIds);
-
 
701
        model.addAttribute("unreadMap", unreadMap);
-
 
702
        model.addAttribute("lastActivityMap", lastActivityMap);
-
 
703
 
654
        model.addAttribute("tickets", tickets);
704
        model.addAttribute("tickets", tickets);
655
        model.addAttribute("resolved", ActivityType.RESOLVED);
705
        model.addAttribute("resolved", ActivityType.RESOLVED);
656
        model.addAttribute("resolved-accepted", ActivityType.RESOLVED_ACCEPTED);
706
        model.addAttribute("resolved-accepted", ActivityType.RESOLVED_ACCEPTED);
657
        model.addAttribute("resolved-rejected", ActivityType.RESOLVED_REJECTED);
707
        model.addAttribute("resolved-rejected", ActivityType.RESOLVED_REJECTED);
658
        model.addAttribute("authUserIdAndAuthUserMap", authUserIdAndAuthUserMap);
708
        model.addAttribute("authUserIdAndAuthUserMap", authUserIdAndAuthUserMap);
Line 668... Line 718...
668
        model.addAttribute("selectedticketStatus", ticketStatus);
718
        model.addAttribute("selectedticketStatus", ticketStatus);
669
        model.addAttribute("selectedorderby", sortOrder);
719
        model.addAttribute("selectedorderby", sortOrder);
670
        model.addAttribute("ticketSearchTypes", TicketSearchType.values());
720
        model.addAttribute("ticketSearchTypes", TicketSearchType.values());
671
        model.addAttribute("ticketSearchType", ticketSearchType);
721
        model.addAttribute("ticketSearchType", ticketSearchType);
672
        model.addAttribute("searchTerm", searchTerm);
722
        model.addAttribute("searchTerm", searchTerm);
673
        return "ticket";
-
 
674
    }
723
    }
675
 
724
 
676
 
725
 
677
    @GetMapping(value = "/cs/getActivities")
726
    @GetMapping(value = "/cs/getActivities")
678
    public String getActivity(HttpServletRequest request, @RequestParam(name = "ticketId", defaultValue = "0") int ticketId, Model model) throws Exception {
727
    public String getActivity(HttpServletRequest request, @RequestParam(name = "ticketId", defaultValue = "0") int ticketId, Model model) throws Exception {
Line 888... Line 937...
888
        return "response";
937
        return "response";
889
    }
938
    }
890
 
939
 
891
    @GetMapping(value = "/cs/myPartyTicketTicket")
940
    @GetMapping(value = "/cs/myPartyTicketTicket")
892
    public String getMyPartyTicketTicket(HttpServletRequest request, @RequestParam(name = "orderby", defaultValue = "DESCENDING") SortOrder sortOrder, @RequestParam(name = "ticketStatus", defaultValue = "OPENED") TicketStatus ticketStatus, @RequestParam(name = "ticketSearchType", defaultValue = "") TicketSearchType ticketSearchType, @RequestParam(name = "searchTerm", defaultValue = "0") int searchTerm, Model model) throws ProfitMandiBusinessException {
941
    public String getMyPartyTicketTicket(HttpServletRequest request, @RequestParam(name = "orderby", defaultValue = "DESCENDING") SortOrder sortOrder, @RequestParam(name = "ticketStatus", defaultValue = "OPENED") TicketStatus ticketStatus, @RequestParam(name = "ticketSearchType", defaultValue = "") TicketSearchType ticketSearchType, @RequestParam(name = "searchTerm", defaultValue = "0") int searchTerm, Model model) throws ProfitMandiBusinessException {
-
 
942
        populateMyPartnerTicketModel(request, sortOrder, ticketStatus, ticketSearchType, searchTerm, model);
-
 
943
        return "my-partner-tickets";
-
 
944
    }
-
 
945
 
-
 
946
    @GetMapping(value = "/cs/myPartyTicket-content")
-
 
947
    public String getMyPartyTicketContent(HttpServletRequest request,
-
 
948
                                          @RequestParam(name = "orderby", defaultValue = "DESCENDING") SortOrder sortOrder,
-
 
949
                                          @RequestParam(name = "ticketStatus", defaultValue = "OPENED") TicketStatus ticketStatus,
-
 
950
                                          @RequestParam(name = "ticketSearchType", defaultValue = "") TicketSearchType ticketSearchType,
-
 
951
                                          @RequestParam(name = "searchTerm", defaultValue = "0") int searchTerm,
-
 
952
                                          Model model) throws ProfitMandiBusinessException {
-
 
953
        populateMyPartnerTicketModel(request, sortOrder, ticketStatus, ticketSearchType, searchTerm, model);
-
 
954
        return "my-partner-tickets-content";
-
 
955
    }
-
 
956
 
-
 
957
    private void populateMyPartnerTicketModel(HttpServletRequest request, SortOrder sortOrder, TicketStatus ticketStatus,
-
 
958
                                              TicketSearchType ticketSearchType, int searchTerm, Model model) throws ProfitMandiBusinessException {
893
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
959
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
894
        long size = 0;
-
 
895
        AuthUser authUser = authRepository.selectByEmailOrMobile(loginDetails.getEmailId());
960
        AuthUser authUser = authRepository.selectByEmailOrMobile(loginDetails.getEmailId());
896
        List<Ticket> tickets = new ArrayList<>();
961
        List<Ticket> tickets = new ArrayList<>();
897
        Map<String, Set<Integer>> storeGuyMap = csService.getAuthUserPartnerIdMapping();
962
        Map<String, Set<Integer>> storeGuyMap = csService.getAuthUserPartnerIdMapping();
898
        Set<Integer> fofoIds = storeGuyMap.get(authUser.getEmailId());
963
        Set<Integer> fofoIds = storeGuyMap.get(authUser.getEmailId());
899
 
964
 
900
        Map<Integer, List<AuthUser>> authUserListMap = null;
965
        Map<Integer, List<AuthUser>> authUserListMap = null;
901
        if (fofoIds != null && !fofoIds.isEmpty()) {
966
        if (fofoIds != null && !fofoIds.isEmpty()) {
902
            // Batch fetch all open tickets for all fofoIds (fix N+1 query)
-
 
903
            List<Ticket> allPartnerTickets = ticketRepository.selectAllOpenTickets(new ArrayList<>(fofoIds));
967
            List<Ticket> allPartnerTickets = ticketRepository.selectAllOpenTickets(new ArrayList<>(fofoIds));
904
            if (allPartnerTickets != null && !allPartnerTickets.isEmpty()) {
968
            if (allPartnerTickets != null && !allPartnerTickets.isEmpty()) {
905
                // Filter tickets where last_activity is not "RESOLVED"
-
 
906
                tickets = allPartnerTickets.stream()
969
                tickets = allPartnerTickets.stream()
907
                        .filter(ticket -> ticket.getLastActivity() == null ||
970
                        .filter(ticket -> ticket.getLastActivity() == null ||
908
                                ticket.getLastActivity() != ActivityType.RESOLVED)
971
                                ticket.getLastActivity() != ActivityType.RESOLVED)
909
                        .collect(Collectors.toList());
972
                        .collect(Collectors.toList());
910
            }
973
            }
911
        }
974
        }
912
 
975
 
913
        authUserListMap = csService.getAssignedAuthList(tickets);
976
        authUserListMap = csService.getAssignedAuthList(tickets);
914
 
977
 
915
 
-
 
916
        if (tickets.size() > 0) {
978
        if (tickets.size() > 0) {
917
            Map<Integer, CustomRetailer> fofoIdsAndCustomRetailer = csService.getPartnerByFofoIds(tickets);
979
            Map<Integer, CustomRetailer> fofoIdsAndCustomRetailer = csService.getPartnerByFofoIds(tickets);
918
            model.addAttribute("fofoIdsAndCustomRetailer", fofoIdsAndCustomRetailer);
980
            model.addAttribute("fofoIdsAndCustomRetailer", fofoIdsAndCustomRetailer);
919
        }
981
        }
920
 
982
 
-
 
983
        // Pagination for partner tickets (in-memory since selectAllOpenTickets doesn't support DB-level pagination)
-
 
984
        long totalRecords = tickets.size();
-
 
985
        int totalPages = totalRecords > 0 ? (int) Math.ceil((double) totalRecords / 25) : 1;
-
 
986
        model.addAttribute("totalRecords", totalRecords);
-
 
987
        model.addAttribute("currentPage", 0);
-
 
988
        model.addAttribute("pageSize", 25);
-
 
989
        model.addAttribute("totalPages", totalPages);
-
 
990
        model.addAttribute("startRecord", totalRecords > 0 ? 1 : 0);
-
 
991
        model.addAttribute("endRecord", totalRecords);
-
 
992
        model.addAttribute("currentPageDisplay", 1);
-
 
993
        model.addAttribute("prevPage", 0);
-
 
994
        model.addAttribute("nextPage", 1);
-
 
995
        model.addAttribute("lastPage", totalPages - 1);
-
 
996
 
921
        model.addAttribute("size", tickets.size());
997
        model.addAttribute("size", tickets.size());
922
        model.addAttribute("tickets", tickets);
998
        model.addAttribute("tickets", tickets);
923
 
999
 
924
        List<Integer> subCategoryIds = tickets.stream().map(x -> x.getSubCategoryId()).collect(Collectors.toList());
1000
        List<Integer> subCategoryIds = tickets.stream().map(x -> x.getSubCategoryId()).collect(Collectors.toList());
925
        Map<Integer, TicketSubCategory> subCategoryIdAndSubCategoryMap = csService.getSubCategoryIdAndSubCategoryMap(subCategoryIds);
1001
        Map<Integer, TicketSubCategory> subCategoryIdAndSubCategoryMap = csService.getSubCategoryIdAndSubCategoryMap(subCategoryIds);
Line 936... Line 1012...
936
        Map<Integer, List<Activity>> activityMap = new HashMap<>();
1012
        Map<Integer, List<Activity>> activityMap = new HashMap<>();
937
        Map<Integer, List<Activity>> activityMapWithActivityId = new HashMap<>();
1013
        Map<Integer, List<Activity>> activityMapWithActivityId = new HashMap<>();
938
        Map<Integer, AuthUser> authUserMap = new HashMap<>();
1014
        Map<Integer, AuthUser> authUserMap = new HashMap<>();
939
 
1015
 
940
        if (!ticketIds.isEmpty()) {
1016
        if (!ticketIds.isEmpty()) {
941
            // Fetch activities once and group by both ticketId and activityId
-
 
942
            List<Activity> allActivities = activityRepository.selectAll(ticketIds);
1017
            List<Activity> allActivities = activityRepository.selectAll(ticketIds);
943
            activityMap = allActivities.stream().collect(Collectors.groupingBy(Activity::getTicketId));
1018
            activityMap = allActivities.stream().collect(Collectors.groupingBy(Activity::getTicketId));
944
            activityMapWithActivityId = allActivities.stream().collect(Collectors.groupingBy(Activity::getId));
1019
            activityMapWithActivityId = allActivities.stream().collect(Collectors.groupingBy(Activity::getId));
945
 
1020
 
946
            // Only fetch AuthUsers who created activities (instead of all users)
-
 
947
            Set<Integer> activityCreatorIds = allActivities.stream()
1021
            Set<Integer> activityCreatorIds = allActivities.stream()
948
                    .map(Activity::getCreatedBy)
1022
                    .map(Activity::getCreatedBy)
949
                    .filter(id -> id > 0)
1023
                    .filter(id -> id > 0)
950
                    .collect(Collectors.toSet());
1024
                    .collect(Collectors.toSet());
951
            if (!activityCreatorIds.isEmpty()) {
1025
            if (!activityCreatorIds.isEmpty()) {
952
                authUserMap = authRepository.selectByIds(new ArrayList<>(activityCreatorIds))
1026
                authUserMap = authRepository.selectByIds(new ArrayList<>(activityCreatorIds))
953
                        .stream().collect(Collectors.toMap(AuthUser::getId, x -> x));
1027
                        .stream().collect(Collectors.toMap(AuthUser::getId, x -> x));
954
            }
1028
            }
955
        }
1029
        }
956
 
1030
 
-
 
1031
        Map<Integer, Boolean> unreadMap = csService.getUnreadStatusForTickets(tickets, authUser.getId(), UserType.AUTH_USER);
-
 
1032
        Map<Integer, Activity> lastActivityMap = csService.getLastActivitiesForTickets(
-
 
1033
                tickets.stream().map(Ticket::getId).collect(Collectors.toList()));
-
 
1034
        model.addAttribute("unreadMap", unreadMap);
-
 
1035
        model.addAttribute("lastActivityMap", lastActivityMap);
-
 
1036
 
957
        model.addAttribute("ticketStatusValues", TicketStatus.values());
1037
        model.addAttribute("ticketStatusValues", TicketStatus.values());
958
        model.addAttribute("orderByValues", SortOrder.values());
1038
        model.addAttribute("orderByValues", SortOrder.values());
959
        model.addAttribute("selectedticketStatus", ticketStatus);
1039
        model.addAttribute("selectedticketStatus", ticketStatus);
960
        model.addAttribute("selectedorderby", sortOrder);
1040
        model.addAttribute("selectedorderby", sortOrder);
961
        model.addAttribute("tickets", tickets);
-
 
962
        model.addAttribute("ticketSearchTypes", TicketSearchType.values());
1041
        model.addAttribute("ticketSearchTypes", TicketSearchType.values());
963
        model.addAttribute("ticketSearchType", ticketSearchType);
1042
        model.addAttribute("ticketSearchType", ticketSearchType);
964
        model.addAttribute("searchTerm", searchTerm);
1043
        model.addAttribute("searchTerm", searchTerm);
965
        model.addAttribute("authUserListMap", authUserListMap != null ? authUserListMap : new HashMap<>());
1044
        model.addAttribute("authUserListMap", authUserListMap != null ? authUserListMap : new HashMap<>());
966
        model.addAttribute("subCategoryIdAndSubCategoryMap", subCategoryIdAndSubCategoryMap);
1045
        model.addAttribute("subCategoryIdAndSubCategoryMap", subCategoryIdAndSubCategoryMap);
Line 968... Line 1047...
968
        model.addAttribute("subCategoryIdAndCategoryMap", subCategoryIdAndCategoryMap);
1047
        model.addAttribute("subCategoryIdAndCategoryMap", subCategoryIdAndCategoryMap);
969
 
1048
 
970
        model.addAttribute("activityMap", activityMap);
1049
        model.addAttribute("activityMap", activityMap);
971
        model.addAttribute("authUserMap", authUserMap);
1050
        model.addAttribute("authUserMap", authUserMap);
972
        model.addAttribute("activityMapWithActivityId", activityMapWithActivityId);
1051
        model.addAttribute("activityMapWithActivityId", activityMapWithActivityId);
973
        // Check if user is in CRM category (only CRM can send external communications)
-
 
974
        boolean isCrmUser = positionRepository.hasCategory(authUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_CRM);
1052
        boolean isCrmUser = positionRepository.hasCategory(authUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_CRM);
975
        model.addAttribute("isCrmUser", isCrmUser);
1053
        model.addAttribute("isCrmUser", isCrmUser);
976
 
-
 
977
        return "my-partner-tickets";
-
 
978
    }
1054
    }
979
 
1055
 
980
    @GetMapping(value = "/cs/managerTicket")
1056
    @GetMapping(value = "/cs/managerTicket")
-
 
1057
    public String getManagerTickets(HttpServletRequest request,
-
 
1058
                                    @RequestParam(name = "orderby", defaultValue = "DESCENDING") SortOrder sortOrder,
-
 
1059
                                    @RequestParam(name = "ticketStatus", defaultValue = "OPENED") TicketStatus ticketStatus,
-
 
1060
                                    @RequestParam(name = "ticketSearchType", defaultValue = "") TicketSearchType ticketSearchType,
-
 
1061
                                    @RequestParam(name = "searchTerm", defaultValue = "0") int searchTerm,
-
 
1062
                                    @RequestParam(name = "page", defaultValue = "0") int page,
-
 
1063
                                    @RequestParam(name = "pageSize", defaultValue = "25") int pageSize,
-
 
1064
                                    @RequestParam(name = "search", required = false) String searchText,
-
 
1065
                                    Model model) throws ProfitMandiBusinessException {
-
 
1066
        populateManagerTicketModel(request, sortOrder, ticketStatus, ticketSearchType, searchTerm, page, pageSize, searchText, model);
-
 
1067
        return "managerTicket";
-
 
1068
    }
-
 
1069
 
-
 
1070
    @GetMapping(value = "/cs/managerTicket-content")
-
 
1071
    public String getManagerTicketContent(HttpServletRequest request,
-
 
1072
                                          @RequestParam(name = "orderby", defaultValue = "DESCENDING") SortOrder sortOrder,
-
 
1073
                                          @RequestParam(name = "ticketStatus", defaultValue = "OPENED") TicketStatus ticketStatus,
-
 
1074
                                          @RequestParam(name = "ticketSearchType", defaultValue = "") TicketSearchType ticketSearchType,
-
 
1075
                                          @RequestParam(name = "searchTerm", defaultValue = "0") int searchTerm,
-
 
1076
                                          @RequestParam(name = "page", defaultValue = "0") int page,
-
 
1077
                                          @RequestParam(name = "pageSize", defaultValue = "25") int pageSize,
-
 
1078
                                          @RequestParam(name = "search", required = false) String searchText,
-
 
1079
                                          Model model) throws ProfitMandiBusinessException {
-
 
1080
        populateManagerTicketModel(request, sortOrder, ticketStatus, ticketSearchType, searchTerm, page, pageSize, searchText, model);
-
 
1081
        return "managerTicket-content";
-
 
1082
    }
-
 
1083
 
981
    public String getManagerTickets(HttpServletRequest request, @RequestParam(name = "orderby", defaultValue = "DESCENDING") SortOrder sortOrder, @RequestParam(name = "ticketStatus", defaultValue = "OPENED") TicketStatus ticketStatus, @RequestParam(name = "ticketSearchType", defaultValue = "") TicketSearchType ticketSearchType, @RequestParam(name = "searchTerm", defaultValue = "0") int searchTerm, Model model) throws ProfitMandiBusinessException {
1084
    private void populateManagerTicketModel(HttpServletRequest request, SortOrder sortOrder, TicketStatus ticketStatus,
-
 
1085
                                            TicketSearchType ticketSearchType, int searchTerm, int page, int pageSize,
-
 
1086
                                            String searchText, Model model) throws ProfitMandiBusinessException {
982
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
1087
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
983
        long size = 0;
1088
        long totalRecords = 0;
984
        AuthUser authUser = authRepository.selectByEmailOrMobile(loginDetails.getEmailId());
1089
        AuthUser authUser = authRepository.selectByEmailOrMobile(loginDetails.getEmailId());
-
 
1090
 
-
 
1091
        // Block L1-only users from accessing manager tickets
-
 
1092
        List<Position> positions = positionRepository.selectAllByAuthUserId(authUser.getId());
-
 
1093
        boolean isAboveL1 = positions.stream().anyMatch(pos -> pos.getEscalationType() != EscalationType.L1);
-
 
1094
        if (!isAboveL1) {
-
 
1095
            throw new ProfitMandiBusinessException("ManagerTicket", 0, "Access denied: requires at least L2 position");
-
 
1096
        }
-
 
1097
 
985
        boolean isCrmUser = positionRepository.hasCategory(authUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_CRM);
1098
        boolean isCrmUser = positionRepository.hasCategory(authUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_CRM);
986
 
1099
 
-
 
1100
        List<Integer> userCategoryIds = positionRepository.selectCategoryIdsByAuthUserId(authUser.getId());
-
 
1101
 
987
        List<Ticket> tickets = null;
1102
        List<Ticket> tickets = null;
988
        Map<Integer, List<AuthUser>> authUserListMap = null;
1103
        Map<Integer, List<AuthUser>> authUserListMap = null;
989
 
1104
 
990
        // CRM users can see all tickets to assign them (like managers)
1105
        int offset = page * pageSize;
-
 
1106
        Optional<Boolean> resolvedOpt = ticketStatus.equals(TicketStatus.RESOLVED) ? Optional.empty() : Optional.of(TicketStatus.CLOSED.equals(ticketStatus));
-
 
1107
 
991
        if (isCrmUser) {
1108
        if (isCrmUser) {
992
            if (ticketStatus.equals(TicketStatus.RESOLVED)) {
-
 
993
                tickets = ticketRepository.selectAllTickets(Optional.empty(), sortOrder, ticketSearchType, searchTerm);
1109
            tickets = ticketRepository.selectAllTicketsPaginated(
994
                size = ticketRepository.selectAllTicketsCount(Optional.empty(), ticketSearchType, searchTerm);
1110
                    resolvedOpt, sortOrder, ticketSearchType, searchTerm, searchText,
995
            } else {
-
 
996
                tickets = ticketRepository.selectAllTickets(Optional.of(TicketStatus.CLOSED.equals(ticketStatus)), sortOrder, ticketSearchType, searchTerm);
-
 
997
                size = ticketRepository.selectAllTicketsCount(Optional.of(TicketStatus.CLOSED.equals(ticketStatus)), ticketSearchType, searchTerm);
-
 
998
            }
-
 
999
        } else if (ticketSearchType == null) {
-
 
1000
            if (ticketStatus.equals(TicketStatus.RESOLVED)) {
1111
                    userCategoryIds, offset, pageSize);
1001
                tickets = ticketRepository.selectAllManagerTicket(authUser.getId(), sortOrder, Optional.empty(), null, searchTerm);
1112
            totalRecords = ticketRepository.selectAllTicketsPaginatedCount(
1002
                size = ticketRepository.selectAllCountByManagerTicket(authUser.getId(), Optional.empty(), null, 0);
1113
                    resolvedOpt, ticketSearchType, searchTerm, searchText, userCategoryIds);
1003
            } else {
-
 
1004
                tickets = ticketRepository.selectAllManagerTicket(authUser.getId(), sortOrder, Optional.of(TicketStatus.CLOSED.equals(ticketStatus)), null, searchTerm);
-
 
1005
                size = ticketRepository.selectAllCountByManagerTicket(authUser.getId(), Optional.of(TicketStatus.CLOSED.equals(ticketStatus)), null, 0);
-
 
1006
            }
-
 
1007
        } else {
1114
        } else {
1008
            if (ticketStatus.equals(TicketStatus.RESOLVED)) {
1115
            tickets = ticketRepository.selectAllManagerTicketPaginated(
1009
                tickets = ticketRepository.selectAllManagerTicket(authUser.getId(), sortOrder, Optional.empty(), ticketSearchType, searchTerm);
1116
                    authUser.getId(), sortOrder, resolvedOpt, ticketSearchType, searchTerm, searchText,
1010
                size = ticketRepository.selectAllCountByManagerTicket(authUser.getId(), Optional.empty(), ticketSearchType, searchTerm);
-
 
1011
            } else {
1117
                    offset, pageSize);
1012
                tickets = ticketRepository.selectAllManagerTicket(authUser.getId(), sortOrder, Optional.of(TicketStatus.CLOSED.equals(ticketStatus)), ticketSearchType, searchTerm);
1118
            totalRecords = ticketRepository.selectAllCountByManagerTicketPaginated(
1013
                size = ticketRepository.selectAllCountByManagerTicket(authUser.getId(), Optional.of(TicketStatus.CLOSED.equals(ticketStatus)), ticketSearchType, searchTerm);
1119
                    authUser.getId(), resolvedOpt, ticketSearchType, searchTerm, searchText);
1014
            }
-
 
1015
 
-
 
1016
        }
1120
        }
1017
        authUserListMap = csService.getAssignedAuthList(tickets);
1121
        authUserListMap = csService.getAssignedAuthList(tickets);
1018
 
1122
 
1019
        if (tickets.size() > 0) {
1123
        if (tickets.size() > 0) {
1020
            Map<Integer, CustomRetailer> fofoIdsAndCustomRetailer = csService.getPartnerByFofoIds(tickets);
1124
            Map<Integer, CustomRetailer> fofoIdsAndCustomRetailer = csService.getPartnerByFofoIds(tickets);
1021
            model.addAttribute("fofoIdsAndCustomRetailer", fofoIdsAndCustomRetailer);
1125
            model.addAttribute("fofoIdsAndCustomRetailer", fofoIdsAndCustomRetailer);
1022
        }
1126
        }
1023
 
1127
 
-
 
1128
        int totalPages = (int) Math.ceil((double) totalRecords / pageSize);
-
 
1129
        if (totalPages == 0) totalPages = 1;
-
 
1130
        int startRecord = totalRecords > 0 ? offset + 1 : 0;
-
 
1131
        int endRecord = (int) Math.min(offset + pageSize, totalRecords);
-
 
1132
 
-
 
1133
        model.addAttribute("size", totalRecords);
-
 
1134
        model.addAttribute("totalRecords", totalRecords);
-
 
1135
        model.addAttribute("currentPage", page);
1024
        model.addAttribute("size", size);
1136
        model.addAttribute("pageSize", pageSize);
-
 
1137
        model.addAttribute("totalPages", totalPages);
-
 
1138
        model.addAttribute("startRecord", startRecord);
-
 
1139
        model.addAttribute("endRecord", endRecord);
-
 
1140
        model.addAttribute("searchText", searchText != null ? searchText : "");
-
 
1141
        model.addAttribute("currentPageDisplay", page + 1);
-
 
1142
        model.addAttribute("prevPage", page - 1);
-
 
1143
        model.addAttribute("nextPage", page + 1);
-
 
1144
        model.addAttribute("lastPage", totalPages - 1);
1025
        model.addAttribute("tickets", tickets);
1145
        model.addAttribute("tickets", tickets);
1026
 
1146
 
1027
        List<Integer> subCategoryIds = tickets.stream().map(x -> x.getSubCategoryId()).collect(Collectors.toList());
1147
        List<Integer> subCategoryIds = tickets.stream().map(x -> x.getSubCategoryId()).collect(Collectors.toList());
1028
        Map<Integer, TicketSubCategory> subCategoryIdAndSubCategoryMap = csService.getSubCategoryIdAndSubCategoryMap(subCategoryIds);
1148
        Map<Integer, TicketSubCategory> subCategoryIdAndSubCategoryMap = csService.getSubCategoryIdAndSubCategoryMap(subCategoryIds);
1029
        if (subCategoryIdAndSubCategoryMap == null) {
1149
        if (subCategoryIdAndSubCategoryMap == null) {
Line 1039... Line 1159...
1039
        Map<Integer, List<Activity>> activityMap = new HashMap<>();
1159
        Map<Integer, List<Activity>> activityMap = new HashMap<>();
1040
        Map<Integer, List<Activity>> activityMapWithActivityId = new HashMap<>();
1160
        Map<Integer, List<Activity>> activityMapWithActivityId = new HashMap<>();
1041
        Map<Integer, AuthUser> authUserMap = new HashMap<>();
1161
        Map<Integer, AuthUser> authUserMap = new HashMap<>();
1042
 
1162
 
1043
        if (!ticketIds.isEmpty()) {
1163
        if (!ticketIds.isEmpty()) {
1044
            // Fetch activities once and reuse for both maps (fix duplicate query)
-
 
1045
            List<Activity> allActivities = activityRepository.selectAll(ticketIds);
1164
            List<Activity> allActivities = activityRepository.selectAll(ticketIds);
1046
            activityMap = allActivities.stream().collect(Collectors.groupingBy(Activity::getTicketId));
1165
            activityMap = allActivities.stream().collect(Collectors.groupingBy(Activity::getTicketId));
1047
            activityMapWithActivityId = allActivities.stream().collect(Collectors.groupingBy(Activity::getId));
1166
            activityMapWithActivityId = allActivities.stream().collect(Collectors.groupingBy(Activity::getId));
1048
 
1167
 
1049
            // Only fetch users who created activities (fix loading ALL users)
-
 
1050
            Set<Integer> activityCreatorIds = allActivities.stream()
1168
            Set<Integer> activityCreatorIds = allActivities.stream()
1051
                    .map(Activity::getCreatedBy)
1169
                    .map(Activity::getCreatedBy)
1052
                    .filter(id -> id > 0)
1170
                    .filter(id -> id > 0)
1053
                    .collect(Collectors.toSet());
1171
                    .collect(Collectors.toSet());
1054
            if (!activityCreatorIds.isEmpty()) {
1172
            if (!activityCreatorIds.isEmpty()) {
1055
                authUserMap = authRepository.selectByIds(new ArrayList<>(activityCreatorIds))
1173
                authUserMap = authRepository.selectByIds(new ArrayList<>(activityCreatorIds))
1056
                        .stream().collect(Collectors.toMap(AuthUser::getId, x -> x));
1174
                        .stream().collect(Collectors.toMap(AuthUser::getId, x -> x));
1057
            }
1175
            }
1058
        }
1176
        }
1059
 
1177
 
-
 
1178
        Map<Integer, Boolean> unreadMap = csService.getUnreadStatusForTickets(tickets, authUser.getId(), UserType.AUTH_USER);
-
 
1179
        Map<Integer, Activity> lastActivityMap = csService.getLastActivitiesForTickets(
-
 
1180
                tickets.stream().map(Ticket::getId).collect(Collectors.toList()));
-
 
1181
        model.addAttribute("unreadMap", unreadMap);
-
 
1182
        model.addAttribute("lastActivityMap", lastActivityMap);
-
 
1183
 
1060
        model.addAttribute("ticketStatusValues", TicketStatus.values());
1184
        model.addAttribute("ticketStatusValues", TicketStatus.values());
1061
        model.addAttribute("orderByValues", SortOrder.values());
1185
        model.addAttribute("orderByValues", SortOrder.values());
1062
        model.addAttribute("selectedticketStatus", ticketStatus);
1186
        model.addAttribute("selectedticketStatus", ticketStatus);
1063
        model.addAttribute("selectedorderby", sortOrder);
1187
        model.addAttribute("selectedorderby", sortOrder);
1064
        model.addAttribute("tickets", tickets);
-
 
1065
        model.addAttribute("ticketSearchTypes", TicketSearchType.values());
1188
        model.addAttribute("ticketSearchTypes", TicketSearchType.values());
1066
        model.addAttribute("ticketSearchType", ticketSearchType);
1189
        model.addAttribute("ticketSearchType", ticketSearchType);
1067
        model.addAttribute("searchTerm", searchTerm);
1190
        model.addAttribute("searchTerm", searchTerm);
1068
        model.addAttribute("authUserListMap", authUserListMap);
1191
        model.addAttribute("authUserListMap", authUserListMap);
1069
        model.addAttribute("subCategoryIdAndSubCategoryMap", subCategoryIdAndSubCategoryMap);
1192
        model.addAttribute("subCategoryIdAndSubCategoryMap", subCategoryIdAndSubCategoryMap);
Line 1072... Line 1195...
1072
 
1195
 
1073
        model.addAttribute("activityMap", activityMap);
1196
        model.addAttribute("activityMap", activityMap);
1074
        model.addAttribute("authUserMap", authUserMap);
1197
        model.addAttribute("authUserMap", authUserMap);
1075
        model.addAttribute("activityMapWithActivityId", activityMapWithActivityId);
1198
        model.addAttribute("activityMapWithActivityId", activityMapWithActivityId);
1076
        model.addAttribute("isCrmUser", isCrmUser);
1199
        model.addAttribute("isCrmUser", isCrmUser);
1077
 
-
 
1078
        return "managerTicket";
-
 
1079
    }
1200
    }
1080
 
1201
 
1081
 
1202
 
1082
    @GetMapping(value = "/cs/edit-ticket")
1203
    @GetMapping(value = "/cs/edit-ticket")
1083
    public String getEditTicket(HttpServletRequest request, @RequestParam(name = "ticketId", defaultValue = "0") int ticketId, Model model) throws ProfitMandiBusinessException {
1204
    public String getEditTicket(HttpServletRequest request, @RequestParam(name = "ticketId", defaultValue = "0") int ticketId, Model model) throws ProfitMandiBusinessException {
1084
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
1205
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
1085
        AuthUser currentAuthUser = authRepository.selectByEmailOrMobile(loginDetails.getEmailId());
1206
        AuthUser currentAuthUser = authRepository.selectByEmailOrMobile(loginDetails.getEmailId());
1086
        boolean isCrmUser = positionRepository.hasCategory(currentAuthUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_CRM);
1207
        boolean isCrmUser = positionRepository.hasCategory(currentAuthUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_CRM);
1087
 
1208
 
1088
        Ticket ticket = ticketRepository.selectById(ticketId);
1209
        Ticket ticket = ticketRepository.selectById(ticketId);
-
 
1210
        if (ticket == null) {
1089
        List<TicketCategory> ticketCategories = csService.getAllTicketCategotyFromSubCategory();
1211
            throw new ProfitMandiBusinessException("Ticket", ticketId, "Ticket not found");
-
 
1212
        }
-
 
1213
 
1090
        TicketSubCategory ticketSubCategory = ticketSubCategoryRepository.selectById(ticket.getSubCategoryId());
1214
        TicketSubCategory ticketSubCategory = ticketSubCategoryRepository.selectById(ticket.getSubCategoryId());
-
 
1215
        int ticketCategoryId = ticketSubCategory.getCategoryId();
-
 
1216
        boolean isVisibleSubCategory = ticketSubCategory.isVisibility();
-
 
1217
 
-
 
1218
        // Check permissions
-
 
1219
        boolean hasPositionInCategory = positionRepository.hasCategory(currentAuthUser.getId(), ticketCategoryId);
-
 
1220
        List<TicketAssigned> assignments = ticketAssignedRepository.selectByTicketIds(Arrays.asList(ticketId));
-
 
1221
        boolean isAssigned = assignments.stream().anyMatch(ta -> ta.getAssineeId() == currentAuthUser.getId() || ta.getManagerId() == currentAuthUser.getId());
-
 
1222
        boolean isInEscalationChain = ticket.getL1AuthUser() == currentAuthUser.getId() ||
-
 
1223
                ticket.getL2AuthUser() == currentAuthUser.getId() ||
-
 
1224
                ticket.getL3AuthUser() == currentAuthUser.getId() ||
-
 
1225
                ticket.getL4AuthUser() == currentAuthUser.getId() ||
-
 
1226
                ticket.getL5AuthUser() == currentAuthUser.getId();
-
 
1227
 
-
 
1228
        boolean canEdit = (isCrmUser && isVisibleSubCategory)
-
 
1229
                || hasPositionInCategory
-
 
1230
                || isAssigned
-
 
1231
                || isInEscalationChain;
-
 
1232
 
-
 
1233
        if (!canEdit) {
-
 
1234
            throw new ProfitMandiBusinessException("Ticket", ticketId, "You do not have permission to edit this ticket");
-
 
1235
        }
-
 
1236
 
-
 
1237
        List<TicketCategory> ticketCategories = csService.getAllTicketCategotyFromSubCategory();
1091
        List<TicketSubCategory> ticketSubCategories = ticketSubCategoryRepository.selectAll(ticketSubCategory.getCategoryId());
1238
        List<TicketSubCategory> ticketSubCategories = ticketSubCategoryRepository.selectAll(ticketSubCategory.getCategoryId());
1092
        List<AuthUser> authUsers = authRepository.selectAllActiveUser();
1239
        List<AuthUser> authUsers = authRepository.selectAllActiveUser();
1093
 
1240
 
1094
        // CRM users should not see invisible subcategories
1241
        // CRM users should not see invisible subcategories
1095
        if (isCrmUser) {
1242
        if (isCrmUser) {
Line 1156... Line 1303...
1156
        Ticket ticket = ticketRepository.selectById(ticketId);
1303
        Ticket ticket = ticketRepository.selectById(ticketId);
1157
        if (ticket == null) {
1304
        if (ticket == null) {
1158
            throw new ProfitMandiBusinessException("Ticket", ticketId, "Ticket not found");
1305
            throw new ProfitMandiBusinessException("Ticket", ticketId, "Ticket not found");
1159
        }
1306
        }
1160
 
1307
 
1161
        // Verify admin has access to this ticket (assigned, manager, escalation chain, or CRM)
1308
        // Verify admin has access to this ticket
1162
        AuthUser currentAuthUser = authRepository.selectByEmailOrMobile(loginDetails.getEmailId());
1309
        AuthUser currentAuthUser = authRepository.selectByEmailOrMobile(loginDetails.getEmailId());
1163
        boolean isCrmUser = positionRepository.hasCategory(currentAuthUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_CRM);
1310
        boolean isCrmUser = positionRepository.hasCategory(currentAuthUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_CRM);
1164
 
1311
 
1165
        if (!isCrmUser) {
-
 
1166
            List<TicketAssigned> assignments = ticketAssignedRepository.selectByTicketIds(Arrays.asList(ticketId));
-
 
1167
            boolean isAssigned = assignments.stream().anyMatch(ta -> ta.getAssineeId() == currentAuthUser.getId() || ta.getManagerId() == currentAuthUser.getId());
-
 
1168
            boolean isInEscalationChain = ticket.getL1AuthUser() == currentAuthUser.getId() ||
-
 
1169
                    ticket.getL2AuthUser() == currentAuthUser.getId() ||
1312
        // Get ticket's subcategory to check visibility
1170
                    ticket.getL3AuthUser() == currentAuthUser.getId() ||
1313
        TicketSubCategory ticketSubCategory = ticketSubCategoryRepository.selectById(ticket.getSubCategoryId());
1171
                    ticket.getL4AuthUser() == currentAuthUser.getId() ||
1314
        int ticketCategoryId = ticketSubCategory.getCategoryId();
1172
                    ticket.getL5AuthUser() == currentAuthUser.getId();
1315
        boolean isVisibleSubCategory = ticketSubCategory.isVisibility();
1173
 
1316
 
-
 
1317
        // Check if user has position in ticket's category
-
 
1318
        boolean hasPositionInCategory = positionRepository.hasCategory(currentAuthUser.getId(), ticketCategoryId);
-
 
1319
 
1174
            if (!isAssigned && !isInEscalationChain) {
1320
        // Check if assigned or in escalation chain
1175
                throw new ProfitMandiBusinessException("Ticket", ticketId, "You do not have permission to edit this ticket");
1321
        List<TicketAssigned> assignments = ticketAssignedRepository.selectByTicketIds(Arrays.asList(ticketId));
-
 
1322
        boolean isAssigned = assignments.stream().anyMatch(ta -> ta.getAssineeId() == currentAuthUser.getId() || ta.getManagerId() == currentAuthUser.getId());
-
 
1323
        boolean isInEscalationChain = ticket.getL1AuthUser() == currentAuthUser.getId() ||
-
 
1324
                ticket.getL2AuthUser() == currentAuthUser.getId() ||
-
 
1325
                ticket.getL3AuthUser() == currentAuthUser.getId() ||
-
 
1326
                ticket.getL4AuthUser() == currentAuthUser.getId() ||
-
 
1327
                ticket.getL5AuthUser() == currentAuthUser.getId();
-
 
1328
 
-
 
1329
        // Permission rules:
-
 
1330
        // 1. CRM user AND ticket has visible subcategory, OR
-
 
1331
        // 2. Has position in ticket's category (can edit even invisible), OR
-
 
1332
        // 3. Is assigned to ticket, OR
-
 
1333
        // 4. Is in escalation chain
-
 
1334
        boolean canEdit = (isCrmUser && isVisibleSubCategory)
-
 
1335
                || hasPositionInCategory
-
 
1336
                || isAssigned
-
 
1337
                || isInEscalationChain;
-
 
1338
 
1176
            }
1339
        if (!canEdit) {
-
 
1340
            throw new ProfitMandiBusinessException("Ticket", ticketId, "You do not have permission to edit this ticket");
1177
        }
1341
        }
1178
 
1342
 
1179
        csService.updateTicket(categoryId, subCategoryId, ticket, authUserId, escalationType);
1343
        csService.updateTicket(categoryId, subCategoryId, ticket, authUserId, escalationType);
1180
        model.addAttribute("response1", mvcResponseSender.createResponseString(true));
1344
        model.addAttribute("response1", mvcResponseSender.createResponseString(true));
1181
        return "response";
1345
        return "response";
Line 1397... Line 1561...
1397
        model.addAttribute("response1", mvcResponseSender.createResponseString(true));
1561
        model.addAttribute("response1", mvcResponseSender.createResponseString(true));
1398
        return "response";
1562
        return "response";
1399
 
1563
 
1400
    }
1564
    }
1401
 
1565
 
-
 
1566
    @PostMapping(value = "/cs/markTicketRead")
-
 
1567
    @ResponseBody
-
 
1568
    public Map<String, Object> markTicketRead(HttpServletRequest request,
-
 
1569
                                              @RequestParam(name = "ticketId") int ticketId,
-
 
1570
                                              Model model) throws ProfitMandiBusinessException {
-
 
1571
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
-
 
1572
        boolean isAdmin = roleManager.isAdmin(loginDetails.getRoleIds());
-
 
1573
        Map<String, Object> response = new HashMap<>();
-
 
1574
 
-
 
1575
        if (isAdmin) {
-
 
1576
            AuthUser authUser = authRepository.selectByEmailOrMobile(loginDetails.getEmailId());
-
 
1577
            csService.markTicketAsRead(ticketId, authUser.getId(), UserType.AUTH_USER);
-
 
1578
        } else {
-
 
1579
            csService.markTicketAsRead(ticketId, loginDetails.getFofoId(), UserType.PARTNER);
-
 
1580
        }
-
 
1581
 
-
 
1582
        response.put("success", true);
-
 
1583
        return response;
-
 
1584
    }
-
 
1585
 
-
 
1586
    @GetMapping(value = "/cs/unreadCount")
-
 
1587
    @ResponseBody
-
 
1588
    public Map<String, Object> getUnreadCount(HttpServletRequest request) throws ProfitMandiBusinessException {
-
 
1589
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
-
 
1590
        boolean isAdmin = roleManager.isAdmin(loginDetails.getRoleIds());
-
 
1591
        Map<String, Object> response = new HashMap<>();
-
 
1592
 
-
 
1593
        List<Ticket> tickets;
-
 
1594
        int userId;
-
 
1595
        UserType userType;
-
 
1596
 
-
 
1597
        if (isAdmin) {
-
 
1598
            AuthUser authUser = authRepository.selectByEmailOrMobile(loginDetails.getEmailId());
-
 
1599
            userId = authUser.getId();
-
 
1600
            userType = UserType.AUTH_USER;
-
 
1601
            boolean isCrmUser = positionRepository.hasCategory(authUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_CRM);
-
 
1602
            List<Integer> userCategoryIds = positionRepository.selectCategoryIdsByAuthUserId(authUser.getId());
-
 
1603
            if (isCrmUser) {
-
 
1604
                tickets = ticketRepository.selectAllTicketsPaginated(
-
 
1605
                        Optional.of(false), null, null, 0, null,
-
 
1606
                        userCategoryIds, 0, 1000);
-
 
1607
            } else {
-
 
1608
                tickets = ticketRepository.selectAllByAssigneePaginated(
-
 
1609
                        authUser.getId(), Optional.of(false), null, null, 0, null,
-
 
1610
                        0, 1000);
-
 
1611
            }
-
 
1612
        } else {
-
 
1613
            userId = loginDetails.getFofoId();
-
 
1614
            userType = UserType.PARTNER;
-
 
1615
            tickets = ticketRepository.selectAllByCreator(loginDetails.getFofoId(), Optional.of(true), null);
-
 
1616
        }
-
 
1617
 
-
 
1618
        Map<Integer, Boolean> unreadMap = csService.getUnreadStatusForTickets(tickets, userId, userType);
-
 
1619
        long unreadCount = unreadMap.values().stream().filter(v -> v).count();
-
 
1620
 
-
 
1621
        response.put("success", true);
-
 
1622
        response.put("unreadCount", unreadCount);
-
 
1623
        return response;
-
 
1624
    }
1402
 
1625
 
1403
}
1626
}