feat(T06): Verkaufsmodul + Rechtsdokumente + DATEV-Export + Sales UI

This commit is contained in:
2026-07-17 01:58:34 +02:00
parent a38d340ddc
commit 6603e411e9
33 changed files with 3481 additions and 107 deletions
+31
View File
@@ -0,0 +1,31 @@
import { apiFetch, type PaginatedResponse } from './api';
export interface DATEVExportResponse {
id: string;
start_date: string;
end_date: string;
file_path?: string | null;
total_amount: number;
created_at?: string;
}
export interface DATEVExportCreate {
start_date: string;
end_date: string;
}
export async function createDatevExport(data: DATEVExportCreate): Promise<DATEVExportResponse> {
return apiFetch<DATEVExportResponse>('/datev/export', {
method: 'POST',
body: JSON.stringify(data),
});
}
export async function listDatevExports(page = 1, pageSize = 20): Promise<PaginatedResponse<DATEVExportResponse>> {
return apiFetch<PaginatedResponse<DATEVExportResponse>>(`/datev/exports?page=${page}&page_size=${pageSize}`);
}
export function getDatevDownloadUrl(id: string): string {
const baseUrl = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000/api/v1';
return `${baseUrl}/datev/exports/${id}/download`;
}
+121
View File
@@ -0,0 +1,121 @@
import { apiFetch, type PaginatedResponse } from './api';
export interface VehicleNested {
id: string;
make: string;
model: string;
fin: string;
vehicle_type: string;
availability: string;
price: number;
}
export interface ContactNested {
id: string;
company_name: string;
address_city?: string;
address_country: string;
vat_id?: string;
email?: string;
phone?: string;
}
export interface SaleResponse {
id: string;
vehicle_id: string;
buyer_contact_id: string;
seller_contact_id?: string | null;
sale_price: number;
sale_date: string;
status: string;
is_gwg: boolean;
contract_pdf_path?: string | null;
created_at?: string;
updated_at?: string;
vehicle?: VehicleNested;
buyer?: ContactNested;
seller?: ContactNested;
}
export interface SaleCreateData {
vehicle_id: string;
buyer_contact_id: string;
seller_contact_id?: string;
sale_price: number;
sale_date?: string;
status?: string;
is_gwg?: boolean;
}
export interface SaleUpdateData {
sale_price?: number;
sale_date?: string;
status?: string;
is_gwg?: boolean;
seller_contact_id?: string;
}
export interface SaleListParams {
page?: number;
page_size?: number;
status?: string;
date_from?: string;
date_to?: string;
}
export interface ContractResponse {
sale_id: string;
contract_pdf_path: string;
message: string;
}
export interface UstIdVerifyResponse {
verified: boolean;
message: string;
vat_id?: string | null;
}
export async function listSales(params: SaleListParams = {}): Promise<PaginatedResponse<SaleResponse>> {
const query = new URLSearchParams();
if (params.page) query.set('page', String(params.page));
if (params.page_size) query.set('page_size', String(params.page_size));
if (params.status) query.set('status', params.status);
if (params.date_from) query.set('date_from', params.date_from);
if (params.date_to) query.set('date_to', params.date_to);
return apiFetch<PaginatedResponse<SaleResponse>>(`/sales/?${query.toString()}`);
}
export async function getSale(id: string): Promise<SaleResponse> {
return apiFetch<SaleResponse>(`/sales/${id}`);
}
export async function createSale(data: SaleCreateData): Promise<SaleResponse> {
return apiFetch<SaleResponse>('/sales/', {
method: 'POST',
body: JSON.stringify(data),
});
}
export async function updateSale(id: string, data: SaleUpdateData): Promise<SaleResponse> {
return apiFetch<SaleResponse>(`/sales/${id}`, {
method: 'PUT',
body: JSON.stringify(data),
});
}
export async function deleteSale(id: string): Promise<SaleResponse> {
return apiFetch<SaleResponse>(`/sales/${id}`, { method: 'DELETE' });
}
export async function regenerateContract(id: string): Promise<ContractResponse> {
return apiFetch<ContractResponse>(`/sales/${id}/contract`, { method: 'POST' });
}
export async function verifyUstId(id: string): Promise<UstIdVerifyResponse> {
return apiFetch<UstIdVerifyResponse>(`/sales/${id}/verify-ust-id`, { method: 'POST' });
}
export function getContractDownloadUrl(id: string): string {
const baseUrl = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000/api/v1';
return `${baseUrl}/sales/${id}/contract`;
}