supplier und address
This commit is contained in:
@@ -95,6 +95,13 @@ export const routes: Routes = [
|
|||||||
'./features/components/shop-info/shop-info.routes'
|
'./features/components/shop-info/shop-info.routes'
|
||||||
).then((r) => r.SHOP_INFO_ROUTES),
|
).then((r) => r.SHOP_INFO_ROUTES),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'supplier-list',
|
||||||
|
loadChildren: () =>
|
||||||
|
import(
|
||||||
|
'./features/components/suppliers/suppliers.routes'
|
||||||
|
).then((r) => r.SUPPLIERS_ROUTES),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,14 +5,29 @@
|
|||||||
<h3>
|
<h3>
|
||||||
{{ selectedSupplierId ? "Lieferant bearbeiten" : "Neuer Lieferant" }}
|
{{ selectedSupplierId ? "Lieferant bearbeiten" : "Neuer Lieferant" }}
|
||||||
</h3>
|
</h3>
|
||||||
<input type="text" formControlName="name" placeholder="Name" />
|
|
||||||
<input
|
<fieldset>
|
||||||
type="text"
|
<legend>Lieferanten-Daten</legend>
|
||||||
formControlName="contactPerson"
|
<div><label>Name:</label><input type="text" formControlName="name" /></div>
|
||||||
placeholder="Ansprechpartner"
|
<div><label>Ansprechpartner:</label><input type="text" formControlName="contactPerson" /></div>
|
||||||
/>
|
<div><label>E-Mail:</label><input type="email" formControlName="email" /></div>
|
||||||
<input type="email" formControlName="email" placeholder="E-Mail" />
|
<div><label>Telefon:</label><input type="tel" formControlName="phoneNumber" /></div>
|
||||||
<input type="tel" formControlName="phoneNumber" placeholder="Telefon" />
|
<div><label>Notizen:</label><textarea formControlName="notes"></textarea></div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<!-- +++ NEUES ADRESS-FORMULAR +++ -->
|
||||||
|
<fieldset formGroupName="address">
|
||||||
|
<legend>Adresse (optional)</legend>
|
||||||
|
<div><label>Straße:</label><input type="text" formControlName="street" /></div>
|
||||||
|
<div><label>Hausnummer:</label><input type="text" formControlName="houseNumber" /></div>
|
||||||
|
<div><label>Stadt:</label><input type="text" formControlName="city" /></div>
|
||||||
|
<div><label>PLZ:</label><input type="text" formControlName="postalCode" /></div>
|
||||||
|
<div><label>Land:</label><input type="text" formControlName="country" /></div>
|
||||||
|
</fieldset>
|
||||||
|
<!-- +++ ENDE NEU +++ -->
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
<button type="submit" [disabled]="supplierForm.invalid">
|
<button type="submit" [disabled]="supplierForm.invalid">
|
||||||
{{ selectedSupplierId ? "Aktualisieren" : "Erstellen" }}
|
{{ selectedSupplierId ? "Aktualisieren" : "Erstellen" }}
|
||||||
</button>
|
</button>
|
||||||
@@ -26,9 +41,9 @@
|
|||||||
<h2>Bestehende Lieferanten</h2>
|
<h2>Bestehende Lieferanten</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li *ngFor="let supplier of suppliers$ | async">
|
<li *ngFor="let supplier of suppliers$ | async">
|
||||||
{{ supplier.name }} ({{ supplier.contactPerson }})
|
{{ supplier.name }} ({{ supplier.contactPerson || 'Kein Ansprechpartner' }})
|
||||||
<button (click)="selectSupplier(supplier)">Bearbeiten</button>
|
<button (click)="selectSupplier(supplier)">Bearbeiten</button>
|
||||||
<button (click)="onDelete(supplier.id)">Löschen</button>
|
<button (click)="onDelete(supplier.id)">Löschen</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@@ -1,9 +1,27 @@
|
|||||||
import { Component, OnInit, inject } from '@angular/core';
|
import { Component, OnInit, inject } from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
import {
|
||||||
import { Observable } from 'rxjs';
|
FormBuilder,
|
||||||
|
FormGroup,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
Validators,
|
||||||
|
} from '@angular/forms';
|
||||||
|
import { Observable, of } from 'rxjs';
|
||||||
|
import { switchMap, map } from 'rxjs/operators'; // <-- KORREKTUR: 'map' importiert
|
||||||
|
|
||||||
|
// Models
|
||||||
import { Supplier } from '../../../../core/models/supplier.model';
|
import { Supplier } from '../../../../core/models/supplier.model';
|
||||||
|
import {
|
||||||
|
Address,
|
||||||
|
CreateAddress,
|
||||||
|
UpdateAddress,
|
||||||
|
} from '../../../../core/models/address.model';
|
||||||
|
|
||||||
|
// Services
|
||||||
import { SupplierService } from '../../../services/supplier.service';
|
import { SupplierService } from '../../../services/supplier.service';
|
||||||
|
import { AddressService } from '../../../services/address.service';
|
||||||
|
// HINWEIS: Du hast den CustomerAddressService nicht mehr gebraucht, daher habe ich ihn entfernt.
|
||||||
|
// Falls du ihn doch an anderer Stelle brauchst, füge den Import wieder hinzu.
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-supplier-list',
|
selector: 'app-supplier-list',
|
||||||
@@ -13,9 +31,12 @@ import { SupplierService } from '../../../services/supplier.service';
|
|||||||
})
|
})
|
||||||
export class SupplierListComponent implements OnInit {
|
export class SupplierListComponent implements OnInit {
|
||||||
private supplierService = inject(SupplierService);
|
private supplierService = inject(SupplierService);
|
||||||
|
private addressService = inject(AddressService); // Korrekten Service verwenden
|
||||||
private fb = inject(FormBuilder);
|
private fb = inject(FormBuilder);
|
||||||
|
|
||||||
suppliers$!: Observable<Supplier[]>;
|
suppliers$!: Observable<Supplier[]>;
|
||||||
|
// Das Dropdown für Adressen wird nicht mehr benötigt
|
||||||
|
// addresses$!: Observable<Address[]>;
|
||||||
supplierForm: FormGroup;
|
supplierForm: FormGroup;
|
||||||
selectedSupplierId: string | null = null;
|
selectedSupplierId: string | null = null;
|
||||||
|
|
||||||
@@ -24,16 +45,50 @@ export class SupplierListComponent implements OnInit {
|
|||||||
name: ['', Validators.required],
|
name: ['', Validators.required],
|
||||||
contactPerson: [''],
|
contactPerson: [''],
|
||||||
email: ['', Validators.email],
|
email: ['', Validators.email],
|
||||||
phoneNumber: ['']
|
phoneNumber: [''],
|
||||||
|
addressId: [null],
|
||||||
|
notes: [''],
|
||||||
|
address: this.fb.group({
|
||||||
|
street: [''],
|
||||||
|
houseNumber: [''],
|
||||||
|
city: [''],
|
||||||
|
postalCode: [''],
|
||||||
|
country: [''],
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void { this.loadSuppliers(); }
|
get addressForm(): FormGroup {
|
||||||
loadSuppliers(): void { this.suppliers$ = this.supplierService.getAll(); }
|
return this.supplierForm.get('address') as FormGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
private isAddressFormDirty(): boolean {
|
||||||
|
const address = this.addressForm.value;
|
||||||
|
return Object.values(address).some((value) => !!value);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.loadSuppliers();
|
||||||
|
// this.addresses$ = this.adminAddressService.getAllUnlinkedAddresses(); // Lade ungebundene Adressen
|
||||||
|
}
|
||||||
|
|
||||||
|
loadSuppliers(): void {
|
||||||
|
this.suppliers$ = this.supplierService.getAll();
|
||||||
|
}
|
||||||
|
|
||||||
selectSupplier(supplier: Supplier): void {
|
selectSupplier(supplier: Supplier): void {
|
||||||
this.selectedSupplierId = supplier.id;
|
this.selectedSupplierId = supplier.id;
|
||||||
|
// Reset address form before patching to avoid leftover values
|
||||||
|
this.addressForm.reset();
|
||||||
this.supplierForm.patchValue(supplier);
|
this.supplierForm.patchValue(supplier);
|
||||||
|
|
||||||
|
if (supplier.addressId) {
|
||||||
|
this.addressService
|
||||||
|
.getAddressById(supplier.addressId)
|
||||||
|
.subscribe((address) => {
|
||||||
|
this.addressForm.patchValue(address);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clearSelection(): void {
|
clearSelection(): void {
|
||||||
@@ -43,24 +98,80 @@ export class SupplierListComponent implements OnInit {
|
|||||||
|
|
||||||
onSubmit(): void {
|
onSubmit(): void {
|
||||||
if (this.supplierForm.invalid) return;
|
if (this.supplierForm.invalid) return;
|
||||||
|
|
||||||
const dataToSend = { ...this.supplierForm.value, id: this.selectedSupplierId || '0' };
|
|
||||||
|
|
||||||
if (this.selectedSupplierId) {
|
const addressIdToSave$ = this.isAddressFormDirty()
|
||||||
this.supplierService.update(this.selectedSupplierId, dataToSend).subscribe(() => this.reset());
|
? this.saveAddress()
|
||||||
|
: of(this.supplierForm.value.addressId || null);
|
||||||
|
|
||||||
|
addressIdToSave$
|
||||||
|
.pipe(
|
||||||
|
switchMap((addressId: string | null) => {
|
||||||
|
const supplierData: Supplier = {
|
||||||
|
...this.supplierForm.value,
|
||||||
|
id: this.selectedSupplierId || undefined,
|
||||||
|
addressId: addressId,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.selectedSupplierId) {
|
||||||
|
return this.supplierService.update(
|
||||||
|
this.selectedSupplierId,
|
||||||
|
supplierData
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return this.supplierService.create(supplierData);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.subscribe(() => this.reset());
|
||||||
|
}
|
||||||
|
|
||||||
|
private saveAddress(): Observable<string | null> {
|
||||||
|
const supplierName = this.supplierForm.get('name')?.value || 'Lieferant';
|
||||||
|
const contactPerson = this.supplierForm
|
||||||
|
.get('contactPerson')
|
||||||
|
?.value.split(' ') || [''];
|
||||||
|
const firstName = contactPerson[0] || supplierName;
|
||||||
|
const lastName = contactPerson.slice(1).join(' ') || '(Lieferant)';
|
||||||
|
|
||||||
|
const addressData = {
|
||||||
|
...this.addressForm.value,
|
||||||
|
firstName,
|
||||||
|
lastName,
|
||||||
|
type: 'Billing',
|
||||||
|
};
|
||||||
|
|
||||||
|
const existingAddressId = this.supplierForm.get('addressId')?.value;
|
||||||
|
|
||||||
|
if (existingAddressId) {
|
||||||
|
const updateData: UpdateAddress = {
|
||||||
|
...addressData,
|
||||||
|
id: existingAddressId,
|
||||||
|
};
|
||||||
|
return this.addressService
|
||||||
|
.updateAddress(existingAddressId, updateData)
|
||||||
|
.pipe(
|
||||||
|
map(() => existingAddressId) // Gibt die bestehende ID zurück
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
this.supplierService.create(dataToSend).subscribe(() => this.reset());
|
const createData: CreateAddress = addressData;
|
||||||
|
return this.addressService.createAddress(createData).pipe(
|
||||||
|
map((createdAddress: Address) => createdAddress.id) // Gibt die neue ID zurück
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onDelete(id: string): void {
|
onDelete(id: string): void {
|
||||||
if (confirm('Lieferant wirklich löschen?')) {
|
if (
|
||||||
|
confirm(
|
||||||
|
'Lieferant wirklich löschen? (Zugehörige Adresse wird nicht gelöscht)'
|
||||||
|
)
|
||||||
|
) {
|
||||||
this.supplierService.delete(id).subscribe(() => this.loadSuppliers());
|
this.supplierService.delete(id).subscribe(() => this.loadSuppliers());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private reset(): void {
|
private reset(): void {
|
||||||
this.loadSuppliers();
|
this.loadSuppliers();
|
||||||
this.clearSelection();
|
this.clearSelection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
11
src/app/features/components/suppliers/suppliers.routes.ts
Normal file
11
src/app/features/components/suppliers/suppliers.routes.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { Routes } from '@angular/router';
|
||||||
|
import { SupplierListComponent } from './supplier-list/supplier-list.component';
|
||||||
|
|
||||||
|
|
||||||
|
export const SUPPLIERS_ROUTES: Routes = [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
component: SupplierListComponent,
|
||||||
|
title: '',
|
||||||
|
},
|
||||||
|
];
|
||||||
59
src/app/features/services/address.service.ts
Normal file
59
src/app/features/services/address.service.ts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import { Injectable, inject } from '@angular/core';
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { API_URL } from '../../core/tokens/api-url.token';
|
||||||
|
import { Address, CreateAddress, UpdateAddress } from '../../core/models/address.model';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class AddressService {
|
||||||
|
private http = inject(HttpClient);
|
||||||
|
private apiUrl = inject(API_URL);
|
||||||
|
private readonly endpoint = '/admin/AdminAddresses';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves all addresses that are not linked to a customer (e.g., for suppliers).
|
||||||
|
* @returns An Observable array of Address objects.
|
||||||
|
*/
|
||||||
|
getAllUnlinkedAddresses(): Observable<Address[]> {
|
||||||
|
return this.http.get<Address[]>(`${this.apiUrl}${this.endpoint}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a single unlinked address by its ID.
|
||||||
|
* @param id The unique identifier of the address.
|
||||||
|
* @returns An Observable of a single Address object.
|
||||||
|
*/
|
||||||
|
getAddressById(id: string): Observable<Address> {
|
||||||
|
return this.http.get<Address>(`${this.apiUrl}${this.endpoint}/${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new unlinked address.
|
||||||
|
* @param data The data for the new address.
|
||||||
|
* @returns An Observable of the newly created Address object.
|
||||||
|
*/
|
||||||
|
createAddress(data: CreateAddress): Observable<Address> {
|
||||||
|
return this.http.post<Address>(`${this.apiUrl}${this.endpoint}`, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates an existing unlinked address.
|
||||||
|
* @param id The unique identifier of the address to update.
|
||||||
|
* @param data The updated address data.
|
||||||
|
* @returns An Observable that completes when the update is successful.
|
||||||
|
*/
|
||||||
|
updateAddress(id: string, data: UpdateAddress): Observable<void> {
|
||||||
|
return this.http.put<void>(`${this.apiUrl}${this.endpoint}/${id}`, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes an unlinked address by its ID.
|
||||||
|
* @param id The unique identifier of the address to delete.
|
||||||
|
* @returns An Observable that completes when the deletion is successful.
|
||||||
|
*/
|
||||||
|
deleteAddress(id: string): Observable<void> {
|
||||||
|
return this.http.delete<void>(`${this.apiUrl}${this.endpoint}/${id}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -89,5 +89,14 @@
|
|||||||
|
|
||||||
<span>shop-info</span>
|
<span>shop-info</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
class="nav-item"
|
||||||
|
[class.active]="activeRoute === 'supplier-list'"
|
||||||
|
(click)="setActive('supplier-list')"
|
||||||
|
>
|
||||||
|
<app-icon [iconName]="'placeholder'" [svgColor]="'#8e44ad'"></app-icon>
|
||||||
|
|
||||||
|
<span>supplier-list</span>
|
||||||
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
</aside>
|
</aside>
|
||||||
|
|||||||
Reference in New Issue
Block a user