mirror of
https://github.com/s-frick/effigenix.git
synced 2026-03-28 10:09:35 +01:00
- Neue Screens: Kategorien, Lieferanten, Artikel, Kunden (jeweils Liste, Detail, Anlegen + Detailaktionen wie Bewertung, Zertifikate, Verkaufseinheiten, Lieferadressen, Präferenzen) - API-Client: Resources für alle 4 Stammdaten-Aggregate implementiert (categories, suppliers, articles, customers) mit Mapping von verschachtelten Domain-VOs auf flache DTOs - Lieferant, Artikel, Kategorie: echte HTTP-Calls gegen Backend (/api/suppliers, /api/articles, /api/categories, /api/customers) - 204-No-Content-Endpoints (removeSalesUnit, removeSupplier, removeCertificate, removeDeliveryAddress, removeFrameContract) lösen Re-Fetch des Aggregats aus - MasterdataMenu, Navigation-Erweiterung, App.tsx-Routing
236 lines
6.8 KiB
TypeScript
236 lines
6.8 KiB
TypeScript
/**
|
||
* Suppliers resource – Real HTTP implementation.
|
||
* Endpoints: GET/POST /api/suppliers, GET/PUT /api/suppliers/{id},
|
||
* POST /api/suppliers/{id}/activate|deactivate,
|
||
* POST /api/suppliers/{id}/rating,
|
||
* POST /api/suppliers/{id}/certificates,
|
||
* DELETE /api/suppliers/{id}/certificates (with body)
|
||
*
|
||
* NOTE: Backend returns domain objects with nested VOs:
|
||
* { "id": {"value":"uuid"}, "name": {"value":"string"},
|
||
* "address": {"street":"...","houseNumber":"...","postalCode":"...","city":"...","country":"DE"},
|
||
* "contactInfo": {"phone":"...","email":"...","contactPerson":"..."},
|
||
* "paymentTerms": {"paymentDueDays":30,"description":"..."},
|
||
* "certificates": [{"certificateType":"...","issuer":"...","validFrom":"2024-01-01","validUntil":"2026-12-31"}],
|
||
* "rating": {"qualityScore":4,"deliveryScore":4,"priceScore":5},
|
||
* "status": "ACTIVE", "createdAt":"...", "updatedAt":"..." }
|
||
* DELETE /api/suppliers/{id}/certificates returns 204 No Content → re-fetch.
|
||
*/
|
||
|
||
import type { AxiosInstance } from 'axios';
|
||
|
||
export interface AddressDTO {
|
||
street: string;
|
||
houseNumber: string | null;
|
||
postalCode: string;
|
||
city: string;
|
||
country: string;
|
||
}
|
||
|
||
export interface ContactInfoDTO {
|
||
phone: string;
|
||
email: string | null;
|
||
contactPerson: string | null;
|
||
}
|
||
|
||
export interface PaymentTermsDTO {
|
||
paymentDueDays: number;
|
||
paymentDescription: string | null;
|
||
}
|
||
|
||
export interface QualityCertificateDTO {
|
||
certificateType: string;
|
||
issuer: string;
|
||
validFrom: string;
|
||
validUntil: string;
|
||
}
|
||
|
||
export interface SupplierRatingDTO {
|
||
qualityScore: number;
|
||
deliveryScore: number;
|
||
priceScore: number;
|
||
}
|
||
|
||
export type SupplierStatus = 'ACTIVE' | 'INACTIVE';
|
||
|
||
export interface SupplierDTO {
|
||
id: string;
|
||
name: string;
|
||
status: SupplierStatus;
|
||
address: AddressDTO | null;
|
||
contactInfo: ContactInfoDTO;
|
||
paymentTerms: PaymentTermsDTO | null;
|
||
certificates: QualityCertificateDTO[];
|
||
rating: SupplierRatingDTO | null;
|
||
createdAt: string;
|
||
updatedAt: string;
|
||
}
|
||
|
||
export interface CreateSupplierRequest {
|
||
name: string;
|
||
phone: string;
|
||
email?: string;
|
||
contactPerson?: string;
|
||
street?: string;
|
||
houseNumber?: string;
|
||
postalCode?: string;
|
||
city?: string;
|
||
country?: string;
|
||
paymentDueDays?: number;
|
||
paymentDescription?: string;
|
||
}
|
||
|
||
export interface UpdateSupplierRequest {
|
||
name?: string;
|
||
phone?: string;
|
||
email?: string | null;
|
||
contactPerson?: string | null;
|
||
street?: string | null;
|
||
houseNumber?: string | null;
|
||
postalCode?: string | null;
|
||
city?: string | null;
|
||
country?: string | null;
|
||
paymentDueDays?: number | null;
|
||
paymentDescription?: string | null;
|
||
}
|
||
|
||
export interface RateSupplierRequest {
|
||
qualityScore: number;
|
||
deliveryScore: number;
|
||
priceScore: number;
|
||
}
|
||
|
||
export interface AddCertificateRequest {
|
||
certificateType: string;
|
||
issuer: string;
|
||
validFrom: string;
|
||
validUntil: string;
|
||
}
|
||
|
||
export interface RemoveCertificateRequest {
|
||
certificateType: string;
|
||
issuer: string;
|
||
validFrom: string;
|
||
}
|
||
|
||
// ── Backend response shapes (domain objects with nested VOs) ─────────────────
|
||
|
||
interface BackendAddress {
|
||
street: string;
|
||
houseNumber: string | null;
|
||
postalCode: string;
|
||
city: string;
|
||
country: string;
|
||
}
|
||
|
||
interface BackendContactInfo {
|
||
phone: string;
|
||
email: string | null;
|
||
contactPerson: string | null;
|
||
}
|
||
|
||
interface BackendPaymentTerms {
|
||
paymentDueDays: number;
|
||
description: string | null; // Note: backend field is "description", not "paymentDescription"
|
||
}
|
||
|
||
interface BackendQualityCertificate {
|
||
certificateType: string;
|
||
issuer: string;
|
||
validFrom: string; // LocalDate → "2024-01-01"
|
||
validUntil: string;
|
||
}
|
||
|
||
interface BackendSupplierRating {
|
||
qualityScore: number;
|
||
deliveryScore: number;
|
||
priceScore: number;
|
||
}
|
||
|
||
interface BackendSupplier {
|
||
id: { value: string };
|
||
name: { value: string };
|
||
address: BackendAddress | null;
|
||
contactInfo: BackendContactInfo;
|
||
paymentTerms: BackendPaymentTerms | null;
|
||
certificates: BackendQualityCertificate[];
|
||
rating: BackendSupplierRating | null;
|
||
status: SupplierStatus;
|
||
createdAt: string;
|
||
updatedAt: string;
|
||
}
|
||
|
||
function mapSupplier(bs: BackendSupplier): SupplierDTO {
|
||
return {
|
||
id: bs.id.value,
|
||
name: bs.name.value,
|
||
status: bs.status,
|
||
address: bs.address,
|
||
contactInfo: bs.contactInfo,
|
||
paymentTerms: bs.paymentTerms
|
||
? {
|
||
paymentDueDays: bs.paymentTerms.paymentDueDays,
|
||
paymentDescription: bs.paymentTerms.description,
|
||
}
|
||
: null,
|
||
certificates: bs.certificates,
|
||
rating: bs.rating,
|
||
createdAt: bs.createdAt,
|
||
updatedAt: bs.updatedAt,
|
||
};
|
||
}
|
||
|
||
// ── Resource factory ─────────────────────────────────────────────────────────
|
||
|
||
export function createSuppliersResource(client: AxiosInstance) {
|
||
return {
|
||
async list(): Promise<SupplierDTO[]> {
|
||
const res = await client.get<BackendSupplier[]>('/api/suppliers');
|
||
return res.data.map(mapSupplier);
|
||
},
|
||
|
||
async getById(id: string): Promise<SupplierDTO> {
|
||
const res = await client.get<BackendSupplier>(`/api/suppliers/${id}`);
|
||
return mapSupplier(res.data);
|
||
},
|
||
|
||
async create(request: CreateSupplierRequest): Promise<SupplierDTO> {
|
||
const res = await client.post<BackendSupplier>('/api/suppliers', request);
|
||
return mapSupplier(res.data);
|
||
},
|
||
|
||
async update(id: string, request: UpdateSupplierRequest): Promise<SupplierDTO> {
|
||
const res = await client.put<BackendSupplier>(`/api/suppliers/${id}`, request);
|
||
return mapSupplier(res.data);
|
||
},
|
||
|
||
async activate(id: string): Promise<SupplierDTO> {
|
||
const res = await client.post<BackendSupplier>(`/api/suppliers/${id}/activate`);
|
||
return mapSupplier(res.data);
|
||
},
|
||
|
||
async deactivate(id: string): Promise<SupplierDTO> {
|
||
const res = await client.post<BackendSupplier>(`/api/suppliers/${id}/deactivate`);
|
||
return mapSupplier(res.data);
|
||
},
|
||
|
||
async rate(id: string, request: RateSupplierRequest): Promise<SupplierDTO> {
|
||
const res = await client.post<BackendSupplier>(`/api/suppliers/${id}/rating`, request);
|
||
return mapSupplier(res.data);
|
||
},
|
||
|
||
async addCertificate(id: string, request: AddCertificateRequest): Promise<SupplierDTO> {
|
||
const res = await client.post<BackendSupplier>(`/api/suppliers/${id}/certificates`, request);
|
||
return mapSupplier(res.data);
|
||
},
|
||
|
||
// Returns 204 No Content → re-fetch supplier
|
||
async removeCertificate(id: string, request: RemoveCertificateRequest): Promise<SupplierDTO> {
|
||
await client.delete(`/api/suppliers/${id}/certificates`, { data: request });
|
||
const res = await client.get<BackendSupplier>(`/api/suppliers/${id}`);
|
||
return mapSupplier(res.data);
|
||
},
|
||
};
|
||
}
|
||
|
||
export type SuppliersResource = ReturnType<typeof createSuppliersResource>;
|