Subversion Repositories SmartDukaan

Rev

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

Rev 35879 Rev 36000
Line 1... Line 1...
1
package com.spice.profitmandi.web.service;
1
package com.spice.profitmandi.web.service;
2
 
2
 
-
 
3
import com.spice.profitmandi.dao.entity.cs.RbmBreakLog;
-
 
4
import com.spice.profitmandi.dao.repository.cs.RbmBreakLogRepository;
-
 
5
import org.apache.logging.log4j.LogManager;
-
 
6
import org.apache.logging.log4j.Logger;
3
import org.hibernate.Session;
7
import org.hibernate.Session;
4
import org.hibernate.SessionFactory;
8
import org.hibernate.SessionFactory;
5
import org.springframework.beans.factory.annotation.Autowired;
9
import org.springframework.beans.factory.annotation.Autowired;
6
import org.springframework.stereotype.Service;
10
import org.springframework.stereotype.Service;
-
 
11
import org.springframework.transaction.PlatformTransactionManager;
-
 
12
import org.springframework.transaction.TransactionStatus;
-
 
13
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
-
 
14
import org.springframework.transaction.support.TransactionTemplate;
7
 
15
 
8
import javax.annotation.PostConstruct;
16
import javax.annotation.PostConstruct;
-
 
17
import java.time.LocalDate;
9
import java.time.LocalDateTime;
18
import java.time.LocalDateTime;
10
import java.util.ArrayList;
19
import java.util.ArrayList;
11
import java.util.List;
20
import java.util.List;
12
import java.util.Map;
21
import java.util.Map;
13
import java.util.concurrent.ConcurrentHashMap;
22
import java.util.concurrent.ConcurrentHashMap;
14
 
23
 
