Rev 35617 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
package com.spice.profitmandi.web.controller;import com.spice.profitmandi.common.exception.ProfitMandiBusinessException;import com.spice.profitmandi.common.model.CustomRetailer;import com.spice.profitmandi.common.model.ProfitMandiConstants;import com.spice.profitmandi.common.util.Utils;import com.spice.profitmandi.dao.entity.auth.AuthUser;import com.spice.profitmandi.dao.entity.cs.*;import com.spice.profitmandi.dao.entity.cs.Position;import com.spice.profitmandi.dao.entity.dtr.Document;import com.spice.profitmandi.dao.entity.cs.TicketReadStatus.UserType;import com.spice.profitmandi.dao.entity.fofo.ActivityType;import com.spice.profitmandi.dao.enumuration.cs.EscalationType;import com.spice.profitmandi.dao.enumuration.cs.TicketStatus;import com.spice.profitmandi.dao.model.CreatePositionModel;import com.spice.profitmandi.dao.repository.auth.AuthRepository;import com.spice.profitmandi.dao.repository.cs.*;import com.spice.profitmandi.dao.repository.dtr.DocumentRepository;import com.spice.profitmandi.dao.repository.dtr.FofoStoreRepository;import com.spice.profitmandi.service.authentication.RoleManager;import com.spice.profitmandi.service.user.RetailerService;import com.spice.profitmandi.web.model.LoginDetails;import com.spice.profitmandi.web.util.CookiesProcessor;import com.spice.profitmandi.web.util.MVCResponseSender;import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.mail.javamail.JavaMailSender;import org.springframework.stereotype.Controller;import org.springframework.transaction.annotation.Transactional;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpServletRequest;import javax.swing.SortOrder;import java.time.LocalDateTime;import java.util.*;import java.util.stream.Collectors;@Controller@Transactional(rollbackFor = Throwable.class)public class CsController {private static final Logger LOGGER = LogManager.getLogger(CsController.class);private static final String ACTIVITY_SUBJECT = "Message related ticketId#%s";private static final String PARTNER_RESOLVED_TICKET_MAIL = "Dear Partner , we have resolved your ticket # %s , request to kindly accept the same. In case you still have any concerns regarding the same pls click on %s so that we can help you.Regards\nSmartdukaan";private static final String PARTNER_REOPEN = "Dear Partner , Your ticket # %s has been re-opened as per your confirmation & we are committed to resolve it on priority.Regards\nSmartdukaan";private static final String INTERNAL_REOPEN_MAIL = "Team, Pls note that the Ticket Id %s has been re-opened by %s , pls respond on priority";private static final String INTERNAL_REOPEN_ACTIVITY_MESSAGE = "Hi,My ticket is not resolved yet,so I have reopened it";@AutowiredJavaMailSender mailSender;@Autowiredprivate CsService csService;@Autowiredprivate CookiesProcessor cookiesProcessor;@Autowiredprivate TicketCategoryRepository ticketCategoryRepository;@Autowiredprivate TicketSubCategoryRepository ticketSubCategoryRepository;@Autowiredprivate RegionRepository regionRepository;@Autowiredprivate RetailerService retailerService;@Autowiredprivate MVCResponseSender mvcResponseSender;@Autowiredprivate AuthRepository authRepository;@Autowiredprivate PositionRepository positionRepository;@Autowiredprivate TicketRepository ticketRepository;@Autowiredprivate RoleManager roleManager;@Autowiredprivate ActivityRepository activityRepository;@Autowiredprivate ActivityAttachmentRepository activityAttachmentRepository;@Autowiredprivate TicketAssignedRepository ticketAssignedRepository;@Autowiredprivate PartnerRegionRepository partnerRegionRepository;@AutowiredPartnerPositionRepository partnerPositionRepository;@AutowiredFofoStoreRepository fofoStoreRepository;@AutowiredDocumentRepository documentRepository;@GetMapping(value = "/cs/createCategory")public String getCreateCategory(HttpServletRequest request, Model model) {List<TicketCategory> ticketCategories = ticketCategoryRepository.selectAll();model.addAttribute("ticketCategories", ticketCategories);return "create-ticket-category";}@PostMapping(value = "/cs/createCategory")public String createCategory(HttpServletRequest request,@RequestParam(name = "name") String name,@RequestParam(name = "categoryType") int categoryType,@RequestParam(name = "description") String description,Model model) throws ProfitMandiBusinessException {TicketCategory ticketCategory = ticketCategoryRepository.selectByName(name);if (ticketCategory != null) {throw new ProfitMandiBusinessException("name", name, "already exists!");}ticketCategory = new TicketCategory();ticketCategory.setName(name);ticketCategory.setDescription(description);ticketCategory.setCategoryType(categoryType == 1);ticketCategoryRepository.persist(ticketCategory);return "create-ticket-category";}@GetMapping(value = "/cs/createSubCategory")public String getCreateSubCategory(HttpServletRequest request, Model model) {List<TicketCategory> ticketCategories = ticketCategoryRepository.selectAll();model.addAttribute("ticketCategories", ticketCategories);return "create-ticket-sub-category";}@GetMapping(value = "/cs/getSubCategoryByCategoryId")public String getSubCategoryByCategoryId(HttpServletRequest request, @RequestParam(name = "ticketCategoryId", defaultValue = "") int ticketCategoryId, Model model) {List<TicketSubCategory> ticketSubCategories = ticketSubCategoryRepository.selectAll(ticketCategoryId);TicketCategory ticketCategory = ticketCategoryRepository.selectById(ticketCategoryId);LOGGER.info("ticketSubCategories {}", ticketSubCategories);LOGGER.info("ticketCategory {}", ticketCategory);model.addAttribute("ticketSubCategories", ticketSubCategories);model.addAttribute("ticketCategory", ticketCategory);return "ticket-sub-category";}@PostMapping(value = "/cs/createSubCategory")public String createSubCategory(HttpServletRequest request, @RequestParam(name = "categoryId", defaultValue = "0") int categoryId, @RequestParam(name = "name") String name, @RequestParam(name = "description") String description, Model model) throws ProfitMandiBusinessException {TicketSubCategory ticketSubCategory = ticketSubCategoryRepository.selectTicketSubCategory(categoryId, name);if (ticketSubCategory != null) {throw new ProfitMandiBusinessException("name & categoryId", name + " " + categoryId, "already exists!");}ticketSubCategory = new TicketSubCategory();ticketSubCategory.setCategoryId(categoryId);ticketSubCategory.setName(name);ticketSubCategory.setDescription(description);ticketSubCategoryRepository.persist(ticketSubCategory);return "create-ticket-sub-category";}@GetMapping(value = "/cs/createRegion")public String createRegion(HttpServletRequest request, Model model) {List<Region> regions = regionRepository.selectAll();model.addAttribute("regions", regions);return "create-region";}@PostMapping(value = "/cs/createRegion")public String createRegion(HttpServletRequest request, @RequestParam(name = "name") String name, @RequestParam(name = "description") String description, Model model) throws Exception {Region region = regionRepository.selectByName(name);if (region != null) {throw new ProfitMandiBusinessException("name", name, "already exists!");}region = new Region();region.setName(name);region.setDescription(description);regionRepository.persist(region);model.addAttribute("response1", mvcResponseSender.createResponseString(true));return "response";}@GetMapping(value = "/cs/getPartners")public String getPartners(HttpServletRequest request, @RequestParam(name = "regionId", defaultValue = "0") int regionId, Model model) throws ProfitMandiBusinessException {List<Integer> fofoIds = fofoStoreRepository.selectAll().stream().map(x -> x.getId()).collect(Collectors.toList());List<Integer> addedfofoIds = partnerRegionRepository.selectByRegionId(regionId).stream().map(x -> x.getFofoId()).collect(Collectors.toList());Map<Integer, CustomRetailer> customRetailerMap = retailerService.getAllFofoRetailers();Map<Integer, CustomRetailer> fofoRetailers = fofoIds.stream().map(x -> customRetailerMap.get(x)).filter(x -> x != null).collect(Collectors.toList()).stream().collect(Collectors.toMap(x -> x.getPartnerId(), x -> x));model.addAttribute("fofoRetailers", fofoRetailers);model.addAttribute("addedfofoIds", addedfofoIds);return "added-region-partners";}@GetMapping(value = "/cs/getPartnersByRegion")public String getPartnersByRegion(HttpServletRequest request, @RequestParam(name = "regionId", defaultValue = "0") int regionId, Model model) throws ProfitMandiBusinessException {List<Integer> fofoIds = null;fofoIds = partnerRegionRepository.selectByRegionId(regionId).stream().map(x -> x.getFofoId()).collect(Collectors.toList());if (fofoIds.contains(0)) {fofoIds = fofoStoreRepository.selectAll().stream().filter(x -> x.isActive()).collect(Collectors.toList()).stream().map(x -> x.getId()).collect(Collectors.toList());}Map<Integer, CustomRetailer> customRetailerMap = retailerService.getAllFofoRetailers();Map<Integer, CustomRetailer> fofoRetailers = fofoIds.stream().map(x -> customRetailerMap.get(x)).filter(x -> x != null).collect(Collectors.toList()).stream().collect(Collectors.toMap(x -> x.getPartnerId(), x -> x));model.addAttribute("fofoRetailers", fofoRetailers);return "added-subregion-partners";}@GetMapping(value = "/cs/createPartnerRegion")public String createPartnerRegion(HttpServletRequest request, Model model) {List<Region> regions = regionRepository.selectAll();model.addAttribute("regions", regions);return "create-partner-region";}@PostMapping(value = "/cs/createPartnerRegion")public String createPartnerRegion(HttpServletRequest request, @RequestParam(name = "regionId") int regionId, @RequestBody List<Integer> selectedFofoIds, Model model) throws Exception {partnerRegionRepository.delete(regionId);LOGGER.info("successfully removed");LOGGER.info(selectedFofoIds.size());csService.addPartnerToRegion(regionId, selectedFofoIds);model.addAttribute("response1", mvcResponseSender.createResponseString(true));return "response";}@GetMapping(value = "/cs/getPosition")public String getPosition(HttpServletRequest request, @RequestParam int positionId, Model model) throws ProfitMandiBusinessException {Position position = positionRepository.selectById(positionId);List<CustomRetailer> positionIdCustomRetailer = csService.getPositionCustomRetailerMap(Arrays.asList(position)).get(position.getId());Map<Integer, CustomRetailer> regionRetailerMap = csService.getRegionPartners(Arrays.asList(position)).get(position.getRegionId()).stream().collect(Collectors.toMap(x -> x.getPartnerId(), x -> x));model.addAttribute("position", position);model.addAttribute("regionRetailerMap", regionRetailerMap);model.addAttribute("positionIdCustomRetailer", positionIdCustomRetailer);return "position-partner";}@GetMapping(value = "/cs/createPosition")public String createPosition(HttpServletRequest request, @RequestParam(name = "offset", defaultValue = "0") int offset, @RequestParam(name = "limit", defaultValue = "10") int limit, Model model) {List<AuthUser> authUsers = authRepository.selectAllActiveUser();List<TicketCategory> ticketCategories = ticketCategoryRepository.selectAll();List<Region> regions = regionRepository.selectAll();model.addAttribute("escalationTypes", EscalationType.values());model.addAttribute("authUsers", authUsers);model.addAttribute("ticketCategories", ticketCategories);model.addAttribute("regions", regions);List<Position> positions = positionRepository.selectAllPosition();LOGGER.info("positions" + positions);Map<Integer, AuthUser> authUserIdAndAuthUserMap = csService.getAuthUserIdAndAuthUserMapUsingPositions(positions);Map<Integer, TicketCategory> categoryIdAndCategoryMap = csService.getCategoryIdAndCategoryUsingPositions(positions);Map<Integer, Region> regionIdAndRegionMap = csService.getRegionIdAndRegionMap(positions);// Map<Integer, List<CustomRetailer>> positionIdAndpartnerRegionMap = csService// .getpositionIdAndpartnerRegionMap(positions);// Map<Integer, List<CustomRetailer>> addedpositionIdAndCustomRetailerMap = csService// .getPositionCustomRetailerMap(positions);// LOGGER.info("fofoIdAndCustomRetailerMap" + addedpositionIdAndCustomRetailerMap);model.addAttribute("start", offset + 1);model.addAttribute("positions", positions);model.addAttribute("authUserIdAndAuthUserMap", authUserIdAndAuthUserMap);model.addAttribute("categoryIdAndCategoryMap", categoryIdAndCategoryMap);model.addAttribute("regionIdAndRegionMap", regionIdAndRegionMap);// model.addAttribute("positionIdAndCustomRetailerMap",// addedpositionIdAndCustomRetailerMap);// model.addAttribute("positionIdAndpartnerRegionMap",// positionIdAndpartnerRegionMap);return "create-position";}@GetMapping(value = "/cs/position-paginated")public String positionPaginated(HttpServletRequest request, @RequestParam(name = "offset", defaultValue = "0") int offset, @RequestParam(name = "limit", defaultValue = "10") int limit, Model model) {List<Position> positions = positionRepository.selectAll(offset, limit);Map<Integer, AuthUser> authUserIdAndAuthUserMap = csService.getAuthUserIdAndAuthUserMapUsingPositions(positions);Map<Integer, TicketCategory> categoryIdAndCategoryMap = csService.getCategoryIdAndCategoryUsingPositions(positions);Map<Integer, Region> regionIdAndRegionMap = csService.getRegionIdAndRegionMap(positions);/** Map<Integer, List<CustomRetailer>> positionIdAndpartnerRegionMap = csService* .getpositionIdAndpartnerRegionMap(positions);** Map<Integer, List<CustomRetailer>> addedpositionIdAndCustomRetailerMap =* csService .getPositionCustomRetailerMap(positions);*/model.addAttribute("positions", positions);model.addAttribute("authUserIdAndAuthUserMap", authUserIdAndAuthUserMap);model.addAttribute("categoryIdAndCategoryMap", categoryIdAndCategoryMap);model.addAttribute("regionIdAndRegionMap", regionIdAndRegionMap);// model.addAttribute("positionIdAndCustomRetailerMap",// addedpositionIdAndCustomRetailerMap);// model.addAttribute("positionIdAndpartnerRegionMap",// positionIdAndpartnerRegionMap);return "position-paginated";}@PostMapping(value = "/cs/createPosition")public String createPosition(HttpServletRequest request, @RequestBody CreatePositionModel createPositionModel, Model model) throws Exception {LOGGER.info("partnerPosition" + createPositionModel.isTicketAssigned());// Validate authUserId existsint authUserId = createPositionModel.getAuthUserId();if (authUserId <= 0 || authRepository.selectById(authUserId) == null) {throw new ProfitMandiBusinessException("Position", authUserId, "Invalid authUserId");}// Validate categoryId exists (0 means "All Categories")int categoryId = createPositionModel.getCategoryId();if (categoryId > 0 && ticketCategoryRepository.selectById(categoryId) == null) {throw new ProfitMandiBusinessException("Position", categoryId, "Invalid categoryId");}// Validate regionId exists (0 or 5 typically means "All Partners/Regions")int regionId = createPositionModel.getRegionId();if (regionId > 0 && regionId != 5 && regionRepository.selectById(regionId) == null) {throw new ProfitMandiBusinessException("Position", regionId, "Invalid regionId");}// Validate fofoIds exist (0 means "All Partners")List<Integer> fofoIds = createPositionModel.getFofoIds();if (fofoIds == null || fofoIds.isEmpty()) {throw new ProfitMandiBusinessException("Position", 0, "At least one partner must be specified");}boolean hasAllPartners = fofoIds.contains(0);if (hasAllPartners && fofoIds.size() > 1) {throw new ProfitMandiBusinessException("Position", 0, "Cannot mix 'All Partners' (0) with specific partner IDs");}if (!hasAllPartners) {Map<Integer, CustomRetailer> validRetailers = retailerService.getFofoRetailers(false);for (int fofoId : fofoIds) {if (!validRetailers.containsKey(fofoId)) {throw new ProfitMandiBusinessException("Position", fofoId, "Invalid fofoId");}}}Position position = positionRepository.selectPosition(authUserId, categoryId, regionId, createPositionModel.getEscalationType());if (position == null) {position = new Position();position.setAuthUserId(authUserId);position.setCategoryId(categoryId);position.setEscalationType(createPositionModel.getEscalationType());position.setRegionId(regionId);position.setCreateTimestamp(LocalDateTime.now());position.setTicketAssignee(createPositionModel.isTicketAssigned());positionRepository.persist(position);if (fofoIds != null) {for (int fofoId : fofoIds) {PartnerPosition partnerPosition = new PartnerPosition();partnerPosition.setFofoId(fofoId);partnerPosition.setRegionId(regionId);partnerPosition.setPositionId(position.getId());partnerPositionRepository.persist(partnerPosition);LOGGER.info("partnerPosition" + partnerPosition);}}model.addAttribute("response1", mvcResponseSender.createResponseString(true));} else {throw new ProfitMandiBusinessException("Position", authUserId, "already exists!");}return "response";}@PostMapping(value = "/cs/updatePartnerPosition")public String updatePartnerPosition(HttpServletRequest request, @RequestParam(name = "regionId") int regionId, @RequestBody List<Integer> selectedFofoIds, @RequestParam(name = "positionId") int positionId, Model model) throws Exception {// Validate positionId existsPosition position = positionRepository.selectById(positionId);if (position == null) {throw new ProfitMandiBusinessException("Position", positionId, "Position not found");}// Validate regionId exists (0 or 5 typically means "All Partners/Regions")if (regionId > 0 && regionId != 5 && regionRepository.selectById(regionId) == null) {throw new ProfitMandiBusinessException("Position", regionId, "Invalid regionId");}// Validate fofoIds exist (0 means "All Partners")if (selectedFofoIds == null || selectedFofoIds.isEmpty()) {throw new ProfitMandiBusinessException("Position", 0, "At least one partner must be specified");}boolean hasAllPartners = selectedFofoIds.contains(0);if (hasAllPartners && selectedFofoIds.size() > 1) {throw new ProfitMandiBusinessException("Position", 0, "Cannot mix 'All Partners' (0) with specific partner IDs");}if (!hasAllPartners) {// Use direct database query instead of cached retailerService to include newly added partnersSet<Integer> validFofoIds = fofoStoreRepository.selectAll().stream().map(fs -> fs.getId()).collect(Collectors.toSet());for (int fofoId : selectedFofoIds) {if (!validFofoIds.contains(fofoId)) {throw new ProfitMandiBusinessException("Position", fofoId, "Invalid fofoId");}}}partnerPositionRepository.delete(positionId);if (selectedFofoIds != null) {for (int fofoId : selectedFofoIds) {PartnerPosition partnerPosition = new PartnerPosition();partnerPosition.setFofoId(fofoId);partnerPosition.setRegionId(regionId);partnerPosition.setPositionId(positionId);partnerPositionRepository.persist(partnerPosition);}}model.addAttribute("response1", mvcResponseSender.createResponseString(true));return "response";}@GetMapping(value = "/cs/createTicket")public String createTicket(HttpServletRequest request, Model model) throws ProfitMandiBusinessException {LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);boolean isAdmin = roleManager.isAdmin(loginDetails.getRoleIds());boolean isCrmUser = false;List<TicketCategory> ticketCategories = csService.getAllTicketCategotyFromSubCategory();if (isAdmin) {AuthUser currentAuthUser = authRepository.selectByEmailOrMobile(loginDetails.getEmailId());isCrmUser = positionRepository.hasCategory(currentAuthUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_CRM);// CRM users should not see Sales and RBM categoriesif (isCrmUser) {ticketCategories = ticketCategories.stream().filter(tc -> tc.getId() != ProfitMandiConstants.TICKET_CATEGORY_SALES&& tc.getId() != ProfitMandiConstants.TICKET_CATEGORY_RBM).collect(Collectors.toList());}} else {// For partners/customers: hide categories where ALL subcategories are invisibleticketCategories = ticketCategories.stream().filter(category -> {List<TicketSubCategory> subs = ticketSubCategoryRepository.selectAll(category.getId());// Keep category if at least one subcategory is visiblereturn subs.stream().anyMatch(TicketSubCategory::isVisibility);}).collect(Collectors.toList());}model.addAttribute("roleType", isAdmin);model.addAttribute("ticketCategories", ticketCategories);model.addAttribute("isCrmUser", isCrmUser);return "create-ticket";}@GetMapping(value = "/cs/getSubCategoriesByCategoryId")public String getSubCategoriesByCategoryId(HttpServletRequest request, @RequestParam(name = "categoryId", defaultValue = "0") int categoryId, Model model) throws ProfitMandiBusinessException {LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);boolean isAdmin = roleManager.isAdmin(loginDetails.getRoleIds());boolean isCrmUser = false;if (isAdmin) {AuthUser currentAuthUser = authRepository.selectByEmailOrMobile(loginDetails.getEmailId());isCrmUser = positionRepository.hasCategory(currentAuthUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_CRM);}List<TicketSubCategory> ticketSubCategories = ticketSubCategoryRepository.selectAllVisible(categoryId);// CRM users should not see invisible subcategoriesif (isCrmUser) {ticketSubCategories = ticketSubCategories.stream().filter(TicketSubCategory::isVisibility).collect(Collectors.toList());}LOGGER.info(ticketSubCategories);model.addAttribute("ticketSubCategories", ticketSubCategories);return "ticket-sub-categories";}@GetMapping(value = "/cs/getEscalationTypeByCategoryId")public String getEscalationTypeByCategoryId(HttpServletRequest request, @RequestParam(name = "categoryId", defaultValue = "0") int categoryId, @RequestParam(name = "authId", defaultValue = "0") int authId, Model model) {List<Position> positions = positionRepository.selectPositionbyCategoryIdAndAuthId(categoryId, authId);List<EscalationType> escalationTypes = new ArrayList<>();if (!positions.isEmpty()) {escalationTypes = positions.stream().map(x -> x.getEscalationType()).distinct().collect(Collectors.toList());}LOGGER.info("escalationTypes {}", escalationTypes);model.addAttribute("escalationTypes", escalationTypes);return "ticket-escalationtype";}@GetMapping(value = "/cs/getCategoriesByAuthId")public String getCategoriesByAuthId(HttpServletRequest request, @RequestParam(name = "authId", defaultValue = "0") int authId, Model model) {List<Position> positions = positionRepository.selectPositionByAuthId(authId);LOGGER.info("positions {}", positions);List<TicketCategory> ticketCategories = new ArrayList<TicketCategory>();if (!positions.isEmpty()) {List<Integer> categoryIds = positions.stream().map(x -> x.getCategoryId()).collect(Collectors.toList());ticketCategories = ticketCategoryRepository.selectAll(categoryIds);}LOGGER.info("ticketCategories {}", ticketCategories);model.addAttribute("ticketCategories", ticketCategories);return "ticket-categories";}@PostMapping(value = "/cs/createTicket")public String createTicket(HttpServletRequest request, @RequestParam(name = "categoryId") int categoryId, @RequestParam(name = "subCategoryId") int subCategoryId, @RequestParam(name = "message") String message, Model model) throws Exception {LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);List<Ticket> tickets = ticketRepository.selectAllResolvedMarkedTicketByCreator(loginDetails.getFofoId());if (tickets.size() > 3 || tickets.size() == 3) {model.addAttribute("response1", mvcResponseSender.createResponseString(false));} else {csService.createTicket(loginDetails.getFofoId(), categoryId, subCategoryId, message);model.addAttribute("response1", mvcResponseSender.createResponseString(true));}return "response";}@GetMapping(value = "/cs/myticket")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,@RequestParam(name = "page", defaultValue = "0") int page,@RequestParam(name = "pageSize", defaultValue = "25") int pageSize,@RequestParam(name = "search", required = false) String searchText,Model model) throws ProfitMandiBusinessException {populateMyTicketModel(request, sortOrder, ticketStatus, ticketSearchType, searchTerm, page, pageSize, searchText, model);return "ticket";}@GetMapping(value = "/cs/myticket-content")public String getTicketContent(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,@RequestParam(name = "page", defaultValue = "0") int page,@RequestParam(name = "pageSize", defaultValue = "25") int pageSize,@RequestParam(name = "search", required = false) String searchText,Model model) throws ProfitMandiBusinessException {populateMyTicketModel(request, sortOrder, ticketStatus, ticketSearchType, searchTerm, page, pageSize, searchText, model);return "ticket-content";}private void populateMyTicketModel(HttpServletRequest request, SortOrder sortOrder, TicketStatus ticketStatus,TicketSearchType ticketSearchType, int searchTerm, int page, int pageSize,String searchText, Model model) throws ProfitMandiBusinessException {LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);List<Ticket> tickets = null;List<TicketAssigned> ticketAssigneds = null;long totalRecords = 0;Map<Integer, AuthUser> authUserIdAndAuthUserMap = null;boolean isAdmin = roleManager.isAdmin(new HashSet<>(loginDetails.getRoleIds()));AuthUser currentAuthUser = isAdmin ? authRepository.selectByEmailOrMobile(loginDetails.getEmailId()) : null;boolean isCrmUser = isAdmin && currentAuthUser != null && positionRepository.hasCategory(currentAuthUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_CRM);boolean isSalesUser = isAdmin && currentAuthUser != null && positionRepository.hasCategory(currentAuthUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_SALES);boolean isRbmUser = isAdmin && currentAuthUser != null && positionRepository.hasCategory(currentAuthUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_RBM);List<Integer> userCategoryIds = isAdmin && currentAuthUser != null? positionRepository.selectCategoryIdsByAuthUserId(currentAuthUser.getId()): Collections.emptyList();int offset = page * pageSize;if (isAdmin) {int authUserId = currentAuthUser.getId();if (isCrmUser) {Optional<Boolean> resolvedOpt = ticketStatus.equals(TicketStatus.RESOLVED) ? Optional.empty() : Optional.of(TicketStatus.CLOSED.equals(ticketStatus));tickets = ticketRepository.selectAllTicketsPaginated(resolvedOpt, sortOrder, ticketSearchType, searchTerm, searchText,userCategoryIds, offset, pageSize);totalRecords = ticketRepository.selectAllTicketsPaginatedCount(resolvedOpt, ticketSearchType, searchTerm, searchText, userCategoryIds);} else {Optional<Boolean> resolvedOpt = ticketStatus.equals(TicketStatus.RESOLVED) ? Optional.empty() : Optional.of(TicketStatus.CLOSED.equals(ticketStatus));tickets = ticketRepository.selectAllByAssigneePaginated(authUserId, resolvedOpt, sortOrder, ticketSearchType, searchTerm, searchText,offset, pageSize);totalRecords = ticketRepository.selectAllByAssigneePaginatedCount(authUserId, resolvedOpt, ticketSearchType, searchTerm, searchText);}if (tickets.size() > 0) {ticketAssigneds = ticketAssignedRepository.selectByTicketIds(tickets.stream().map(x -> x.getId()).collect(Collectors.toList()));authUserIdAndAuthUserMap = csService.getAuthUserIdAndAuthUserMap(ticketAssigneds);Map<Integer, CustomRetailer> fofoIdsAndCustomRetailer = csService.getPartnerByFofoIds(tickets);model.addAttribute("fofoIdsAndCustomRetailer", fofoIdsAndCustomRetailer);}} else {tickets = ticketRepository.selectAllByCreator(loginDetails.getFofoId(), Optional.of(TicketStatus.OPENED.equals(ticketStatus)), sortOrder);totalRecords = ticketRepository.selectAllCountByCreator(loginDetails.getFofoId(), Optional.of(TicketStatus.OPENED.equals(ticketStatus)));}authUserIdAndAuthUserMap = csService.getTicketIdAndAuthUserMapUsingTickets(tickets);if (authUserIdAndAuthUserMap == null) {authUserIdAndAuthUserMap = new HashMap<>();}int totalPages = (int) Math.ceil((double) totalRecords / pageSize);if (totalPages == 0) totalPages = 1;int startRecord = totalRecords > 0 ? offset + 1 : 0;int endRecord = (int) Math.min(offset + pageSize, totalRecords);model.addAttribute("size", totalRecords);model.addAttribute("totalRecords", totalRecords);model.addAttribute("currentPage", page);model.addAttribute("pageSize", pageSize);model.addAttribute("totalPages", totalPages);model.addAttribute("startRecord", startRecord);model.addAttribute("endRecord", endRecord);model.addAttribute("searchText", searchText != null ? searchText : "");model.addAttribute("currentPageDisplay", page + 1);model.addAttribute("prevPage", page - 1);model.addAttribute("nextPage", page + 1);model.addAttribute("lastPage", totalPages - 1);model.addAttribute("roleType", isAdmin);model.addAttribute("isCrmUser", isCrmUser);model.addAttribute("isSalesUser", isSalesUser);model.addAttribute("salesCategoryId", ProfitMandiConstants.TICKET_CATEGORY_SALES);model.addAttribute("isRbmUser", isRbmUser);model.addAttribute("rbmCategoryId", ProfitMandiConstants.TICKET_CATEGORY_RBM);model.addAttribute("userCategoryIds", userCategoryIds);List<Integer> subCategoryIds = tickets.stream().map(x -> x.getSubCategoryId()).collect(Collectors.toList());Map<Integer, TicketSubCategory> subCategoryIdAndSubCategoryMap = csService.getSubCategoryIdAndSubCategoryMap(subCategoryIds);if (subCategoryIdAndSubCategoryMap == null) {subCategoryIdAndSubCategoryMap = new HashMap<>();}Map<Integer, TicketCategory> subCategoryIdAndCategoryMap = csService.getSubCategoryIdAndCategoryMap(subCategoryIds);if (subCategoryIdAndCategoryMap == null) {subCategoryIdAndCategoryMap = new HashMap<>();}List<Integer> ticketIds = tickets.stream().map(x -> x.getId()).collect(Collectors.toList());Map<Integer, List<Activity>> activityMap = new HashMap<>();Map<Integer, List<Activity>> activityMapWithActivityId = new HashMap<>();Map<Integer, AuthUser> authUserMap = new HashMap<>();if (!ticketIds.isEmpty()) {List<Activity> allActivities = activityRepository.selectAll(ticketIds);activityMap = allActivities.stream().collect(Collectors.groupingBy(Activity::getTicketId));activityMapWithActivityId = allActivities.stream().collect(Collectors.groupingBy(Activity::getId));Set<Integer> activityCreatorIds = allActivities.stream().map(Activity::getCreatedBy).filter(id -> id > 0).collect(Collectors.toSet());if (!activityCreatorIds.isEmpty()) {authUserMap = authRepository.selectByIds(new ArrayList<>(activityCreatorIds)).stream().collect(Collectors.toMap(AuthUser::getId, x -> x));}}int currentUserId;UserType currentUserType;if (isAdmin) {currentUserId = currentAuthUser.getId();currentUserType = UserType.AUTH_USER;} else {currentUserId = loginDetails.getFofoId();currentUserType = UserType.PARTNER;}Map<Integer, Boolean> unreadMap = csService.getUnreadStatusForTickets(tickets, currentUserId, currentUserType);Map<Integer, Activity> lastActivityMap = csService.getLastActivitiesForTickets(ticketIds);model.addAttribute("unreadMap", unreadMap);model.addAttribute("lastActivityMap", lastActivityMap);model.addAttribute("tickets", tickets);model.addAttribute("resolved", ActivityType.RESOLVED);model.addAttribute("resolved-accepted", ActivityType.RESOLVED_ACCEPTED);model.addAttribute("resolved-rejected", ActivityType.RESOLVED_REJECTED);model.addAttribute("authUserIdAndAuthUserMap", authUserIdAndAuthUserMap);model.addAttribute("subCategoryIdAndSubCategoryMap", subCategoryIdAndSubCategoryMap);model.addAttribute("subCategoryIdAndCategoryMap", subCategoryIdAndCategoryMap);model.addAttribute("activityMap", activityMap);model.addAttribute("authUserMap", authUserMap);model.addAttribute("activityMapWithActivityId", activityMapWithActivityId);model.addAttribute("ticketStatusValues", TicketStatus.values());model.addAttribute("orderByValues", SortOrder.values());model.addAttribute("selectedticketStatus", ticketStatus);model.addAttribute("selectedorderby", sortOrder);model.addAttribute("ticketSearchTypes", TicketSearchType.values());model.addAttribute("ticketSearchType", ticketSearchType);model.addAttribute("searchTerm", searchTerm);}@GetMapping(value = "/cs/getActivities")public String getActivity(HttpServletRequest request, @RequestParam(name = "ticketId", defaultValue = "0") int ticketId, Model model) throws Exception {LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);Ticket ticket = ticketRepository.selectById(ticketId);if (ticket == null) {throw new ProfitMandiBusinessException("Ticket", ticketId, "Ticket not found");}// Authorization check: verify user has access to this ticketboolean isAdmin = roleManager.isAdmin(loginDetails.getRoleIds());if (!isAdmin) {// Partners can only view their own ticketsif (ticket.getFofoId() != loginDetails.getFofoId()) {throw new ProfitMandiBusinessException("Ticket", ticketId, "You do not have permission to view this ticket");}} else {// Admins must be assigned to the ticket OR be CRM user OR be in the escalation chainAuthUser currentAuthUser = authRepository.selectByEmailOrMobile(loginDetails.getEmailId());boolean isCrmUser = positionRepository.hasCategory(currentAuthUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_CRM);if (!isCrmUser) {// Check if user is assigned or in escalation chainList<TicketAssigned> assignments = ticketAssignedRepository.selectByTicketIds(Arrays.asList(ticketId));boolean isAssigned = assignments.stream().anyMatch(ta -> ta.getAssineeId() == currentAuthUser.getId() || ta.getManagerId() == currentAuthUser.getId());boolean isInEscalationChain = ticket.getL1AuthUser() == currentAuthUser.getId() ||ticket.getL2AuthUser() == currentAuthUser.getId() ||ticket.getL3AuthUser() == currentAuthUser.getId() ||ticket.getL4AuthUser() == currentAuthUser.getId() ||ticket.getL5AuthUser() == currentAuthUser.getId();if (!isAssigned && !isInEscalationChain) {throw new ProfitMandiBusinessException("Ticket", ticketId, "You do not have permission to view this ticket");}}}List<Activity> allactivities = activityRepository.selectAll(ticketId);// Batch fetch all documents for attachments (fix N+1 query)List<Integer> documentIds = allactivities.stream().flatMap(a -> a.getActivityAttachment().stream()).map(ActivityAttachment::getDocumentId).distinct().collect(Collectors.toList());Map<Integer, Document> documentMap = Collections.emptyMap();if (!documentIds.isEmpty()) {documentMap = documentRepository.selectByIds(documentIds).stream().collect(Collectors.toMap(Document::getId, d -> d));}// Set document names transiently (do not persist during GET)for (Activity activity : allactivities) {for (ActivityAttachment attachment : activity.getActivityAttachment()) {Document document = documentMap.get(attachment.getDocumentId());if (document != null) {attachment.setDocumentName(document.getDisplayName());}}}List<Activity> activities = null;if (isAdmin) {Set<Integer> authUserIds = allactivities.stream().map(x -> x.getCreatedBy()).collect(Collectors.toSet());List<AuthUser> users = authRepository.selectByIds(new ArrayList<>(authUserIds));Map<Integer, String> authUserNameMap = users.stream().collect(Collectors.toMap(AuthUser::getId, x -> x.getFirstName() + " " + x.getLastName()));allactivities.stream().forEach(x -> x.setName(authUserNameMap.get(x.getCreatedBy())));activities = allactivities;} else {activities = allactivities.stream().filter(x -> ActivityType.PARTNER_ACTIVITIES.contains(x.getType())).collect(Collectors.toList());}if (activities == null) {throw new ProfitMandiBusinessException("Activity", ticketId, "No Activity Found");}model.addAttribute("response1", mvcResponseSender.createResponseString(activities));return "response";}@PostMapping(value = "/cs/createActivity")public String createActivity(HttpServletRequest request, @RequestParam(name = "ticketId", defaultValue = "0") int ticketId, @RequestParam(name = "assigneeId", defaultValue = "0") int assigneeId, @RequestParam(name = "internal", defaultValue = "true") boolean internal, @RequestParam(name = "message", defaultValue = "") String message, @RequestBody List<Integer> documentIds,Model model) throws Exception {LOGGER.info("documentIds" + documentIds);LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);Ticket ticket = ticketRepository.selectById(ticketId);if (ticket == null) {throw new ProfitMandiBusinessException("Ticket", ticketId, "Ticket not found");}// Authorization check: verify user has access to add activity to this ticketboolean isAdmin = roleManager.isAdmin(loginDetails.getRoleIds());if (!isAdmin) {// Partners can only add activity to their own ticketsif (ticket.getFofoId() != loginDetails.getFofoId()) {throw new ProfitMandiBusinessException("Ticket", ticketId, "You do not have permission to add activity to this ticket");}} else {// Admins must be assigned to the ticket OR be CRM user OR be in the escalation chainAuthUser currentAuthUser = authRepository.selectByEmailOrMobile(loginDetails.getEmailId());boolean isCrmUser = positionRepository.hasCategory(currentAuthUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_CRM);if (!isCrmUser) {List<TicketAssigned> assignments = ticketAssignedRepository.selectByTicketIds(Arrays.asList(ticketId));boolean isAssigned = assignments.stream().anyMatch(ta -> ta.getAssineeId() == currentAuthUser.getId() || ta.getManagerId() == currentAuthUser.getId());boolean isInEscalationChain = ticket.getL1AuthUser() == currentAuthUser.getId() ||ticket.getL2AuthUser() == currentAuthUser.getId() ||ticket.getL3AuthUser() == currentAuthUser.getId() ||ticket.getL4AuthUser() == currentAuthUser.getId() ||ticket.getL5AuthUser() == currentAuthUser.getId();if (!isAssigned && !isInEscalationChain) {throw new ProfitMandiBusinessException("Ticket", ticketId, "You do not have permission to add activity to this ticket");}}}List<TicketAssigned> ticketAssignedList = ticketAssignedRepository.selectByTicketIds(Arrays.asList(ticketId));List<Integer> authUserIds = ticketAssignedList.stream().map(x -> x.getAssineeId()).collect(Collectors.toList());authUserIds.add(ticketAssignedList.get(ticketAssignedList.size() - 1).getManagerId());Map<Integer, AuthUser> authUsersMap = authRepository.selectByIds(authUserIds).stream().collect(Collectors.toMap(x -> x.getId(), x -> x));if (ticket.getCloseTimestamp() == null) {Activity activity = new Activity();activity.setCreatedBy(0);activity.setCreateTimestamp(LocalDateTime.now());String subject = null;String mailMessage = null;activity.setMessage(message);if (!roleManager.isAdmin(new HashSet<>(loginDetails.getRoleIds()))) {CustomRetailer customRetailer = retailerService.getFofoRetailers(true).get(loginDetails.getFofoId());activity.setType(ActivityType.COMMUNICATION_IN);subject = String.format("Ticket Update #%s by franchisee %s", ticket.getId(), customRetailer.getBusinessName() + "(" + customRetailer.getCode() + ")");mailMessage = String.format("Franchisee message - %s", message);} else {AuthUser authUser = authRepository.selectByEmailOrMobile(loginDetails.getEmailId());activity.setCreatedBy(authUser.getId());authUsersMap.remove(authUser.getId());subject = String.format("Ticket Update #%s by %s", ticket.getId(), authUser.getName());mailMessage = String.format("%s's message - %s", authUser.getFirstName(), message);// Only CRM users can send external communicationsboolean isCrmUser = positionRepository.hasCategory(authUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_CRM);if (internal || !isCrmUser) {activity.setType(ActivityType.COMMUNICATION_INTERNAL);} else {String updatedBy = "SD Team";CustomRetailer customRetailer = retailerService.getFofoRetailers(false).get(ticket.getFofoId());subject = String.format("Ticket Update #%s by %s", ticket.getId(), updatedBy);String partnerMessage = String.format("%s's message - %s", updatedBy, message);this.activityRelatedMail(customRetailer.getEmail(), null, "subject", partnerMessage);activity.setType(ActivityType.COMMUNICATION_OUT);}}activityRepository.persist(activity);for (Integer documentId : documentIds) {ActivityAttachment activityAttachment = new ActivityAttachment();activityAttachment.setActivityId(activity.getId());activityAttachment.setDocumentId(documentId);activityAttachmentRepository.persist(activityAttachment);}csService.addActivity(ticket, activity);AuthUser authUser = authUsersMap.remove(authUserIds.get(0));if (authUser == null) {authUser = authUsersMap.remove(authUserIds.get(1));}model.addAttribute("response1", mvcResponseSender.createResponseString(authUser));String[] cc = authUsersMap.entrySet().stream().map(x -> x.getValue().getEmailId()).toArray(String[]::new);this.activityRelatedMail(authUser.getEmailId(), cc, subject, mailMessage);} else {throw new ProfitMandiBusinessException("Ticket", ticket.getId(), "Already closed ticket");}return "response";}private void activityRelatedMail(String to, String[] cc, String subject, String message) throws ProfitMandiBusinessException {try {Utils.sendMailWithAttachments(mailSender, to, cc, subject, message, null);} catch (Exception e) {throw new ProfitMandiBusinessException("Ticket Activity", to, "Could not send ticket activity mail");}}@PostMapping(value = "/cs/closeTicket")public String closeTicket(HttpServletRequest request, @RequestParam(name = "ticketId", defaultValue = "0") int ticketId, @RequestParam(name = "happyCode") String happyCode, Model model) throws Exception {LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);Ticket ticket = ticketRepository.selectById(ticketId);if (ticket == null) {throw new ProfitMandiBusinessException("Ticket", ticketId, "Ticket not found");}// Authorization check: only the ticket owner (partner) can close the ticketboolean isAdmin = roleManager.isAdmin(loginDetails.getRoleIds());if (isAdmin) {throw new ProfitMandiBusinessException("Ticket", ticketId, "Only partners can close tickets using happy code");}// Verify the partner owns this ticketif (ticket.getFofoId() != loginDetails.getFofoId()) {throw new ProfitMandiBusinessException("Ticket", ticketId, "You do not have permission to close this ticket");}if (ticket.getHappyCode().equals(happyCode)) {ticket.setCloseTimestamp(LocalDateTime.now());ticketRepository.persist(ticket);model.addAttribute("response1", mvcResponseSender.createResponseString(true));} else {throw new ProfitMandiBusinessException("Ticket", ticketId, "Happy Code can't match");}return "response";}@GetMapping(value = "/cs/myPartyTicketTicket")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 {populateMyPartnerTicketModel(request, sortOrder, ticketStatus, ticketSearchType, searchTerm, model);return "my-partner-tickets";}@GetMapping(value = "/cs/myPartyTicket-content")public String getMyPartyTicketContent(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 {populateMyPartnerTicketModel(request, sortOrder, ticketStatus, ticketSearchType, searchTerm, model);return "my-partner-tickets-content";}private void populateMyPartnerTicketModel(HttpServletRequest request, SortOrder sortOrder, TicketStatus ticketStatus,TicketSearchType ticketSearchType, int searchTerm, Model model) throws ProfitMandiBusinessException {LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);AuthUser authUser = authRepository.selectByEmailOrMobile(loginDetails.getEmailId());List<Ticket> tickets = new ArrayList<>();Map<String, Set<Integer>> storeGuyMap = csService.getAuthUserPartnerIdMapping();Set<Integer> fofoIds = storeGuyMap.get(authUser.getEmailId());Map<Integer, List<AuthUser>> authUserListMap = null;if (fofoIds != null && !fofoIds.isEmpty()) {List<Ticket> allPartnerTickets = ticketRepository.selectAllOpenTickets(new ArrayList<>(fofoIds));if (allPartnerTickets != null && !allPartnerTickets.isEmpty()) {tickets = allPartnerTickets.stream().filter(ticket -> ticket.getLastActivity() == null ||ticket.getLastActivity() != ActivityType.RESOLVED).collect(Collectors.toList());}}authUserListMap = csService.getAssignedAuthList(tickets);if (tickets.size() > 0) {Map<Integer, CustomRetailer> fofoIdsAndCustomRetailer = csService.getPartnerByFofoIds(tickets);model.addAttribute("fofoIdsAndCustomRetailer", fofoIdsAndCustomRetailer);}// Pagination for partner tickets (in-memory since selectAllOpenTickets doesn't support DB-level pagination)long totalRecords = tickets.size();int totalPages = totalRecords > 0 ? (int) Math.ceil((double) totalRecords / 25) : 1;model.addAttribute("totalRecords", totalRecords);model.addAttribute("currentPage", 0);model.addAttribute("pageSize", 25);model.addAttribute("totalPages", totalPages);model.addAttribute("startRecord", totalRecords > 0 ? 1 : 0);model.addAttribute("endRecord", totalRecords);model.addAttribute("currentPageDisplay", 1);model.addAttribute("prevPage", 0);model.addAttribute("nextPage", 1);model.addAttribute("lastPage", totalPages - 1);model.addAttribute("size", tickets.size());model.addAttribute("tickets", tickets);List<Integer> subCategoryIds = tickets.stream().map(x -> x.getSubCategoryId()).collect(Collectors.toList());Map<Integer, TicketSubCategory> subCategoryIdAndSubCategoryMap = csService.getSubCategoryIdAndSubCategoryMap(subCategoryIds);if (subCategoryIdAndSubCategoryMap == null) {subCategoryIdAndSubCategoryMap = new HashMap<>();}Map<Integer, TicketCategory> subCategoryIdAndCategoryMap = csService.getSubCategoryIdAndCategoryMap(subCategoryIds);if (subCategoryIdAndCategoryMap == null) {subCategoryIdAndCategoryMap = new HashMap<>();}List<Integer> ticketIds = tickets.stream().map(x -> x.getId()).collect(Collectors.toList());Map<Integer, List<Activity>> activityMap = new HashMap<>();Map<Integer, List<Activity>> activityMapWithActivityId = new HashMap<>();Map<Integer, AuthUser> authUserMap = new HashMap<>();if (!ticketIds.isEmpty()) {List<Activity> allActivities = activityRepository.selectAll(ticketIds);activityMap = allActivities.stream().collect(Collectors.groupingBy(Activity::getTicketId));activityMapWithActivityId = allActivities.stream().collect(Collectors.groupingBy(Activity::getId));Set<Integer> activityCreatorIds = allActivities.stream().map(Activity::getCreatedBy).filter(id -> id > 0).collect(Collectors.toSet());if (!activityCreatorIds.isEmpty()) {authUserMap = authRepository.selectByIds(new ArrayList<>(activityCreatorIds)).stream().collect(Collectors.toMap(AuthUser::getId, x -> x));}}Map<Integer, Boolean> unreadMap = csService.getUnreadStatusForTickets(tickets, authUser.getId(), UserType.AUTH_USER);Map<Integer, Activity> lastActivityMap = csService.getLastActivitiesForTickets(tickets.stream().map(Ticket::getId).collect(Collectors.toList()));model.addAttribute("unreadMap", unreadMap);model.addAttribute("lastActivityMap", lastActivityMap);model.addAttribute("ticketStatusValues", TicketStatus.values());model.addAttribute("orderByValues", SortOrder.values());model.addAttribute("selectedticketStatus", ticketStatus);model.addAttribute("selectedorderby", sortOrder);model.addAttribute("ticketSearchTypes", TicketSearchType.values());model.addAttribute("ticketSearchType", ticketSearchType);model.addAttribute("searchTerm", searchTerm);model.addAttribute("authUserListMap", authUserListMap != null ? authUserListMap : new HashMap<>());model.addAttribute("subCategoryIdAndSubCategoryMap", subCategoryIdAndSubCategoryMap);model.addAttribute("subCategoryIdAndCategoryMap", subCategoryIdAndCategoryMap);model.addAttribute("activityMap", activityMap);model.addAttribute("authUserMap", authUserMap);model.addAttribute("activityMapWithActivityId", activityMapWithActivityId);boolean isCrmUser = positionRepository.hasCategory(authUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_CRM);model.addAttribute("isCrmUser", isCrmUser);}@GetMapping(value = "/cs/managerTicket")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,@RequestParam(name = "page", defaultValue = "0") int page,@RequestParam(name = "pageSize", defaultValue = "25") int pageSize,@RequestParam(name = "search", required = false) String searchText,Model model) throws ProfitMandiBusinessException {populateManagerTicketModel(request, sortOrder, ticketStatus, ticketSearchType, searchTerm, page, pageSize, searchText, model);return "managerTicket";}@GetMapping(value = "/cs/managerTicket-content")public String getManagerTicketContent(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,@RequestParam(name = "page", defaultValue = "0") int page,@RequestParam(name = "pageSize", defaultValue = "25") int pageSize,@RequestParam(name = "search", required = false) String searchText,Model model) throws ProfitMandiBusinessException {populateManagerTicketModel(request, sortOrder, ticketStatus, ticketSearchType, searchTerm, page, pageSize, searchText, model);return "managerTicket-content";}private void populateManagerTicketModel(HttpServletRequest request, SortOrder sortOrder, TicketStatus ticketStatus,TicketSearchType ticketSearchType, int searchTerm, int page, int pageSize,String searchText, Model model) throws ProfitMandiBusinessException {LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);long totalRecords = 0;AuthUser authUser = authRepository.selectByEmailOrMobile(loginDetails.getEmailId());// Block L1-only users from accessing manager ticketsList<Position> positions = positionRepository.selectAllByAuthUserId(authUser.getId());boolean isAboveL1 = positions.stream().anyMatch(pos -> pos.getEscalationType() != EscalationType.L1);if (!isAboveL1) {throw new ProfitMandiBusinessException("ManagerTicket", 0, "Access denied: requires at least L2 position");}boolean isCrmUser = positionRepository.hasCategory(authUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_CRM);List<Integer> userCategoryIds = positionRepository.selectCategoryIdsByAuthUserId(authUser.getId());List<Ticket> tickets = null;Map<Integer, List<AuthUser>> authUserListMap = null;int offset = page * pageSize;Optional<Boolean> resolvedOpt = ticketStatus.equals(TicketStatus.RESOLVED) ? Optional.empty() : Optional.of(TicketStatus.CLOSED.equals(ticketStatus));if (isCrmUser) {tickets = ticketRepository.selectAllTicketsPaginated(resolvedOpt, sortOrder, ticketSearchType, searchTerm, searchText,userCategoryIds, offset, pageSize);totalRecords = ticketRepository.selectAllTicketsPaginatedCount(resolvedOpt, ticketSearchType, searchTerm, searchText, userCategoryIds);} else {tickets = ticketRepository.selectAllManagerTicketPaginated(authUser.getId(), sortOrder, resolvedOpt, ticketSearchType, searchTerm, searchText,offset, pageSize);totalRecords = ticketRepository.selectAllCountByManagerTicketPaginated(authUser.getId(), resolvedOpt, ticketSearchType, searchTerm, searchText);}authUserListMap = csService.getAssignedAuthList(tickets);if (tickets.size() > 0) {Map<Integer, CustomRetailer> fofoIdsAndCustomRetailer = csService.getPartnerByFofoIds(tickets);model.addAttribute("fofoIdsAndCustomRetailer", fofoIdsAndCustomRetailer);}int totalPages = (int) Math.ceil((double) totalRecords / pageSize);if (totalPages == 0) totalPages = 1;int startRecord = totalRecords > 0 ? offset + 1 : 0;int endRecord = (int) Math.min(offset + pageSize, totalRecords);model.addAttribute("size", totalRecords);model.addAttribute("totalRecords", totalRecords);model.addAttribute("currentPage", page);model.addAttribute("pageSize", pageSize);model.addAttribute("totalPages", totalPages);model.addAttribute("startRecord", startRecord);model.addAttribute("endRecord", endRecord);model.addAttribute("searchText", searchText != null ? searchText : "");model.addAttribute("currentPageDisplay", page + 1);model.addAttribute("prevPage", page - 1);model.addAttribute("nextPage", page + 1);model.addAttribute("lastPage", totalPages - 1);model.addAttribute("tickets", tickets);List<Integer> subCategoryIds = tickets.stream().map(x -> x.getSubCategoryId()).collect(Collectors.toList());Map<Integer, TicketSubCategory> subCategoryIdAndSubCategoryMap = csService.getSubCategoryIdAndSubCategoryMap(subCategoryIds);if (subCategoryIdAndSubCategoryMap == null) {subCategoryIdAndSubCategoryMap = new HashMap<>();}Map<Integer, TicketCategory> subCategoryIdAndCategoryMap = csService.getSubCategoryIdAndCategoryMap(subCategoryIds);if (subCategoryIdAndCategoryMap == null) {subCategoryIdAndCategoryMap = new HashMap<>();}List<Integer> ticketIds = tickets.stream().map(x -> x.getId()).collect(Collectors.toList());Map<Integer, List<Activity>> activityMap = new HashMap<>();Map<Integer, List<Activity>> activityMapWithActivityId = new HashMap<>();Map<Integer, AuthUser> authUserMap = new HashMap<>();if (!ticketIds.isEmpty()) {List<Activity> allActivities = activityRepository.selectAll(ticketIds);activityMap = allActivities.stream().collect(Collectors.groupingBy(Activity::getTicketId));activityMapWithActivityId = allActivities.stream().collect(Collectors.groupingBy(Activity::getId));Set<Integer> activityCreatorIds = allActivities.stream().map(Activity::getCreatedBy).filter(id -> id > 0).collect(Collectors.toSet());if (!activityCreatorIds.isEmpty()) {authUserMap = authRepository.selectByIds(new ArrayList<>(activityCreatorIds)).stream().collect(Collectors.toMap(AuthUser::getId, x -> x));}}Map<Integer, Boolean> unreadMap = csService.getUnreadStatusForTickets(tickets, authUser.getId(), UserType.AUTH_USER);Map<Integer, Activity> lastActivityMap = csService.getLastActivitiesForTickets(tickets.stream().map(Ticket::getId).collect(Collectors.toList()));model.addAttribute("unreadMap", unreadMap);model.addAttribute("lastActivityMap", lastActivityMap);model.addAttribute("ticketStatusValues", TicketStatus.values());model.addAttribute("orderByValues", SortOrder.values());model.addAttribute("selectedticketStatus", ticketStatus);model.addAttribute("selectedorderby", sortOrder);model.addAttribute("ticketSearchTypes", TicketSearchType.values());model.addAttribute("ticketSearchType", ticketSearchType);model.addAttribute("searchTerm", searchTerm);model.addAttribute("authUserListMap", authUserListMap);model.addAttribute("subCategoryIdAndSubCategoryMap", subCategoryIdAndSubCategoryMap);model.addAttribute("subCategoryIdAndCategoryMap", subCategoryIdAndCategoryMap);model.addAttribute("activityMap", activityMap);model.addAttribute("authUserMap", authUserMap);model.addAttribute("activityMapWithActivityId", activityMapWithActivityId);model.addAttribute("isCrmUser", isCrmUser);}@GetMapping(value = "/cs/edit-ticket")public String getEditTicket(HttpServletRequest request, @RequestParam(name = "ticketId", defaultValue = "0") int ticketId, Model model) throws ProfitMandiBusinessException {LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);AuthUser currentAuthUser = authRepository.selectByEmailOrMobile(loginDetails.getEmailId());boolean isCrmUser = positionRepository.hasCategory(currentAuthUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_CRM);Ticket ticket = ticketRepository.selectById(ticketId);if (ticket == null) {throw new ProfitMandiBusinessException("Ticket", ticketId, "Ticket not found");}TicketSubCategory ticketSubCategory = ticketSubCategoryRepository.selectById(ticket.getSubCategoryId());int ticketCategoryId = ticketSubCategory.getCategoryId();boolean isVisibleSubCategory = ticketSubCategory.isVisibility();// Check permissionsboolean hasPositionInCategory = positionRepository.hasCategory(currentAuthUser.getId(), ticketCategoryId);List<TicketAssigned> assignments = ticketAssignedRepository.selectByTicketIds(Arrays.asList(ticketId));boolean isAssigned = assignments.stream().anyMatch(ta -> ta.getAssineeId() == currentAuthUser.getId() || ta.getManagerId() == currentAuthUser.getId());boolean isInEscalationChain = ticket.getL1AuthUser() == currentAuthUser.getId() ||ticket.getL2AuthUser() == currentAuthUser.getId() ||ticket.getL3AuthUser() == currentAuthUser.getId() ||ticket.getL4AuthUser() == currentAuthUser.getId() ||ticket.getL5AuthUser() == currentAuthUser.getId();boolean canEdit = (isCrmUser && isVisibleSubCategory)|| hasPositionInCategory|| isAssigned|| isInEscalationChain;if (!canEdit) {throw new ProfitMandiBusinessException("Ticket", ticketId, "You do not have permission to edit this ticket");}List<TicketCategory> ticketCategories = csService.getAllTicketCategotyFromSubCategory();List<TicketSubCategory> ticketSubCategories = ticketSubCategoryRepository.selectAll(ticketSubCategory.getCategoryId());List<AuthUser> authUsers = authRepository.selectAllActiveUser();// CRM users should not see invisible subcategoriesif (isCrmUser) {ticketSubCategories = ticketSubCategories.stream().filter(TicketSubCategory::isVisibility).collect(Collectors.toList());}// Get partner name for modal titleString partnerName = retailerService.getFofoRetailer(ticket.getFofoId()).getBusinessName();model.addAttribute("ticket", ticket);model.addAttribute("ticketCategories", ticketCategories);model.addAttribute("ticketSubCategories", ticketSubCategories);model.addAttribute("ticketSubCategory", ticketSubCategory);model.addAttribute("authUsers", authUsers);model.addAttribute("isCrmUser", isCrmUser);model.addAttribute("partnerName", partnerName);return "edit-ticket-modal";}@GetMapping(value = "/cs/edit-partner-ticket")public String getEditPartnerTicket(HttpServletRequest request, @RequestParam(name = "ticketId", defaultValue = "0") int ticketId, Model model) throws ProfitMandiBusinessException {LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);AuthUser currentAuthUser = authRepository.selectByEmailOrMobile(loginDetails.getEmailId());boolean isCrmUser = positionRepository.hasCategory(currentAuthUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_CRM);Ticket ticket = ticketRepository.selectById(ticketId);List<TicketCategory> ticketCategories = csService.getAllTicketCategotyFromSubCategory();TicketSubCategory ticketSubCategory = ticketSubCategoryRepository.selectById(ticket.getSubCategoryId());List<TicketSubCategory> ticketSubCategories = ticketSubCategoryRepository.selectAll(ticketSubCategory.getCategoryId());List<AuthUser> authUsers = authRepository.selectAllActiveUser();// CRM users should not see invisible subcategoriesif (isCrmUser) {ticketSubCategories = ticketSubCategories.stream().filter(TicketSubCategory::isVisibility).collect(Collectors.toList());}// Get partner name for modal titleString partnerName = retailerService.getFofoRetailer(ticket.getFofoId()).getBusinessName();model.addAttribute("ticket", ticket);model.addAttribute("ticketCategories", ticketCategories);model.addAttribute("ticketSubCategories", ticketSubCategories);model.addAttribute("ticketSubCategory", ticketSubCategory);model.addAttribute("authUsers", authUsers);model.addAttribute("isCrmUser", isCrmUser);model.addAttribute("partnerName", partnerName);return "edit-ticket-partner-modal";}@PostMapping(value = "/cs/edit-ticket")public String editTicket(HttpServletRequest request, @RequestParam(name = "ticketId", defaultValue = "0") int ticketId, @RequestParam(name = "subCategoryId", defaultValue = "0") int subCategoryId, @RequestParam(name = "categoryId", defaultValue = "0") int categoryId, @RequestParam(name = "authUserId", defaultValue = "0") int authUserId, @RequestParam(name = "escalationType", defaultValue = "L1") EscalationType escalationType, Model model) throws Exception {LOGGER.info("Ticket Id {}, CategoryId {}, SubCategory Id {} authUserId {}", ticketId, categoryId, subCategoryId, authUserId);LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);// Only admins can edit ticketsif (!roleManager.isAdmin(loginDetails.getRoleIds())) {throw new ProfitMandiBusinessException("Ticket", ticketId, "Only admins can edit tickets");}Ticket ticket = ticketRepository.selectById(ticketId);if (ticket == null) {throw new ProfitMandiBusinessException("Ticket", ticketId, "Ticket not found");}// Verify admin has access to this ticketAuthUser currentAuthUser = authRepository.selectByEmailOrMobile(loginDetails.getEmailId());boolean isCrmUser = positionRepository.hasCategory(currentAuthUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_CRM);// Get ticket's subcategory to check visibilityTicketSubCategory ticketSubCategory = ticketSubCategoryRepository.selectById(ticket.getSubCategoryId());int ticketCategoryId = ticketSubCategory.getCategoryId();boolean isVisibleSubCategory = ticketSubCategory.isVisibility();// Check if user has position in ticket's categoryboolean hasPositionInCategory = positionRepository.hasCategory(currentAuthUser.getId(), ticketCategoryId);// Check if assigned or in escalation chainList<TicketAssigned> assignments = ticketAssignedRepository.selectByTicketIds(Arrays.asList(ticketId));boolean isAssigned = assignments.stream().anyMatch(ta -> ta.getAssineeId() == currentAuthUser.getId() || ta.getManagerId() == currentAuthUser.getId());boolean isInEscalationChain = ticket.getL1AuthUser() == currentAuthUser.getId() ||ticket.getL2AuthUser() == currentAuthUser.getId() ||ticket.getL3AuthUser() == currentAuthUser.getId() ||ticket.getL4AuthUser() == currentAuthUser.getId() ||ticket.getL5AuthUser() == currentAuthUser.getId();// Permission rules:// 1. CRM user AND ticket has visible subcategory, OR// 2. Has position in ticket's category (can edit even invisible), OR// 3. Is assigned to ticket, OR// 4. Is in escalation chainboolean canEdit = (isCrmUser && isVisibleSubCategory)|| hasPositionInCategory|| isAssigned|| isInEscalationChain;if (!canEdit) {throw new ProfitMandiBusinessException("Ticket", ticketId, "You do not have permission to edit this ticket");}csService.updateTicket(categoryId, subCategoryId, ticket, authUserId, escalationType);model.addAttribute("response1", mvcResponseSender.createResponseString(true));return "response";}@PostMapping(value = "/cs/edit-partner-ticket")public String editPartnerTicket(HttpServletRequest request, @RequestParam(name = "ticketId", defaultValue = "0") int ticketId, @RequestParam(name = "subCategoryId", defaultValue = "0") int subCategoryId, @RequestParam(name = "categoryId", defaultValue = "0") int categoryId, @RequestParam(name = "authUserId", defaultValue = "0") int authUserId, @RequestParam(name = "escalationType", defaultValue = "L1") EscalationType escalationType, Model model) throws Exception {LOGGER.info("Ticket Id {}, CategoryId {}, SubCategory Id {} authUserId {}", ticketId, categoryId, subCategoryId, authUserId);LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);// Only admins can edit partner ticketsif (!roleManager.isAdmin(loginDetails.getRoleIds())) {throw new ProfitMandiBusinessException("Ticket", ticketId, "Only admins can edit partner tickets");}Ticket ticket = ticketRepository.selectById(ticketId);if (ticket == null) {throw new ProfitMandiBusinessException("Ticket", ticketId, "Ticket not found");}// Verify admin has access (must be in Sales, ABM, or RBM position for the partner)AuthUser currentAuthUser = authRepository.selectByEmailOrMobile(loginDetails.getEmailId());Map<String, Set<Integer>> authUserPartnerMap = csService.getAuthUserPartnerIdMapping();Set<Integer> allowedPartnerIds = authUserPartnerMap.get(currentAuthUser.getEmailId());if (allowedPartnerIds == null || !allowedPartnerIds.contains(ticket.getFofoId())) {// Also allow CRM usersboolean isCrmUser = positionRepository.hasCategory(currentAuthUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_CRM);if (!isCrmUser) {throw new ProfitMandiBusinessException("Ticket", ticketId, "You do not have permission to edit this partner's ticket");}}csService.updateTicket(categoryId, subCategoryId, ticket, authUserId, escalationType);model.addAttribute("response1", mvcResponseSender.createResponseString(true));return "response";}@PostMapping(value = "/cs/changeTicketAssignee")public String changeTicketAssignee(HttpServletRequest request, @RequestParam(name = "positionId", defaultValue = "0") int positionId, Model model) throws Exception {Position position = positionRepository.selectById(positionId);if (position.isTicketAssignee()) {position.setTicketAssignee(false);} else {position.setTicketAssignee(true);}model.addAttribute("response1", mvcResponseSender.createResponseString(true));return "response";}@DeleteMapping(value = "/cs/removePosition")public String removePosition(HttpServletRequest request, @RequestParam(name = "positionId", defaultValue = "0") int positionId, Model model) throws Exception {positionRepository.delete(positionId);model.addAttribute("response1", mvcResponseSender.createResponseString(true));return "response";}@PostMapping(value = "/cs/create-last-activity")public String createlastActivity(HttpServletRequest request, @RequestParam(name = "ticketId") int ticketId, @RequestParam(name = "lastactivity") ActivityType lastActivity, Model model) throws Exception {LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);Ticket ticket = ticketRepository.selectById(ticketId);if (ticket == null) {throw new ProfitMandiBusinessException("Ticket", ticketId, "Ticket not found");}// Authorization check for partners: can only update their own ticketsboolean isAdmin = roleManager.isAdmin(loginDetails.getRoleIds());if (!isAdmin && ticket.getFofoId() != loginDetails.getFofoId()) {throw new ProfitMandiBusinessException("Ticket", ticketId, "You do not have permission to update this ticket");}Activity activity = new Activity();String subject = String.format(ACTIVITY_SUBJECT, ticket.getId());if (isAdmin) {// CRM team members can resolve any ticket// Sales team members can resolve their own Sales category tickets// RBM team members can resolve their own RBM category ticketsAuthUser authUser = authRepository.selectByEmailOrMobile(loginDetails.getEmailId());boolean isCrmUser = positionRepository.hasCategory(authUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_CRM);boolean isSalesUser = positionRepository.hasCategory(authUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_SALES);boolean isRbmUser = positionRepository.hasCategory(authUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_RBM);// Check if ticket belongs to Sales or RBM categoryTicketSubCategory ticketSubCategory = ticketSubCategoryRepository.selectById(ticket.getSubCategoryId());boolean isSalesTicket = ticketSubCategory != null && ticketSubCategory.getCategoryId() == ProfitMandiConstants.TICKET_CATEGORY_SALES;boolean isRbmTicket = ticketSubCategory != null && ticketSubCategory.getCategoryId() == ProfitMandiConstants.TICKET_CATEGORY_RBM;// Allow if CRM user OR (Sales user AND Sales ticket) OR (RBM user AND RBM ticket)if (!isCrmUser && !(isSalesUser && isSalesTicket) && !(isRbmUser && isRbmTicket)) {throw new ProfitMandiBusinessException("Ticket", ticketId, "Only CRM, Sales (for Sales tickets), or RBM (for RBM tickets) team can mark tickets as resolved");}ticket.setLastActivity(lastActivity);String to = retailerService.getFofoRetailer(ticket.getFofoId()).getEmail();String message = String.format(PARTNER_RESOLVED_TICKET_MAIL, ticketId, "REOPEN");activity.setMessage(message);activity.setCreatedBy(authUser.getId());activity.setTicketId(ticketId);activity.setCreateTimestamp(LocalDateTime.now());activity.setType(ActivityType.COMMUNICATION_OUT);this.activityRelatedMail(to, null, subject, message);} else {if (ActivityType.RESOLVED_ACCEPTED == lastActivity) {ticket.setLastActivity(lastActivity);ticket.setCloseTimestamp(LocalDateTime.now());activity.setMessage(ActivityType.RESOLVED_ACCEPTED.toString());activity.setCreatedBy(0);activity.setTicketId(ticketId);activity.setType(ActivityType.COMMUNICATION_IN);activity.setCreateTimestamp(LocalDateTime.now());} else {String message = String.format(INTERNAL_REOPEN_MAIL, ticketId, retailerService.getFofoRetailer(loginDetails.getFofoId()).getBusinessName());String to = authRepository.selectById(ticket.getL1AuthUser()).getEmailId();String[] ccTo = authRepository.selectByIds(Arrays.asList(ticket.getL2AuthUser(), ticket.getL3AuthUser(), ticket.getL4AuthUser(), ticket.getL5AuthUser())).stream().map(x -> x.getEmailId()).toArray(String[]::new);ticket.setLastActivity(lastActivity);ticket.setUpdateTimestamp(LocalDateTime.now());ticketAssignedRepository.deleteByTicketId(ticketId);TicketAssigned ticketAssigned = new TicketAssigned();ticketAssigned.setAssineeId(ticket.getL1AuthUser());ticketAssigned.setTicketId(ticketId);ticketAssignedRepository.persist(ticketAssigned);activity.setMessage(INTERNAL_REOPEN_ACTIVITY_MESSAGE);activity.setCreatedBy(0);activity.setTicketId(ticketId);activity.setType(ActivityType.COMMUNICATION_IN);activity.setCreateTimestamp(LocalDateTime.now());this.activityRelatedMail(to, ccTo, subject, message);this.activityRelatedMail(retailerService.getFofoRetailer(loginDetails.getFofoId()).getEmail(), null, subject, String.format(PARTNER_REOPEN, ticketId));}}activityRepository.persist(activity);model.addAttribute("response1", mvcResponseSender.createResponseString(true));return "response";}@PostMapping(value = "/partner-position/update")public String positionUpdated(Model model, @RequestBody List<PartnerPositonUpdateModel> partnerPositionUpdateModels)throws Exception {Map<Integer, List<String>> positionIdsToAddMap = partnerPositionUpdateModels.stream().filter(x->x.getPositionIdTo()!=0).collect(Collectors.groupingBy(x->x.getPositionIdTo(),Collectors.mapping(x->x.getStoreCode(), Collectors.toList())));Map<Integer, List<String>> positionIdsToRemoveMap = partnerPositionUpdateModels.stream().filter(x->x.getPositionIdFrom()!=0).collect(Collectors.groupingBy(x->x.getPositionIdFrom(),Collectors.mapping(x->x.getStoreCode(), Collectors.toList())));List<Integer> positionIdsToUpdate = new ArrayList<>();positionIdsToUpdate.addAll(positionIdsToAddMap.keySet());positionIdsToUpdate.addAll(positionIdsToRemoveMap.keySet());Map<Integer, Position> positionsToUpdateMap = positionRepository.selectByIds(positionIdsToUpdate).stream().collect(Collectors.toMap(x->x.getId(), x->x));List<Integer> invalidPositionIds = positionsToUpdateMap.values().stream().filter(x-> x.getCategoryId()!= ProfitMandiConstants.TICKET_CATEGORY_RBM&& x.getCategoryId() != ProfitMandiConstants.TICKET_CATEGORY_SALES && x.getCategoryId() != ProfitMandiConstants.TICKET_CATEGORY_ABM).map(x -> x.getId()).collect(Collectors.toList());if(invalidPositionIds.size() > 0) {String message = "Non RBM/Sales/ABM are not allowed - " + invalidPositionIds;throw new ProfitMandiBusinessException(message, message, message);}for (Map.Entry<Integer, List<String>> positionIdStoreMapEntry : positionIdsToAddMap.entrySet()) {int positionId = positionIdStoreMapEntry.getKey();Position position = positionsToUpdateMap.get(positionId);LOGGER.info("positionId - {}, Position - {}", positionId, position);List<String> storeCodesToAdd = positionIdStoreMapEntry.getValue();List<Integer> retailerIdsToAdd = fofoStoreRepository.selectByStoreCodes(storeCodesToAdd).stream().map(x->x.getId()).collect(Collectors.toList());Map<Integer, PartnerPosition> partnerPositionsMapByFofoId = partnerPositionRepository.selectByRegionIdAndPostionId(Arrays.asList(position.getRegionId()),Arrays.asList(positionId)).stream().collect(Collectors.toMap(x->x.getFofoId(),x->x));for (Integer retailerIdToAdd : retailerIdsToAdd) {if (!partnerPositionsMapByFofoId.containsKey(retailerIdToAdd)) {PartnerPosition partnerPositionNew = new PartnerPosition();partnerPositionNew.setPositionId(positionId);partnerPositionNew.setFofoId(retailerIdToAdd);partnerPositionNew.setRegionId(position.getRegionId());partnerPositionRepository.persist(partnerPositionNew);}}}for (Map.Entry<Integer, List<String>> positionIdStoreMapEntry : positionIdsToRemoveMap.entrySet()) {int positionId = positionIdStoreMapEntry.getKey();Position position = positionsToUpdateMap.get(positionId);List<String> storeCodesToRemove = positionIdStoreMapEntry.getValue();List<Integer> retailerIdsToRemove = fofoStoreRepository.selectByStoreCodes(storeCodesToRemove).stream().map(x->x.getId()).collect(Collectors.toList());Map<Integer, PartnerPosition> partnerPositionsMapByFofoId = partnerPositionRepository.selectByRegionIdAndPostionId(Arrays.asList(position.getRegionId()),Arrays.asList(positionId)).stream().collect(Collectors.toMap(x->x.getFofoId(),x->x));for (Integer retailerIdToRemove : retailerIdsToRemove) {if (partnerPositionsMapByFofoId.containsKey(retailerIdToRemove)) {PartnerPosition partnerPositionToRemove = partnerPositionsMapByFofoId.get(retailerIdToRemove);partnerPositionRepository.delete(partnerPositionToRemove);}}}/*partnerPositionUpdateModels.strMap<Integer, Position> positionIdMap = positionsToUpdate.stream().collect(Collectors.toMap(x->x.getId(), x->x));for (PartnerPositonUpdateModel partnerPositionUpdateModel : partnerPositionUpdateModels) {FofoStore fofoStore = fofoStoreRepository.selectByStoreCode(partnerPositionUpdateModel.getStoreCode());Position positionFrom = positionIdMap.get(partnerPositionUpdateModel.getPositionIdFrom());Position positionTo = positionIdMap.get(partnerPositionUpdateModel.getPositionIdTo());if(positionFrom != null) {partnerPositionRepository.selectByRegionIdAndPostionId(Arrays.)int regionId = positionFrom.getRegionId()}if(positionTo != null) {}}*/model.addAttribute("response1", mvcResponseSender.createResponseString(true));return "response";}@PostMapping(value = "/cs/markTicketRead")@ResponseBodypublic Map<String, Object> markTicketRead(HttpServletRequest request,@RequestParam(name = "ticketId") int ticketId,Model model) throws ProfitMandiBusinessException {LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);boolean isAdmin = roleManager.isAdmin(loginDetails.getRoleIds());Map<String, Object> response = new HashMap<>();if (isAdmin) {AuthUser authUser = authRepository.selectByEmailOrMobile(loginDetails.getEmailId());csService.markTicketAsRead(ticketId, authUser.getId(), UserType.AUTH_USER);} else {csService.markTicketAsRead(ticketId, loginDetails.getFofoId(), UserType.PARTNER);}response.put("success", true);return response;}@GetMapping(value = "/cs/unreadCount")@ResponseBodypublic Map<String, Object> getUnreadCount(HttpServletRequest request) throws ProfitMandiBusinessException {LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);boolean isAdmin = roleManager.isAdmin(loginDetails.getRoleIds());Map<String, Object> response = new HashMap<>();List<Ticket> tickets;int userId;UserType userType;if (isAdmin) {AuthUser authUser = authRepository.selectByEmailOrMobile(loginDetails.getEmailId());userId = authUser.getId();userType = UserType.AUTH_USER;boolean isCrmUser = positionRepository.hasCategory(authUser.getId(), ProfitMandiConstants.TICKET_CATEGORY_CRM);List<Integer> userCategoryIds = positionRepository.selectCategoryIdsByAuthUserId(authUser.getId());if (isCrmUser) {tickets = ticketRepository.selectAllTicketsPaginated(Optional.of(false), null, null, 0, null,userCategoryIds, 0, 1000);} else {tickets = ticketRepository.selectAllByAssigneePaginated(authUser.getId(), Optional.of(false), null, null, 0, null,0, 1000);}} else {userId = loginDetails.getFofoId();userType = UserType.PARTNER;tickets = ticketRepository.selectAllByCreator(loginDetails.getFofoId(), Optional.of(true), null);}Map<Integer, Boolean> unreadMap = csService.getUnreadStatusForTickets(tickets, userId, userType);long unreadCount = unreadMap.values().stream().filter(v -> v).count();response.put("success", true);response.put("unreadCount", unreadCount);return response;}}