/** Back office ↔ store-server client; session token survives reloads. */ let token = sessionStorage.getItem('bo.token') ?? '' export function hasSession(): boolean { return token !== '' } export function clearSession(): void { token = '' sessionStorage.removeItem('bo.token') } async function call(path: string, init?: RequestInit): Promise { const res = await fetch(`/api${path}`, { ...init, headers: { 'content-type': 'application/json', ...(token !== '' ? { authorization: `Bearer ${token}` } : {}), }, }).catch(() => undefined) if (res === undefined) throw new Error('Store-server unreachable (E-3301)') if (res.status === 401) clearSession() const body = (await res.json().catch(() => ({}))) as T & { error?: string } if (!res.ok) throw new Error(body.error ?? `Server error HTTP ${res.status}`) return body } export async function login(username: string, password: string): Promise { const s = await call<{ token: string; displayName: string }>('/auth/login', { method: 'POST', body: JSON.stringify({ username, password }), }) token = s.token sessionStorage.setItem('bo.token', s.token) return s.displayName } export const getItems = (q?: string): Promise[]> => call(`/items${q !== undefined && q !== '' ? `?q=${encodeURIComponent(q)}` : ''}`) export const createItem = (body: Record): Promise> => call('/items', { method: 'POST', body: JSON.stringify(body) }) export const getParties = (kind?: string): Promise[]> => call(`/parties${kind !== undefined ? `?kind=${kind}` : ''}`) export const getBills = (date?: string, limit?: number, offset?: number): Promise[]> => { const qs = new URLSearchParams() if (date !== undefined) qs.set('date', date) if (limit !== undefined) qs.set('limit', String(limit)) if (offset !== undefined) qs.set('offset', String(offset)) return call(`/bills${qs.toString() !== '' ? `?${qs}` : ''}`) } export const getStock = (): Promise[]> => call('/stock') export const getAudit = (limit?: number, offset?: number): Promise[]> => { const qs = new URLSearchParams() if (limit !== undefined) qs.set('limit', String(limit)) if (offset !== undefined) qs.set('offset', String(offset)) return call(`/audit${qs.toString() !== '' ? `?${qs}` : ''}`) } export const getPurchases = (): Promise[]> => call('/purchases') export const getLastCosts = (supplierId?: string): Promise> => call(`/purchases/last-costs${supplierId !== undefined ? `?supplierId=${supplierId}` : ''}`) export const postPurchase = (body: Record): Promise<{ id: string; totalPaise: number }> => call('/purchases', { method: 'POST', body: JSON.stringify(body) }) export const getCostHistory = (itemId: string, supplierId?: string): Promise<{ cost: number; date: string; supplier: string }[]> => call(`/purchases/cost-history?itemId=${itemId}${supplierId !== undefined ? `&supplierId=${supplierId}` : ''}`) export const getBootstrapPublic = (): Promise<{ taxClasses: { classCode: string; ratePctBp: number; cessPctBp: number; effectiveFrom: string; effectiveTo?: string }[] }> => call('/bootstrap?counter=C1') export interface Seller { id: string; name: string; storeCode: string; stateCode: string; gstin?: string } /** Seller header for GST invoices/labels — store name, GSTIN, state (from bootstrap). */ export const getSeller = (): Promise => call<{ store: Seller }>('/bootstrap?counter=C1').then((b) => b.store)