/** * Payment actions composable — agent-facing payment operations via targo-hub */ import { ref } from 'vue' import { Notify } from 'quasar' import { HUB_SSE_URL } from 'src/config/dispatch' const HUB = HUB_SSE_URL async function hubFetch (path, opts = {}) { const res = await fetch(HUB + path, { method: opts.method || 'GET', headers: { 'Content-Type': 'application/json', ...opts.headers }, ...(opts.body ? { body: JSON.stringify(opts.body) } : {}), }) if (!res.ok) { const err = await res.json().catch(() => ({ error: 'Request failed' })) throw new Error(err.error || `HTTP ${res.status}`) } return res.json() } export function usePaymentActions (customer) { const loading = ref(false) const sendingLink = ref(false) const chargingCard = ref(false) const togglingPpa = ref(false) async function fetchBalance () { if (!customer.value?.name) return null try { return await hubFetch(`/payments/balance/${encodeURIComponent(customer.value.name)}`) } catch (e) { console.error('Balance fetch error:', e) return null } } async function fetchMethods () { if (!customer.value?.name) return [] try { const res = await hubFetch(`/payments/methods/${encodeURIComponent(customer.value.name)}`) return res.methods || [] } catch (e) { console.error('Methods fetch error:', e) return [] } } async function sendPaymentLink (channel = 'both') { sendingLink.value = true try { const res = await hubFetch('/payments/send-link', { method: 'POST', body: { customer: customer.value.name, channel }, }) const sentVia = res.sent?.join(' + ') || 'aucun' Notify.create({ type: 'positive', message: `Lien de paiement envoyé (${sentVia}) — ${res.amount}$`, position: 'top' }) return res } catch (e) { Notify.create({ type: 'negative', message: `Erreur: ${e.message}`, position: 'top' }) } finally { sendingLink.value = false } } async function chargeCard (amount) { chargingCard.value = true try { const res = await hubFetch('/payments/charge', { method: 'POST', body: { customer: customer.value.name, ...(amount ? { amount } : {}) }, }) if (res.ok) { Notify.create({ type: 'positive', message: `Paiement de ${res.amount}$ prélevé avec succès`, position: 'top' }) } else { Notify.create({ type: 'warning', message: `Statut: ${res.status} — vérifier Stripe`, position: 'top' }) } return res } catch (e) { Notify.create({ type: 'negative', message: `Erreur prélèvement: ${e.message}`, position: 'top' }) } finally { chargingCard.value = false } } async function togglePpa (enabled) { togglingPpa.value = true try { await hubFetch('/payments/toggle-ppa', { method: 'POST', body: { customer: customer.value.name, enabled }, }) Notify.create({ type: 'positive', message: enabled ? 'PPA activé' : 'PPA désactivé', position: 'top', }) return true } catch (e) { Notify.create({ type: 'negative', message: `Erreur PPA: ${e.message}`, position: 'top' }) return false } finally { togglingPpa.value = false } } async function openPortal () { loading.value = true try { const res = await hubFetch('/payments/portal', { method: 'POST', body: { customer: customer.value.name }, }) if (res.url) window.open(res.url, '_blank') } catch (e) { Notify.create({ type: 'negative', message: `Erreur: ${e.message}`, position: 'top' }) } finally { loading.value = false } } async function createCheckout () { loading.value = true try { const res = await hubFetch('/payments/checkout', { method: 'POST', body: { customer: customer.value.name }, }) // Copy URL to clipboard for the agent to share if (res.url) { await navigator.clipboard?.writeText(res.url) Notify.create({ type: 'info', message: `Lien copié — ${res.amount}$. Ouvre dans un nouvel onglet.`, position: 'top', timeout: 4000 }) window.open(res.url, '_blank') } return res } catch (e) { Notify.create({ type: 'negative', message: `Erreur: ${e.message}`, position: 'top' }) } finally { loading.value = false } } const refunding = ref(false) async function refundPayment (paymentEntry, amount, reason) { refunding.value = true try { const res = await hubFetch('/payments/refund', { method: 'POST', body: { payment_entry: paymentEntry, amount: amount || undefined, reason }, }) if (res.ok) { const msg = res.stripe_refund ? `Remboursement Stripe ${res.amount}$ (${res.stripe_refund.id})` : `Remboursement ${res.amount}$ enregistré` Notify.create({ type: 'positive', message: msg, position: 'top' }) if (res.warning) { Notify.create({ type: 'warning', message: res.warning, position: 'top', timeout: 8000 }) } } return res } catch (e) { Notify.create({ type: 'negative', message: `Erreur remboursement: ${e.message}`, position: 'top' }) } finally { refunding.value = false } } return { loading, sendingLink, chargingCard, togglingPpa, refunding, fetchBalance, fetchMethods, sendPaymentLink, chargeCard, togglePpa, openPortal, createCheckout, refundPayment, } }