OSS-BSS-Field-Dispatch/src/api/dispatch.js
louispaulb 5e6f20d871 Initial commit — dispatch app baseline before Quasar migration
Current state: custom CSS + vanilla Vue components
Architecture: modular with composables, provide/inject pattern
Ready for progressive migration to Quasar native components

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 13:35:49 -04:00

103 lines
3.5 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 { getCSRF } from './auth'
async function apiGet (path) {
const res = await fetch(BASE_URL + path, { credentials: 'include' })
const data = await res.json()
if (data.exc) throw new Error(data.exc)
return data
}
async function apiPut (doctype, name, body) {
const token = await getCSRF()
const res = await fetch(
`${BASE_URL}/api/resource/${encodeURIComponent(doctype)}/${encodeURIComponent(name)}`,
{
method: 'PUT',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-Frappe-CSRF-Token': token,
},
body: JSON.stringify(body),
},
)
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 token = await getCSRF()
const res = await fetch(
`${BASE_URL}/api/resource/Dispatch%20Job`,
{
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json', 'X-Frappe-CSRF-Token': token },
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 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 token = await getCSRF()
const res = await fetch(
`${BASE_URL}/api/resource/Dispatch%20Tag`,
{
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json', 'X-Frappe-CSRF-Token': token },
body: JSON.stringify({ label, category, color }),
},
)
const data = await res.json()
if (data.exc) throw new Error(data.exc)
return data.data
}