144 lines
4.6 KiB
TypeScript
144 lines
4.6 KiB
TypeScript
import { formatFrappeApiError } from '../utils/frappeErrorMessage';
|
|
|
|
const RESOURCE = 'Purchase%20Order';
|
|
|
|
export interface PurchaseOrderItem {
|
|
name?: string;
|
|
item_code?: string;
|
|
item_name?: string;
|
|
description?: string;
|
|
qty?: number;
|
|
rate?: number;
|
|
amount?: number;
|
|
uom?: string;
|
|
idx?: number;
|
|
[key: string]: any;
|
|
}
|
|
|
|
export interface PurchaseTaxCharge {
|
|
name?: string;
|
|
charge_type?: string;
|
|
account_head?: string;
|
|
tax_amount?: number;
|
|
rate?: number;
|
|
idx?: number;
|
|
[key: string]: any;
|
|
}
|
|
|
|
export interface PurchaseOrder {
|
|
name: string;
|
|
docstatus?: number;
|
|
status?: string;
|
|
supplier?: string;
|
|
supplier_name?: string;
|
|
transaction_date?: string;
|
|
schedule_date?: string;
|
|
company?: string;
|
|
currency?: string;
|
|
grand_total?: number;
|
|
net_total?: number;
|
|
total_taxes_and_charges?: number;
|
|
items?: PurchaseOrderItem[];
|
|
taxes?: PurchaseTaxCharge[];
|
|
owner?: string;
|
|
creation?: string;
|
|
modified?: string;
|
|
[key: string]: any;
|
|
}
|
|
|
|
class PurchaseOrderService {
|
|
private async getCSRFToken(): Promise<string | null> {
|
|
if (typeof window === 'undefined') return null;
|
|
if ((window as any).csrf_token) return (window as any).csrf_token;
|
|
if ((window as any).frappe?.csrf_token) return (window as any).frappe.csrf_token;
|
|
try {
|
|
const res = await fetch('/api/method/frappe.sessions.get_csrf_token', { credentials: 'include' });
|
|
if (res.ok) {
|
|
const json = await res.json();
|
|
if (json.message) {
|
|
(window as any).csrf_token = json.message;
|
|
return json.message;
|
|
}
|
|
}
|
|
} catch { /* ignore */ }
|
|
return null;
|
|
}
|
|
|
|
private async getHeaders(): Promise<Record<string, string>> {
|
|
const h: Record<string, string> = { 'Content-Type': 'application/json', Accept: 'application/json' };
|
|
const csrf = await this.getCSRFToken();
|
|
if (csrf) h['X-Frappe-CSRF-Token'] = csrf;
|
|
return h;
|
|
}
|
|
|
|
private async fetchJson(url: string, opts: RequestInit = {}): Promise<any> {
|
|
const headers = await this.getHeaders();
|
|
const r = await fetch(url, { credentials: 'include', headers, ...opts });
|
|
const body = await r.json().catch(() => ({}));
|
|
if (!r.ok) throw new Error(formatFrappeApiError(body) || body?.message || `HTTP ${r.status}`);
|
|
if (body.exc) throw new Error(formatFrappeApiError(body) || 'Request failed');
|
|
return body;
|
|
}
|
|
|
|
async getPurchaseOrders(
|
|
params: { filters?: any[]; limit_start?: number; limit_page_length?: number; order_by?: string } = {},
|
|
): Promise<PurchaseOrder[]> {
|
|
const q = new URLSearchParams();
|
|
const fields = [
|
|
'name', 'supplier', 'supplier_name', 'transaction_date', 'schedule_date',
|
|
'status', 'grand_total', 'currency', 'docstatus', 'company', 'creation', 'modified',
|
|
];
|
|
q.set('fields', JSON.stringify(fields));
|
|
if (params.filters?.length) q.set('filters', JSON.stringify(params.filters));
|
|
q.set('limit_start', String(params.limit_start ?? 0));
|
|
q.set('limit_page_length', String(params.limit_page_length ?? 20));
|
|
q.set('order_by', params.order_by ?? 'creation desc');
|
|
const body = await this.fetchJson(`/api/resource/${RESOURCE}?${q}`);
|
|
return body.data || [];
|
|
}
|
|
|
|
async getPurchaseOrderCount(filters: any[] = []): Promise<number> {
|
|
const q = new URLSearchParams();
|
|
q.set('fields', JSON.stringify(['count(name) as count']));
|
|
if (filters.length) q.set('filters', JSON.stringify(filters));
|
|
try {
|
|
const body = await this.fetchJson(`/api/resource/${RESOURCE}?${q}`);
|
|
return body.data?.[0]?.count ?? 0;
|
|
} catch {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
async getPurchaseOrder(name: string): Promise<PurchaseOrder> {
|
|
const body = await this.fetchJson(`/api/resource/${RESOURCE}/${encodeURIComponent(name)}`);
|
|
return body.data;
|
|
}
|
|
|
|
async createPurchaseOrder(data: Partial<PurchaseOrder>): Promise<PurchaseOrder> {
|
|
const body = await this.fetchJson(`/api/resource/${RESOURCE}`, {
|
|
method: 'POST',
|
|
body: JSON.stringify(data),
|
|
});
|
|
return body.data;
|
|
}
|
|
|
|
async updatePurchaseOrder(name: string, data: Partial<PurchaseOrder>): Promise<PurchaseOrder> {
|
|
const body = await this.fetchJson(`/api/resource/${RESOURCE}/${encodeURIComponent(name)}`, {
|
|
method: 'PUT',
|
|
body: JSON.stringify(data),
|
|
});
|
|
return body.data;
|
|
}
|
|
|
|
async submitPurchaseOrder(name: string): Promise<PurchaseOrder> {
|
|
const body = await this.fetchJson(`/api/resource/${RESOURCE}/${encodeURIComponent(name)}`, {
|
|
method: 'PUT',
|
|
body: JSON.stringify({ docstatus: 1 }),
|
|
});
|
|
return body.data;
|
|
}
|
|
}
|
|
|
|
const purchaseOrderService = new PurchaseOrderService();
|
|
export default purchaseOrderService;
|