15
@Service
24
@Service
16
public class AgentLiveStatusService {
25
public class AgentLiveStatusService {
17
 
26
 
-
 
27
    private static final Logger LOGGER = LogManager.getLogger(AgentLiveStatusService.class);
-
 
28
 
18
    // In-memory map to store agent status by authId
29
    // In-memory map to store agent status by authId
19
    private final Map<Integer, AgentStatus> agentStatusMap = new ConcurrentHashMap<>();
30
    private final Map<Integer, AgentStatus> agentStatusMap = new ConcurrentHashMap<>();
20
    // Caller ID (Knowlarity SR Number) to Auth ID mapping (loaded from sip_master)
31
    // Caller ID (Knowlarity SR Number) to Auth ID mapping (loaded from sip_master)
21
    private final Map<String, Integer> callerIdToAuthIdMap = new ConcurrentHashMap<>();
32
    private final Map<String, Integer> callerIdToAuthIdMap = new ConcurrentHashMap<>();
22
    // SR Number to Auth ID mapping (loaded from sip_master)
33
    // SR Number to Auth ID mapping (loaded from sip_master)
23
    private final Map<String, Integer> srNumberToAuthIdMap = new ConcurrentHashMap<>();
34
    private final Map<String, Integer> srNumberToAuthIdMap = new ConcurrentHashMap<>();
24
    // Agent name to Auth ID mapping (fallback)
35
    // Agent name to Auth ID mapping (fallback)
25
    private final Map<String, Integer> agentNameToAuthIdMap = new ConcurrentHashMap<>();
36
    private final Map<String, Integer> agentNameToAuthIdMap = new ConcurrentHashMap<>();
-
 
37
 
26
    @Autowired
38
    @Autowired
27
    private SessionFactory sessionFactory;
39
    private SessionFactory sessionFactory;
-
 
40
 
-
 
41
    @Autowired
-
 
42
    private RbmBreakLogRepository rbmBreakLogRepository;
-
 
43
 
-
 
44
    @Autowired
-
 
45
    private PlatformTransactionManager transactionManager;
-
 
46
 
-
 
47
    private TransactionTemplate transactionTemplate;
-
 
48
 
28
    private String lastError = null;
49
    private String lastError = null;
29
    private int lastQueryCount = 0;
50
    private int lastQueryCount = 0;
30
 
51
 
31
    /**
52
    /**
32
     * Load mapping from sip_master table on startup
53
     * Load mapping from sip_master table on startup
33
     * caller_id in sip_master = SR Number on Knowlarity dashboard
54
     * caller_id in sip_master = SR Number on Knowlarity dashboard
34
     * sip_master has auth_id directly
55
     * sip_master has auth_id directly
35
     */
56
     */
36
    @PostConstruct
57
    @PostConstruct
37
    public void loadMappingFromDatabase() {
58
    public void loadMappingFromDatabase() {
-
 
59
        this.transactionTemplate = new TransactionTemplate(transactionManager);
38
        try {
60
        try {
39
            Session session = sessionFactory.openSession();
61
            Session session = sessionFactory.openSession();
40
 
62
 
41
            // Query to get caller_id, auth_user.id, first_name from sip_master
63
            // Query to get caller_id, auth_user.id, first_name from sip_master
42
            // Join with auth_user to get correct auth_id used by rbm_call_target page
64
            // Join with auth_user to get correct auth_id used by rbm_call_target page
Line 143... Line 165...
143
        srNumberToAuthIdMap.clear();
165
        srNumberToAuthIdMap.clear();
144
        agentNameToAuthIdMap.clear();
166
        agentNameToAuthIdMap.clear();
145
    }
167
    }
146
 
168
 
147
    public void updateStatus(int authId, String srNumber, String agentName, String agentStatus, String timeInStatus, String customerNumber) {
169
    public void updateStatus(int authId, String srNumber, String agentName, String agentStatus, String timeInStatus, String customerNumber) {
-
 
170
        // Get previous status to detect change
-
 
171
        AgentStatus previousStatus = agentStatusMap.get(authId);
-
 
172
 
-
 
173
        // Check if status has changed
-
 
174
        if (previousStatus != null && previousStatus.getAgentStatus() != null) {
-
 
175
            String prevStatusStr = previousStatus.getAgentStatus();
-
 
176
            String newStatusStr = agentStatus != null ? agentStatus : "";
-
 
177
 
-
 
178
            // If status changed, save the previous status duration to RbmBreakLog
-
 
179
            if (!prevStatusStr.equalsIgnoreCase(newStatusStr)) {
-
 
180
                // Only track Available and Break statuses
-
 
181
                if (isTrackableStatus(prevStatusStr)) {
-
 
182
                    String prevTimeInStatus = previousStatus.getTimeInStatus();
-
 
183
                    int durationSeconds = parseTimeInStatusToSeconds(prevTimeInStatus);
-
 
184
 
-
 
185
                    // Calculate the START TIME when agent entered this status
-
 
186
                    // startTime = now - duration
-
 
187
                    LocalDateTime statusStartTime = LocalDateTime.now().minusSeconds(durationSeconds);
-
 
188
 
-
 
189
                    LOGGER.info("Status changed for {} (authId={}): '{}' -> '{}', started at: {}, duration: {} ({}s)",
-
 
190
                            agentName, authId, prevStatusStr, newStatusStr, statusStartTime, prevTimeInStatus, durationSeconds);
-
 
191
 
-
 
192
                    // Save to RbmBreakLog with START TIME
-
 
193
                    saveStatusDuration(authId, agentName, srNumber, prevStatusStr, prevTimeInStatus, durationSeconds, statusStartTime);
-
 
194
                }
-
 
195
            }
-
 
196
        }
-
 
197
 
-
 
198
        // Update current status
148
        AgentStatus status = new AgentStatus(authId, srNumber, agentName, agentStatus, timeInStatus, customerNumber);
199
        AgentStatus status = new AgentStatus(authId, srNumber, agentName, agentStatus, timeInStatus, customerNumber);
149
        agentStatusMap.put(authId, status);
200
        agentStatusMap.put(authId, status);
150
    }
201
    }
151
 
202
 
-
 
203
    /**
-
 
204
     * Check if status should be tracked (Only Available and Break)
-
 
205
     */
-
 
206
    private boolean isTrackableStatus(String status) {
-
 
207
        if (status == null || status.isEmpty()) return false;
-
 
208
        String lower = status.toLowerCase();
-
 
209
        return lower.contains("available") || lower.contains("break");
-
 
210
    }
-
 
211
 
-
 
212
    /**
-
 
213
     * Parse timeInStatus string (e.g., "00:05:30" or "5m 30s") to seconds
-
 
214
     */
-
 
215
    private int parseTimeInStatusToSeconds(String timeInStatus) {
-
 
216
        if (timeInStatus == null || timeInStatus.isEmpty()) return 0;
-
 
217
 
-
 
218
        try {
-
 
219
            // Format: HH:mm:ss or H:mm:ss
-
 
220
            if (timeInStatus.contains(":")) {
-
 
221
                String[] parts = timeInStatus.split(":");
-
 
222
                if (parts.length == 3) {
-
 
223
                    int hours = Integer.parseInt(parts[0].trim());
-
 
224
                    int minutes = Integer.parseInt(parts[1].trim());
-
 
225
                    int seconds = Integer.parseInt(parts[2].trim());
-
 
226
                    return hours * 3600 + minutes * 60 + seconds;
-
 
227
                } else if (parts.length == 2) {
-
 
228
                    int minutes = Integer.parseInt(parts[0].trim());
-
 
229
                    int seconds = Integer.parseInt(parts[1].trim());
-
 
230
                    return minutes * 60 + seconds;
-
 
231
                }
-
 
232
            }
-
 
233
 
-
 
234
            // Format: "5m 30s" or "1h 5m 30s"
-
 
235
            int totalSeconds = 0;
-
 
236
            String lower = timeInStatus.toLowerCase();
-
 
237
            if (lower.contains("h")) {
-
 
238
                String hourPart = lower.split("h")[0].trim();
-
 
239
                totalSeconds += Integer.parseInt(hourPart.replaceAll("[^0-9]", "")) * 3600;
-
 
240
            }
-
 
241
            if (lower.contains("m")) {
-
 
242
                String minPart = lower.contains("h") ? lower.split("h")[1].split("m")[0] : lower.split("m")[0];
-
 
243
                totalSeconds += Integer.parseInt(minPart.trim().replaceAll("[^0-9]", "")) * 60;
-
 
244
            }
-
 
245
            if (lower.contains("s") && !lower.contains("h") && !lower.contains("m")) {
-
 
246
                totalSeconds += Integer.parseInt(lower.replaceAll("[^0-9]", ""));
-
 
247
            } else if (lower.contains("s")) {
-
 
248
                String secPart = lower.split("m")[1].split("s")[0];
-
 
249
                totalSeconds += Integer.parseInt(secPart.trim().replaceAll("[^0-9]", ""));
-
 
250
            }
-
 
251
            return totalSeconds;
-
 
252
 
-
 
253
        } catch (Exception e) {
-
 
254
            LOGGER.warn("Could not parse timeInStatus: {}", timeInStatus);
-
 
255
            return 0;
-
 
256
        }
-
 
257
    }
-
 
258
 
-
 
259
    /**
-
 
260
     * Save status duration to RbmBreakLog
-
 
261
     *
-
 
262
     * @param statusStartTime - the time when agent ENTERED this status (start time)
-
 
263
     */
-
 
264
    private void saveStatusDuration(int authId, String agentName, String srNumber, String status,
-
 
265
                                    String durationDisplay, int durationSeconds, LocalDateTime statusStartTime) {
-
 
266
        try {
-
 
267
            transactionTemplate.execute(new TransactionCallbackWithoutResult() {
-
 
268
                @Override
-
 
269
                protected void doInTransactionWithoutResult(TransactionStatus txStatus) {
-
 
270
                    LocalDate logDate = statusStartTime.toLocalDate();
-
 
271
 
-
 
272
                    LOGGER.info("Saving status duration: agent={}, status={}, startTime={}, duration={}s ({})",
-
 
273
                            agentName, status, statusStartTime, durationSeconds, durationDisplay);
-
 
274
 
-
 
275
                    RbmBreakLog breakLog = new RbmBreakLog(
-
 
276
                            authId,
-
 
277
                            agentName,
-
 
278
                            srNumber,
-
 
279
                            status,
-
 
280
                            statusStartTime,  // Use START TIME when agent entered this status
-
 
281
                            durationSeconds,
-
 
282
                            durationDisplay,
-
 
283
                            logDate
-
 
284
                    );
-
 
285
                    rbmBreakLogRepository.persist(breakLog);
-
 
286
                }
-
 
287
            });
-
 
288
        } catch (Exception e) {
-
 
289
            LOGGER.error("Error saving status duration for {}: {}", agentName, e.getMessage());
-
 
290
        }
-
 
291
    }
-
 
292
 
152
    public AgentStatus getStatusByAuthId(int authId) {
293
    public AgentStatus getStatusByAuthId(int authId) {
153
        return agentStatusMap.get(authId);
294
        return agentStatusMap.get(authId);
154
    }
295
    }
155
 
296
 
156
    public Map<Integer, AgentStatus> getAllStatusMap() {
297
    public Map<Integer, AgentStatus> getAllStatusMap() {