// src/services/jiraService.js import jira from '../integrations/jira/JiraClient.js'; import { logger } from '../utils/logger.js'; const componentMap = { av: 'Audio Visual', audio: 'Audio Visual', visual: 'Audio Visual', voice: 'Communication Services', phone: 'Communication Services', phones: 'Communication Services', telephony: 'Communication Services', comm: 'Communication Services', mobility: 'Mobility', mobile: 'Mobility', wireless: 'Mobility', }; const projects = ['SUPPORT', 'SS']; // ==================== STORE + COMPONENT ==================== export async function getJiraTicketsForComponentWithStore(storeNumber, componentInput) { if (!storeNumber || !componentInput) return []; const normalized = componentInput.toLowerCase().trim(); const componentName = componentMap[normalized] || componentInput; const paddedStore = storeNumber.toString().padStart(5, '0'); const projectClause = projects.map(p => `project = ${p}`).join(' OR '); const jql = `(${projectClause}) AND "Store Number" = "${paddedStore}" AND component = "${componentName}" ORDER BY updated DESC`; try { const result = await jira.search(jql, 'key,summary,status,resolution,assignee,created,resolved,components', 20); return result.issues || []; } catch (err) { logger('jira:service', `Failed store+component search`, 'warn'); return []; } } // ==================== STORE ONLY ==================== export async function getJiraTicketsForStore(storeNumber) { if (!storeNumber) return []; const paddedStore = storeNumber.toString().padStart(5, '0'); const projectClause = projects.map(p => `project = ${p}`).join(' OR '); const jql = `(${projectClause}) AND "Store Number" = "${paddedStore}" ORDER BY updated DESC`; logger('jira:service', `Searching store ${paddedStore} with JQL: ${jql}`, 'debug'); try { const result = await jira.search(jql, 'key,summary,status,resolution,assignee,created,resolved,components', 30); logger('jira:service', `Found ${result.issues?.length || 0} tickets for store ${paddedStore}`, 'debug'); return result.issues || []; } catch (err) { logger('jira:service', `Failed store search for ${paddedStore}: ${err.message}`, 'error'); return []; } } // ==================== COMPONENT ONLY ==================== export async function getJiraTicketsForComponent(componentInput) { if (!componentInput) return []; const normalized = componentInput.toLowerCase().trim(); const componentName = componentMap[normalized] || componentInput; const projectClause = projects.map(p => `project = ${p}`).join(' OR '); const jql = `(${projectClause}) AND component = "${componentName}" ORDER BY updated DESC`; try { const result = await jira.search(jql, 'key,summary,status,resolution,assignee,created,resolved,components', 15); return result.issues || []; } catch (err) { logger('jira:service', `Failed component search`, 'error'); return []; } } // ==================== SHARED HELPERS (for commands consistency) ==================== export function getStatusEmoji(status) { const s = (status || '').toLowerCase(); if (s.includes('resolved') || s.includes('done') || s.includes('fixed')) return '✅'; if (s.includes('in progress') || s.includes('open')) return '🔄'; if (s.includes('pending')) return '⏳'; return '📌'; } export function calculateDaysOpen(created, resolvedOrUpdated) { if (!created) return '—'; const start = new Date(created); const end = resolvedOrUpdated ? new Date(resolvedOrUpdated) : new Date(); const diffTime = Math.abs(end - start); const days = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); return isNaN(days) ? '—' : days; }