Kunden loeschen: DSGVO-geloeschte Kunden ausblenden und sperren; Checkout-Herkunft freiwillig

Kunden loeschen (Rueckmeldung "es wird nichts geloescht"):
- DSGVO-geloeschte Eintraege blieben mit Name in den Listen stehen; Kunde
  61009 wurde deshalb achtmal geloescht, bei Eintrag 45013 wurde die E-Mail
  danach ueber ein offenes Bearbeiten-Formular zurueckgeschrieben
- neue Spalte shopping_users.gdpr_deleted_at (Bestand per Migration markiert)
- Admin-Kundenliste blendet geloeschte Kunden aus (Filter: ausblenden /
  mit anzeigen / nur geloeschte), Berater-Kundenliste immer
- Bearbeiten/Speichern im Admin und beim Berater gesperrt; ShoppingUser
  verweigert das Zurueckschreiben von E-Mail und Telefon
- Modal und Erfolgsmeldung (de/en/es/fr) sagen klar, dass Name und
  Rechnungsadresse wegen der Aufbewahrungspflicht bleiben
- gdpr:repair-customers [--execute] zieht protokollierte Loeschungen nach
- DSGVO-Loeschung prueft Superadmin serverseitig; Berater duerfen eine
  Kunden-E-Mail nur beim eigenen Kunden nachtragen
- setFakerMail setzt faker_mail bei geloeschten Eintraegen nicht zurueck

Checkout: "Wie bist du auf uns aufmerksam geworden?" ist kein Pflichtfeld
mehr und wird farbig hervorgehoben.

Deploy: php artisan migrate && php artisan gdpr:repair-customers --execute

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kevin 2026-10-06 12:36:02 +00:00
parent 083d643220
commit 3d0864713b
19 changed files with 635 additions and 90 deletions

View file

@ -0,0 +1,50 @@
<?php
namespace App\Console\Commands;
use App\Services\GdprDeletionService;
use Illuminate\Console\Command;
class GdprRepairCustomers extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'gdpr:repair-customers
{--execute : Änderungen wirklich ausführen (ohne Option nur Vorschau)}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Zieht protokollierte DSGVO-Löschungen von Endkunden nach: Einträge, deren Kontaktdaten nach der Löschung wieder befüllt wurden, werden erneut anonymisiert und gesperrt.';
/**
* Execute the console command.
*/
public function handle(GdprDeletionService $gdprDeletionService): int
{
$execute = (bool) $this->option('execute');
$rows = $gdprDeletionService->repairLoggedShoppingUserDeletions(! $execute);
if ($rows === []) {
$this->info('Keine Einträge zu reparieren.');
return 0;
}
$this->table(['ShoppingUser-ID', 'Kd-Nr.', 'Löschung protokolliert am'], array_map(
fn (array $row) => [$row['id'], $row['number'] ?: '-', $row['deletion_logged_at']],
$rows
));
$this->info($execute
? count($rows).' Eintrag/Einträge erneut anonymisiert und gesperrt.'
: count($rows).' Eintrag/Einträge betroffen. Vorschau – mit --execute ausführen.');
return 0;
}
}