gigafibre-fsm/apps/dispatch/src/api/dispatch.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

117 lines
4.1 KiB
JavaScript

// ── ERPNext Dispatch resource calls ─────────────────────────────────────────
// All ERPNext fetch() calls live here.
// Swap BASE_URL in config/erpnext.js to change the target server.
// ─────────────────────────────────────────────────────────────────────────────
import { BASE_URL } from 'src/config/erpnext'
import { authFetch } from './auth'
async function apiGet (path) {
const res = await authFetch(BASE_URL + path)
const data = await res.json()
if (data.exc) throw new Error(data.exc)
return data
}
async function apiPut (doctype, name, body) {
const res = await authFetch(
`${BASE_URL}/api/resource/${encodeURIComponent(doctype)}/${encodeURIComponent(name)}`,
{
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
},
)
if (!res.ok) console.error(`[API] PUT ${doctype}/${name} failed:`, res.status, await res.text().catch(() => ''))
const data = await res.json()
if (data.exc) throw new Error(data.exc)
return data
}
export async function fetchTechnicians () {
const list = await apiGet('/api/resource/Dispatch%20Technician?fields=["name"]&limit=100')
const names = (list.data || []).map(t => t.name)
if (!names.length) return []
const docs = await Promise.all(
names.map(n => apiGet(`/api/resource/Dispatch%20Technician/${encodeURIComponent(n)}`).then(d => d.data))
)
return docs
}
// Fetch all jobs with child tables (assistants)
export async function fetchJobs (filters = null) {
// Step 1: get job names from list endpoint
let url = '/api/resource/Dispatch%20Job?fields=["name"]&limit=200'
if (filters) url += '&filters=' + encodeURIComponent(JSON.stringify(filters))
const list = await apiGet(url)
const names = (list.data || []).map(j => j.name)
if (!names.length) return []
// Step 2: fetch each doc individually (includes child tables)
const docs = await Promise.all(
names.map(n => apiGet(`/api/resource/Dispatch%20Job/${encodeURIComponent(n)}`).then(d => d.data))
)
return docs
}
export async function updateJob (name, payload) {
return apiPut('Dispatch Job', name, payload)
}
export async function createJob (payload) {
const res = await authFetch(
`${BASE_URL}/api/resource/Dispatch%20Job`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
},
)
const data = await res.json()
if (data.exc) throw new Error(data.exc)
return data.data
}
export async function updateTech (name, payload) {
return apiPut('Dispatch Technician', name, payload)
}
export async function createTech (payload) {
const res = await authFetch(
`${BASE_URL}/api/resource/Dispatch%20Technician`,
{ method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) },
)
const data = await res.json()
if (data.exc) throw new Error(data.exc)
return data.data
}
export async function deleteTech (name) {
const res = await authFetch(
`${BASE_URL}/api/resource/Dispatch%20Technician/${encodeURIComponent(name)}`,
{ method: 'DELETE' },
)
if (!res.ok) {
const data = await res.json().catch(() => ({}))
const msg = data._server_messages ? JSON.parse(JSON.parse(data._server_messages)[0]).message : data.exception || 'Delete failed'
throw new Error(msg)
}
}
export async function fetchTags () {
const data = await apiGet('/api/resource/Dispatch%20Tag?fields=["name","label","color","category"]&limit=200')
return data.data || []
}
export async function createTag (label, category = 'Custom', color = '#6b7280') {
const res = await authFetch(
`${BASE_URL}/api/resource/Dispatch%20Tag`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ label, category, color }),
},
)
const data = await res.json()
if (data.exc) throw new Error(data.exc)
return data.data
}