diff --git a/apps/ops/src/modules/dispatch/components/RightPanel.vue b/apps/ops/src/modules/dispatch/components/RightPanel.vue index a156496..04f19ba 100644 --- a/apps/ops/src/modules/dispatch/components/RightPanel.vue +++ b/apps/ops/src/modules/dispatch/components/RightPanel.vue @@ -116,6 +116,7 @@ const onDeleteTag = inject('onDeleteTag') 📝 Répondre dans legacy + 📺 Activer STB (Ministra) diff --git a/apps/ops/src/stores/dispatch.js b/apps/ops/src/stores/dispatch.js index 1edd46c..8e358e6 100644 --- a/apps/ops/src/stores/dispatch.js +++ b/apps/ops/src/stores/dispatch.js @@ -58,6 +58,7 @@ export const useDispatchStore = defineStore('dispatch', () => { jobType: j.job_type || null, legacyDept: j.legacy_dept || null, // département osTicket legacy → coloriage par type legacyTicketId: j.legacy_ticket_id || null, // n° ticket legacy (affiché dans le panneau détail) + legacyActivationUrl: j.legacy_activation_url || null, // lien connect_ministra (activation STB TV) parentJob: j.parent_job || null, stepOrder: j.step_order || 0, onOpenWebhook: j.on_open_webhook || null, diff --git a/services/targo-hub/lib/legacy-dispatch-sync.js b/services/targo-hub/lib/legacy-dispatch-sync.js index 0e4c3b8..aafa21f 100644 --- a/services/targo-hub/lib/legacy-dispatch-sync.js +++ b/services/targo-hub/lib/legacy-dispatch-sync.js @@ -63,11 +63,19 @@ function pool () { return _pool } +// Lien d'activation STB/Ministra : DÉJÀ posté dans le fil du ticket par le wizard legacy à la vente. +// On le ré-extrait tel quel (zéro reconstruction). Sous-requête = le ticket_msg le plus récent qui le contient. +const ACTIVATION_RE = /https?:\/\/[^\s"'<>]*connect_ministra\.php[^\s"'<>]*/i +function extractActivationUrl (msg) { if (!msg) return ''; const m = String(msg).match(ACTIVATION_RE); return m ? m[0] : '' } + async function fetchTargoTickets () { const p = pool(); if (!p) throw new Error('mysql2 indisponible sur le hub') const [rows] = await p.query( `SELECT t.id, t.subject, t.dept_id, dd.name AS dept, t.due_date, t.due_time, t.priority, t.bon_id, t.account_id, - a.first_name, a.last_name, a.company, a.address1, a.address2, a.city, a.state, a.zip + a.first_name, a.last_name, a.company, a.address1, a.address2, a.city, a.state, a.zip, + (SELECT mm.msg FROM ticket_msg mm + WHERE mm.ticket_id = t.id AND mm.msg LIKE '%connect_ministra%' + ORDER BY mm.id DESC LIMIT 1) AS activation_msg FROM ticket t LEFT JOIN ticket_dept dd ON dd.id = t.dept_id LEFT JOIN account a ON a.id = t.account_id @@ -126,6 +134,7 @@ async function buildJob (t) { legacy_ticket_id: String(t.id), legacy_dept: t.dept || '', // département legacy granulaire → coloriage « comme legacy » (Installation Fibre / Réparation Fibre / Télé / Téléphonie…) } + const actUrl = extractActivationUrl(t.activation_msg); if (actUrl) payload.legacy_activation_url = actUrl // lien connect_ministra (déjà dans le fil) const sd = tzDate(t.due_date); if (sd) payload.scheduled_date = sd const st = startTime(t.due_time); if (st) payload.start_time = st if (cust) payload.customer = cust.name @@ -138,7 +147,7 @@ async function buildJob (t) { } async function findExisting (legacyId) { - const r = await erp.list('Dispatch Job', { filters: [['legacy_ticket_id', '=', legacyId]], fields: ['name', 'status', 'assigned_tech', 'scheduled_date', 'legacy_dept'], limit: 1 }) + const r = await erp.list('Dispatch Job', { filters: [['legacy_ticket_id', '=', legacyId]], fields: ['name', 'status', 'assigned_tech', 'scheduled_date', 'legacy_dept', 'legacy_activation_url'], limit: 1 }) return (r && r[0]) || null } @@ -158,6 +167,7 @@ async function sync ({ dryRun = false } = {}) { // s'il est encore au pool (open + non assigné) → on ne clobbe jamais le travail du répartiteur. const patch = {} if (!ex.legacy_dept && b.payload.legacy_dept) patch.legacy_dept = b.payload.legacy_dept + if (!ex.legacy_activation_url && b.payload.legacy_activation_url) patch.legacy_activation_url = b.payload.legacy_activation_url // backfill lien activation (sans risque) if (ex.status === 'open' && !ex.assigned_tech && b.payload.scheduled_date && b.payload.scheduled_date !== ex.scheduled_date) patch.scheduled_date = b.payload.scheduled_date if (!dryRun && Object.keys(patch).length) { await erp.update('Dispatch Job', ex.name, patch); updated++; details.push({ legacy_id: b.legacy_id, action: 'update', job: ex.name, patch }) } else skipped++