gigafibre-fsm/apps/dispatch/src/api/settings.js
louispaulb 7da22ff132 merge: import dispatch-app into apps/dispatch/ (17 commits preserved)
Integrates the Dispatch PWA (Vue/Quasar) into the gigafibre-fsm monorepo.
Full git history accessible via `git log -- apps/dispatch/`.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 08:08:51 -04:00

98 lines
5.1 KiB
JavaScript

// ── Dispatch Settings — lecture/écriture du DocType Single ERPNext ───────────
import { BASE_URL } from 'src/config/erpnext'
import { getCSRF } from './auth'
const DOCTYPE = 'Dispatch Settings'
const NAME = 'Dispatch Settings'
function isDocTypeError (body) {
const s = JSON.stringify(body)
return s.includes('dispatch_settings') || s.includes('DoesNotExist') || s.includes('No module named')
}
export async function fetchSettings () {
const r = await fetch(`${BASE_URL}/api/resource/${DOCTYPE}/${NAME}`, {
credentials: 'include',
})
if (!r.ok) {
const body = await r.json().catch(() => ({}))
if (r.status === 404 || isDocTypeError(body)) throw new Error('DOCTYPE_NOT_FOUND')
throw new Error(`Erreur HTTP ${r.status}`)
}
const body = await r.json()
// Frappe peut retourner 200 avec une exception dans le corps
if (body.exc_type || body.exception) {
if (isDocTypeError(body)) throw new Error('DOCTYPE_NOT_FOUND')
throw new Error(body.exc_type || 'Erreur Frappe')
}
return body.data
}
export async function saveSettings (payload) {
const csrf = await getCSRF()
const r = await fetch(`${BASE_URL}/api/resource/${DOCTYPE}/${NAME}`, {
method: 'PUT',
credentials: 'include',
headers: { 'Content-Type': 'application/json', 'X-Frappe-CSRF-Token': csrf || '' },
body: JSON.stringify(payload),
})
const body = await r.json().catch(() => ({}))
if (!r.ok || body.exc_type || body.exception) {
if (isDocTypeError(body)) throw new Error('DOCTYPE_NOT_FOUND')
throw new Error(body._error_message || body.exc_type || `Erreur HTTP ${r.status}`)
}
return body
}
// ── Création du DocType via API (bouton Initialiser dans l'admin) ─────────────
const DOCTYPE_FIELDS = [
{ fieldname: 'erp_section', fieldtype: 'Section Break', label: 'ERPNext / Frappe' },
{ fieldname: 'erp_url', fieldtype: 'Data', label: 'URL du serveur', default: 'http://localhost:8080' },
{ fieldname: 'erp_api_key', fieldtype: 'Data', label: 'API Key' },
{ fieldname: 'erp_api_secret', fieldtype: 'Password', label: 'API Secret' },
{ fieldname: 'mapbox_section', fieldtype: 'Section Break', label: 'Mapbox' },
{ fieldname: 'mapbox_token', fieldtype: 'Data', label: 'Token public (pk_)' },
{ fieldname: 'twilio_section', fieldtype: 'Section Break', label: 'Twilio — SMS' },
{ fieldname: 'twilio_account_sid', fieldtype: 'Data', label: 'Account SID' },
{ fieldname: 'twilio_auth_token', fieldtype: 'Password', label: 'Auth Token' },
{ fieldname: 'twilio_from_number', fieldtype: 'Data', label: 'Numéro expéditeur' },
{ fieldname: 'stripe_section', fieldtype: 'Section Break', label: 'Stripe — Paiements' },
{ fieldname: 'stripe_mode', fieldtype: 'Select', label: 'Mode', options: 'test\nlive', default: 'test' },
{ fieldname: 'stripe_publishable_key', fieldtype: 'Data', label: 'Clé publique (pk_)' },
{ fieldname: 'stripe_secret_key', fieldtype: 'Password', label: 'Clé secrète (sk_)' },
{ fieldname: 'stripe_webhook_secret',fieldtype: 'Password', label: 'Webhook Secret (whsec_)' },
{ fieldname: 'n8n_section', fieldtype: 'Section Break', label: 'n8n — Automatisation' },
{ fieldname: 'n8n_url', fieldtype: 'Data', label: 'URL n8n', default: 'http://localhost:5678' },
{ fieldname: 'n8n_api_key', fieldtype: 'Password', label: 'API Key n8n' },
{ fieldname: 'n8n_webhook_base', fieldtype: 'Data', label: 'Base URL webhooks', default: 'http://localhost:5678/webhook' },
{ fieldname: 'sms_section', fieldtype: 'Section Break', label: 'Templates SMS' },
{ fieldname: 'sms_enroute', fieldtype: 'Text', label: 'Technicien en route',
default: 'Bonjour {client_name}, votre technicien {tech_name} est en route et arrivera dans environ {eta} minutes. Réf: {job_id}' },
{ fieldname: 'sms_completed', fieldtype: 'Text', label: 'Service complété',
default: 'Bonjour {client_name}, votre service ({job_id}) a été complété avec succès. Merci de votre confiance !' },
{ fieldname: 'sms_assigned', fieldtype: 'Text', label: 'Job assigné (technicien)',
default: 'Nouveau job assigné : {job_id} — {client_name}, {address}. Durée estimée : {duration}h.' },
]
export async function createDocType () {
const csrf = await getCSRF()
const r = await fetch(`${BASE_URL}/api/resource/DocType`, {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json', 'X-Frappe-CSRF-Token': csrf || '' },
body: JSON.stringify({
name: DOCTYPE, module: 'Core', custom: 1, is_single: 1, track_changes: 0,
fields: DOCTYPE_FIELDS,
permissions: [
{ role: 'System Manager', read: 1, write: 1, create: 1 },
{ role: 'Administrator', read: 1, write: 1, create: 1 },
],
}),
})
const body = await r.json().catch(() => ({}))
if (!r.ok || body.exc_type) {
throw new Error(body._error_message || body.exc_type || `Erreur HTTP ${r.status}`)
}
return body
}