feat(dispatch): bouton « Activer STB (Ministra) » — lien d'activation TV extrait du ticket legacy (Phase 1)
- pont : extrait le lien connect_ministra.php du ticket_msg (déjà posté par le wizard legacy à la vente)
→ champ legacy_activation_url sur le Dispatch Job (backfill des 10 tickets TV). Read-only legacy, aucun 2e
chemin d'écriture → zéro risque de double-facturation (cf. analyse processus).
- store _mapJob : expose legacyActivationUrl ; RightPanel : bouton violet « 📺 Activer STB (Ministra) »
(MÊME lien que le tech reçoit, ouvre connect_ministra.php avec tid/did/sid/cr/m intacts).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
15976342e4
commit
4b377eb887
|
|
@ -116,6 +116,7 @@ const onDeleteTag = inject('onDeleteTag')
|
||||||
<button class="sb-rp-btn" @click="emit('move', panel.data.job, panel.data.tech?.id)">↔ Déplacer / Réassigner</button>
|
<button class="sb-rp-btn" @click="emit('move', panel.data.job, panel.data.tech?.id)">↔ Déplacer / Réassigner</button>
|
||||||
<button class="sb-rp-btn" @click="emit('geofix', panel.data.job)">📍 Géofixer sur la carte</button>
|
<button class="sb-rp-btn" @click="emit('geofix', panel.data.job)">📍 Géofixer sur la carte</button>
|
||||||
<a v-if="legacyReplyUrl(panel.data?.job)" class="sb-rp-btn" :href="legacyReplyUrl(panel.data.job)" target="_blank" rel="noopener" style="text-decoration:none;text-align:center">📝 Répondre dans legacy</a>
|
<a v-if="legacyReplyUrl(panel.data?.job)" class="sb-rp-btn" :href="legacyReplyUrl(panel.data.job)" target="_blank" rel="noopener" style="text-decoration:none;text-align:center">📝 Répondre dans legacy</a>
|
||||||
|
<a v-if="panel.data?.job?.legacyActivationUrl" class="sb-rp-btn" :href="panel.data.job.legacyActivationUrl" target="_blank" rel="noopener" style="text-decoration:none;text-align:center;background:#7e3ff2;color:#fff;border-color:#7e3ff2" title="Connecter / activer le(s) STB sur Ministra (lien legacy du ticket)">📺 Activer STB (Ministra)</a>
|
||||||
<button v-if="panel.data?.job?.assignedTech" class="sb-rp-btn sb-ctx-warn" @click="emit('unassign', panel.data.job)">✕ Désaffecter</button>
|
<button v-if="panel.data?.job?.assignedTech" class="sb-rp-btn sb-ctx-warn" @click="emit('unassign', panel.data.job)">✕ Désaffecter</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,7 @@ export const useDispatchStore = defineStore('dispatch', () => {
|
||||||
jobType: j.job_type || null,
|
jobType: j.job_type || null,
|
||||||
legacyDept: j.legacy_dept || null, // département osTicket legacy → coloriage par type
|
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)
|
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,
|
parentJob: j.parent_job || null,
|
||||||
stepOrder: j.step_order || 0,
|
stepOrder: j.step_order || 0,
|
||||||
onOpenWebhook: j.on_open_webhook || null,
|
onOpenWebhook: j.on_open_webhook || null,
|
||||||
|
|
|
||||||
|
|
@ -63,11 +63,19 @@ function pool () {
|
||||||
return _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 () {
|
async function fetchTargoTickets () {
|
||||||
const p = pool(); if (!p) throw new Error('mysql2 indisponible sur le hub')
|
const p = pool(); if (!p) throw new Error('mysql2 indisponible sur le hub')
|
||||||
const [rows] = await p.query(
|
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,
|
`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
|
FROM ticket t
|
||||||
LEFT JOIN ticket_dept dd ON dd.id = t.dept_id
|
LEFT JOIN ticket_dept dd ON dd.id = t.dept_id
|
||||||
LEFT JOIN account a ON a.id = t.account_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_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…)
|
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 sd = tzDate(t.due_date); if (sd) payload.scheduled_date = sd
|
||||||
const st = startTime(t.due_time); if (st) payload.start_time = st
|
const st = startTime(t.due_time); if (st) payload.start_time = st
|
||||||
if (cust) payload.customer = cust.name
|
if (cust) payload.customer = cust.name
|
||||||
|
|
@ -138,7 +147,7 @@ async function buildJob (t) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function findExisting (legacyId) {
|
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
|
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.
|
// s'il est encore au pool (open + non assigné) → on ne clobbe jamais le travail du répartiteur.
|
||||||
const patch = {}
|
const patch = {}
|
||||||
if (!ex.legacy_dept && b.payload.legacy_dept) patch.legacy_dept = b.payload.legacy_dept
|
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 (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 }) }
|
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++
|
else skipped++
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user