mirror of
https://github.com/s-frick/effigenix.git
synced 2026-03-29 01:13:40 +01:00
fix(masterdata): MASTERDATA-Permissions und JSON-Serialisierung der REST-Responses
MASTERDATA_READ/WRITE fehlten im Permission-Enum und in den Rollen-Seed-Daten, dadurch bekam der Admin bei allen Stammdaten-Schreiboperationen Access Denied. Die Masterdata-Controller gaben Domain-Objekte direkt als JSON zurück, die von Jackson nicht serialisiert werden konnten (method-style Accessors statt JavaBean- Getter). Response-DTOs als Records eingeführt, die Domain-Objekte in flache JSON-Strukturen mappen. Frontend-Mapping-Layer entfernt, da Backend-Responses jetzt 1:1 die erwarteten Feldnamen liefern.
This commit is contained in:
parent
3cccab1f4d
commit
fbed3f899f
26 changed files with 481 additions and 364 deletions
|
|
@ -8,14 +8,6 @@
|
|||
* DELETE /api/customers/{id}/frame-contract,
|
||||
* PUT /api/customers/{id}/preferences
|
||||
*
|
||||
* NOTE: Backend returns domain objects with nested VOs:
|
||||
* { "id": {"value":"uuid"}, "name": {"value":"string"},
|
||||
* "billingAddress": {street, houseNumber, postalCode, city, country},
|
||||
* "contactInfo": {phone, email, contactPerson},
|
||||
* "paymentTerms": {paymentDueDays, description},
|
||||
* "deliveryAddresses": [{label, address: {...}, contactPerson, deliveryNotes}],
|
||||
* "frameContract": {"id": {"value":"uuid"}, validFrom, validUntil, deliveryRhythm, lineItems},
|
||||
* "preferences": ["BIO", ...], "status": "ACTIVE", ... }
|
||||
* DELETE delivery-addresses/{label} and DELETE frame-contract return 204 → re-fetch.
|
||||
*/
|
||||
|
||||
|
|
@ -143,153 +135,75 @@ export interface SetFrameContractRequest {
|
|||
lineItems: SetFrameContractLineItem[];
|
||||
}
|
||||
|
||||
// ── Backend response shapes (domain objects with nested VOs) ─────────────────
|
||||
|
||||
interface BackendPaymentTerms {
|
||||
paymentDueDays: number;
|
||||
description: string | null; // Note: backend field is "description", not "paymentDescription"
|
||||
}
|
||||
|
||||
interface BackendContractLineItem {
|
||||
articleId: { value: string };
|
||||
agreedPrice: { amount: number; currency: string };
|
||||
agreedQuantity: number | null;
|
||||
unit: string | null;
|
||||
}
|
||||
|
||||
interface BackendFrameContract {
|
||||
id: { value: string };
|
||||
validFrom: string | null;
|
||||
validUntil: string | null;
|
||||
deliveryRhythm: DeliveryRhythm;
|
||||
lineItems: BackendContractLineItem[];
|
||||
}
|
||||
|
||||
interface BackendCustomer {
|
||||
id: { value: string };
|
||||
name: { value: string };
|
||||
type: CustomerType;
|
||||
status: CustomerStatus;
|
||||
billingAddress: AddressDTO;
|
||||
contactInfo: ContactInfoDTO;
|
||||
paymentTerms: BackendPaymentTerms | null;
|
||||
deliveryAddresses: DeliveryAddressDTO[]; // DeliveryAddress is a record → matches DTO shape
|
||||
frameContract: BackendFrameContract | null;
|
||||
preferences: CustomerPreference[];
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
function mapLineItem(bli: BackendContractLineItem): ContractLineItemDTO {
|
||||
return {
|
||||
articleId: bli.articleId.value,
|
||||
agreedPrice: bli.agreedPrice.amount,
|
||||
agreedQuantity: bli.agreedQuantity,
|
||||
unit: bli.unit,
|
||||
};
|
||||
}
|
||||
|
||||
function mapFrameContract(bfc: BackendFrameContract): FrameContractDTO {
|
||||
return {
|
||||
id: bfc.id.value,
|
||||
validFrom: bfc.validFrom,
|
||||
validUntil: bfc.validUntil,
|
||||
deliveryRhythm: bfc.deliveryRhythm,
|
||||
lineItems: bfc.lineItems.map(mapLineItem),
|
||||
};
|
||||
}
|
||||
|
||||
function mapCustomer(bc: BackendCustomer): CustomerDTO {
|
||||
return {
|
||||
id: bc.id.value,
|
||||
name: bc.name.value,
|
||||
type: bc.type,
|
||||
status: bc.status,
|
||||
billingAddress: bc.billingAddress,
|
||||
contactInfo: bc.contactInfo,
|
||||
paymentTerms: bc.paymentTerms
|
||||
? {
|
||||
paymentDueDays: bc.paymentTerms.paymentDueDays,
|
||||
paymentDescription: bc.paymentTerms.description,
|
||||
}
|
||||
: null,
|
||||
deliveryAddresses: bc.deliveryAddresses,
|
||||
frameContract: bc.frameContract ? mapFrameContract(bc.frameContract) : null,
|
||||
preferences: bc.preferences,
|
||||
createdAt: bc.createdAt,
|
||||
updatedAt: bc.updatedAt,
|
||||
};
|
||||
}
|
||||
|
||||
// ── Resource factory ─────────────────────────────────────────────────────────
|
||||
|
||||
export function createCustomersResource(client: AxiosInstance) {
|
||||
return {
|
||||
async list(): Promise<CustomerDTO[]> {
|
||||
const res = await client.get<BackendCustomer[]>('/api/customers');
|
||||
return res.data.map(mapCustomer);
|
||||
const res = await client.get<CustomerDTO[]>('/api/customers');
|
||||
return res.data;
|
||||
},
|
||||
|
||||
async getById(id: string): Promise<CustomerDTO> {
|
||||
const res = await client.get<BackendCustomer>(`/api/customers/${id}`);
|
||||
return mapCustomer(res.data);
|
||||
const res = await client.get<CustomerDTO>(`/api/customers/${id}`);
|
||||
return res.data;
|
||||
},
|
||||
|
||||
async create(request: CreateCustomerRequest): Promise<CustomerDTO> {
|
||||
const res = await client.post<BackendCustomer>('/api/customers', request);
|
||||
return mapCustomer(res.data);
|
||||
const res = await client.post<CustomerDTO>('/api/customers', request);
|
||||
return res.data;
|
||||
},
|
||||
|
||||
async update(id: string, request: UpdateCustomerRequest): Promise<CustomerDTO> {
|
||||
const res = await client.put<BackendCustomer>(`/api/customers/${id}`, request);
|
||||
return mapCustomer(res.data);
|
||||
const res = await client.put<CustomerDTO>(`/api/customers/${id}`, request);
|
||||
return res.data;
|
||||
},
|
||||
|
||||
async activate(id: string): Promise<CustomerDTO> {
|
||||
const res = await client.post<BackendCustomer>(`/api/customers/${id}/activate`);
|
||||
return mapCustomer(res.data);
|
||||
const res = await client.post<CustomerDTO>(`/api/customers/${id}/activate`);
|
||||
return res.data;
|
||||
},
|
||||
|
||||
async deactivate(id: string): Promise<CustomerDTO> {
|
||||
const res = await client.post<BackendCustomer>(`/api/customers/${id}/deactivate`);
|
||||
return mapCustomer(res.data);
|
||||
const res = await client.post<CustomerDTO>(`/api/customers/${id}/deactivate`);
|
||||
return res.data;
|
||||
},
|
||||
|
||||
async addDeliveryAddress(id: string, request: AddDeliveryAddressRequest): Promise<CustomerDTO> {
|
||||
const res = await client.post<BackendCustomer>(
|
||||
const res = await client.post<CustomerDTO>(
|
||||
`/api/customers/${id}/delivery-addresses`,
|
||||
request,
|
||||
);
|
||||
return mapCustomer(res.data);
|
||||
return res.data;
|
||||
},
|
||||
|
||||
// Returns 204 No Content → re-fetch customer
|
||||
async removeDeliveryAddress(id: string, label: string): Promise<CustomerDTO> {
|
||||
await client.delete(`/api/customers/${id}/delivery-addresses/${encodeURIComponent(label)}`);
|
||||
const res = await client.get<BackendCustomer>(`/api/customers/${id}`);
|
||||
return mapCustomer(res.data);
|
||||
const res = await client.get<CustomerDTO>(`/api/customers/${id}`);
|
||||
return res.data;
|
||||
},
|
||||
|
||||
async setFrameContract(id: string, request: SetFrameContractRequest): Promise<CustomerDTO> {
|
||||
const res = await client.put<BackendCustomer>(
|
||||
const res = await client.put<CustomerDTO>(
|
||||
`/api/customers/${id}/frame-contract`,
|
||||
request,
|
||||
);
|
||||
return mapCustomer(res.data);
|
||||
return res.data;
|
||||
},
|
||||
|
||||
// Returns 204 No Content → re-fetch customer
|
||||
async removeFrameContract(id: string): Promise<CustomerDTO> {
|
||||
await client.delete(`/api/customers/${id}/frame-contract`);
|
||||
const res = await client.get<BackendCustomer>(`/api/customers/${id}`);
|
||||
return mapCustomer(res.data);
|
||||
const res = await client.get<CustomerDTO>(`/api/customers/${id}`);
|
||||
return res.data;
|
||||
},
|
||||
|
||||
async setPreferences(id: string, preferences: CustomerPreference[]): Promise<CustomerDTO> {
|
||||
const res = await client.put<BackendCustomer>(`/api/customers/${id}/preferences`, {
|
||||
const res = await client.put<CustomerDTO>(`/api/customers/${id}/preferences`, {
|
||||
preferences,
|
||||
});
|
||||
return mapCustomer(res.data);
|
||||
return res.data;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue