feat: initial commit

This commit is contained in:
2026-03-05 22:12:38 +01:00
commit bce762a783
380 changed files with 51955 additions and 0 deletions
+250
View File
@@ -0,0 +1,250 @@
import api from './client'
import type { Product } from './products'
import type { OutputType } from './outputTypes'
export interface OrderLine {
id: string
order_id: string
product_id: string
product: Product
output_type_id: string | null
output_type: OutputType | null
gewuenschte_bildnummer: string | null
item_status: 'pending' | 'approved' | 'rejected'
render_status: 'pending' | 'processing' | 'completed' | 'failed' | 'cancelled'
result_path: string | null
thumbnail_url: string | null
ai_validation_status: string
ai_validation_result: Record<string, unknown> | null
render_backend_used: string | null
flamenco_job_id: string | null
unit_price: number | null
render_position_id: string | null
render_position_name: string | null
notes: string | null
created_at: string
updated_at: string
}
export interface OrderLineCreate {
product_id: string
output_type_id?: string | null
render_position_id?: string | null
gewuenschte_bildnummer?: string | null
notes?: string | null
}
export interface Order {
id: string
order_number: string
template_id: string | null
status: 'draft' | 'submitted' | 'processing' | 'completed' | 'rejected'
created_by: string
source_excel: string | null
notes: string | null
created_at: string
updated_at: string
submitted_at: string | null
completed_at: string | null
estimated_price: number | null
item_count: number
line_count: number
render_progress: {
total: number
completed: number
processing: number
failed: number
pending: number
cancelled: number
} | null
}
export interface OrderItem {
id: string
order_id: string
row_index: number
ebene1: string | null
ebene2: string | null
baureihe: string | null
pim_id: string | null
produkt_baureihe: string | null
gewaehltes_produkt: string | null
name_cad_modell: string | null
gewuenschte_bildnummer: string | null
lagertyp: string | null
medias_rendering: boolean | null
components: Array<{ part_name: string | null; material: string | null; component_type: string | null; column_index: number }>
cad_file_id: string | null
thumbnail_path: string | null
ai_validation_status: string
ai_validation_result: Record<string, unknown> | null
item_status: 'pending' | 'approved' | 'rejected'
notes: string | null
created_at: string
}
export interface OrderDetail extends Order {
items: OrderItem[]
lines: OrderLine[]
}
export async function listOrders(params?: { status?: string; skip?: number; limit?: number }) {
const res = await api.get<Order[]>('/orders', { params })
return res.data
}
export async function searchOrders(params: {
q?: string
statuses?: string[]
date_from?: string
date_to?: string
limit?: number
}): Promise<OrderDetail[]> {
const res = await api.get<OrderDetail[]>('/orders/search', {
params: {
q: params.q || '',
statuses: params.statuses?.join(',') || '',
date_from: params.date_from || '',
date_to: params.date_to || '',
limit: params.limit || 50,
},
})
return res.data
}
export async function getOrder(id: string) {
const res = await api.get<OrderDetail>(`/orders/${id}`)
return res.data
}
export async function patchOrderItem(
orderId: string,
itemId: string,
patch: Partial<{
ebene1: string | null
ebene2: string | null
baureihe: string | null
pim_id: string | null
produkt_baureihe: string | null
gewaehltes_produkt: string | null
name_cad_modell: string | null
gewuenschte_bildnummer: string | null
lagertyp: string | null
medias_rendering: boolean | null
notes: string | null
}>,
) {
const res = await api.patch<OrderItem>(`/orders/${orderId}/items/${itemId}`, patch)
return res.data
}
export async function createOrder(data: {
template_id?: string
source_excel?: string
notes?: string
items?: Array<{
row_index: number
ebene1?: string | null
ebene2?: string | null
baureihe?: string | null
pim_id?: string | null
produkt_baureihe?: string | null
gewaehltes_produkt?: string | null
name_cad_modell?: string | null
gewuenschte_bildnummer?: string | null
lagertyp?: string | null
medias_rendering?: boolean | null
components: Array<{ part_name?: string | null; material?: string | null; component_type?: string | null; column_index: number }>
}>
lines?: OrderLineCreate[]
}) {
const res = await api.post<OrderDetail>('/orders', data)
return res.data
}
export async function addOrderLine(orderId: string, data: OrderLineCreate): Promise<OrderLine> {
const res = await api.post<OrderLine>(`/orders/${orderId}/lines`, data)
return res.data
}
export async function removeOrderLine(orderId: string, lineId: string): Promise<void> {
await api.delete(`/orders/${orderId}/lines/${lineId}`)
}
export async function submitOrder(id: string) {
const res = await api.post<Order>(`/orders/${id}/submit`)
return res.data
}
export async function deleteOrder(id: string) {
await api.delete(`/orders/${id}`)
}
export async function unlinkCadFile(orderId: string, itemId: string) {
await api.delete(`/orders/${orderId}/items/${itemId}/cad-file`)
}
export async function dispatchRenders(orderId: string) {
const res = await api.post<{ dispatched: number }>(`/orders/${orderId}/dispatch-renders`)
return res.data
}
export async function cancelLineRender(orderId: string, lineId: string) {
const res = await api.post<{ cancelled: boolean; line_id: string; backend: string; errors: string[] | null }>(
`/orders/${orderId}/lines/${lineId}/cancel-render`
)
return res.data
}
export async function cancelOrderRenders(orderId: string) {
const res = await api.post<{ cancelled: number; order_status: string; errors: string[] | null }>(
`/orders/${orderId}/cancel-renders`
)
return res.data
}
export async function regenerateItemThumbnail(orderId: string, itemId: string) {
const res = await api.post<{ status: string; task_id: string; cad_file_id: string }>(
`/orders/${orderId}/items/${itemId}/regenerate-thumbnail`
)
return res.data
}
export interface SplitMissingStepResult {
new_order_id: string
new_order_number: string
moved_item_count: number
moved_line_count: number
}
export async function splitMissingStep(orderId: string): Promise<SplitMissingStepResult> {
const res = await api.post<SplitMissingStepResult>(`/orders/${orderId}/split-missing-step`)
return res.data
}
export interface GenerateLinesResult {
created: number
skipped: number
no_product_count: number
no_step_count: number
}
export async function generateLinesFromItems(
orderId: string,
outputTypeIds: string[],
): Promise<GenerateLinesResult> {
const res = await api.post<GenerateLinesResult>(`/orders/${orderId}/generate-lines`, {
output_type_ids: outputTypeIds,
})
return res.data
}
export async function downloadOrderRenders(orderId: string, orderNumber: string): Promise<void> {
const res = await api.get(`/orders/${orderId}/download-renders`, { responseType: 'blob' })
const url = URL.createObjectURL(res.data)
const a = document.createElement('a')
a.href = url
a.download = `${orderNumber}_renders.zip`
a.click()
URL.revokeObjectURL(url)
}