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:
parent
083d643220
commit
3d0864713b
19 changed files with 635 additions and 90 deletions
|
|
@ -10,6 +10,7 @@ use App\Services\GdprDeletionService;
|
|||
use App\Services\HTMLHelper;
|
||||
use App\Services\Shop;
|
||||
use Auth;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Request;
|
||||
use Validator;
|
||||
|
||||
|
|
@ -29,6 +30,7 @@ class CustomerController extends Controller
|
|||
if (Request::get('reset') === 'filter') {
|
||||
set_user_attr('filter_member_id', null);
|
||||
set_user_attr('filter_customer_member', null);
|
||||
set_user_attr('filter_gdpr_deleted', null);
|
||||
|
||||
return redirect(route('admin_customers'));
|
||||
}
|
||||
|
|
@ -82,6 +84,10 @@ class CustomerController extends Controller
|
|||
{
|
||||
$shopping_user = ShoppingUser::withTrashed()->findOrFail($id);
|
||||
|
||||
if (! Auth::user()->isSuperAdmin()) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
if (! Request::get('gdpr_delete_customer')) {
|
||||
\Session()->flash('alert-error', __('msg.gdpr_confirm_checkbox_missing'));
|
||||
|
||||
|
|
@ -89,8 +95,8 @@ class CustomerController extends Controller
|
|||
}
|
||||
|
||||
try {
|
||||
app(GdprDeletionService::class)->deleteShoppingUser($shopping_user, Auth::id());
|
||||
\Session()->flash('alert-success', __('msg.gdpr_delete_customer_success'));
|
||||
$summary = app(GdprDeletionService::class)->deleteShoppingUser($shopping_user, Auth::id());
|
||||
\Session()->flash('alert-success', __('msg.gdpr_delete_customer_success', ['count' => $summary['shopping_users_anonymized']]));
|
||||
} catch (GdprDeletionException $e) {
|
||||
\Session()->flash('alert-error', $e->getMessage());
|
||||
|
||||
|
|
@ -107,6 +113,9 @@ class CustomerController extends Controller
|
|||
$shopping_user->id = 'new';
|
||||
} else {
|
||||
$shopping_user = ShoppingUser::findOrFail($id);
|
||||
if ($shopping_user->isGdprDeleted()) {
|
||||
return $this->redirectGdprLocked($shopping_user);
|
||||
}
|
||||
}
|
||||
$data = [
|
||||
'shopping_user' => $shopping_user,
|
||||
|
|
@ -168,6 +177,9 @@ class CustomerController extends Controller
|
|||
}
|
||||
|
||||
$shopping_user = ShoppingUser::findOrFail($id);
|
||||
if ($shopping_user->isGdprDeleted()) {
|
||||
return $this->redirectGdprLocked($shopping_user);
|
||||
}
|
||||
|
||||
$data['language'] = isset($data['language']) ? $data['language'] : \App::getLocale();
|
||||
$data['has_buyed'] = isset($data['has_buyed']) ? true : false;
|
||||
|
|
@ -196,6 +208,13 @@ class CustomerController extends Controller
|
|||
{
|
||||
$query = ShoppingUser::select('shopping_users.*')->where('auth_user_id', '=', null);
|
||||
|
||||
set_user_attr('filter_gdpr_deleted', Request::get('filter_gdpr_deleted'));
|
||||
if (Request::get('filter_gdpr_deleted') === 'only') {
|
||||
$query->whereNotNull('gdpr_deleted_at');
|
||||
} elseif (Request::get('filter_gdpr_deleted') !== 'all') {
|
||||
$query->withoutGdprDeleted();
|
||||
}
|
||||
|
||||
set_user_attr('filter_member_id', Request::get('filter_member_id'));
|
||||
if (Request::get('filter_member_id') != '') {
|
||||
$query->where('member_id', '=', Request::get('filter_member_id'));
|
||||
|
|
@ -224,7 +243,8 @@ class CustomerController extends Controller
|
|||
return $ShoppingUser->billing_country ? $ShoppingUser->billing_country->getLocated() : '';
|
||||
})
|
||||
->addColumn('isMember', function (ShoppingUser $ShoppingUser) {
|
||||
return get_active_badge($ShoppingUser->auth_user_id).($ShoppingUser->mode === 'dev' ? ' <span class="badge badge-warning">dev</span>' : '');
|
||||
return get_active_badge($ShoppingUser->auth_user_id).($ShoppingUser->mode === 'dev' ? ' <span class="badge badge-warning">dev</span>' : '')
|
||||
.($ShoppingUser->isGdprDeleted() ? ' <span class="badge badge-secondary">DSGVO-gelöscht</span>' : '');
|
||||
})
|
||||
->addColumn('member_id', function (ShoppingUser $ShoppingUser) {
|
||||
if ($ShoppingUser->is_like) {
|
||||
|
|
@ -263,4 +283,11 @@ class CustomerController extends Controller
|
|||
->rawColumns(['id', 'subscribed', 'isMember', 'member_id'])
|
||||
->make(true);
|
||||
}
|
||||
|
||||
protected function redirectGdprLocked(ShoppingUser $shopping_user): RedirectResponse
|
||||
{
|
||||
\Session()->flash('alert-error', __('msg.gdpr_customer_locked'));
|
||||
|
||||
return redirect(route('admin_customer_detail', [$shopping_user->id]));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ use App\Services\HTMLHelper;
|
|||
use App\Services\Shop;
|
||||
use App\Services\ShoppingUserService;
|
||||
use App\User;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Request;
|
||||
use Validator;
|
||||
|
|
@ -61,6 +62,9 @@ class CustomerController extends Controller
|
|||
if ($shopping_user->member_id != \Auth::user()->id) {
|
||||
abort(404);
|
||||
}
|
||||
if ($shopping_user->isGdprDeleted()) {
|
||||
return $this->redirectGdprLocked($shopping_user);
|
||||
}
|
||||
$data = [
|
||||
'shopping_user' => $shopping_user,
|
||||
'isAdmin' => false,
|
||||
|
|
@ -81,6 +85,9 @@ class CustomerController extends Controller
|
|||
if ($shopping_user->member_id != \Auth::user()->id) {
|
||||
abort(404);
|
||||
}
|
||||
if ($shopping_user->isGdprDeleted()) {
|
||||
return $this->redirectGdprLocked($shopping_user);
|
||||
}
|
||||
}
|
||||
|
||||
$billing_email = null;
|
||||
|
|
@ -142,6 +149,12 @@ class CustomerController extends Controller
|
|||
|
||||
if ($action === 'save') {
|
||||
$shopping_user = ShoppingUser::findOrFail($id);
|
||||
if ($shopping_user->member_id != \Auth::user()->id) {
|
||||
abort(404);
|
||||
}
|
||||
if ($shopping_user->isGdprDeleted()) {
|
||||
return $this->redirectGdprLocked($shopping_user);
|
||||
}
|
||||
$shopping_user->faker_mail = false;
|
||||
$shopping_user->billing_email = Request::get($email);
|
||||
$shopping_user->save();
|
||||
|
|
@ -213,6 +226,9 @@ class CustomerController extends Controller
|
|||
if ($shopping_user->member_id != \Auth::user()->id) {
|
||||
abort(404);
|
||||
}
|
||||
if ($shopping_user->isGdprDeleted()) {
|
||||
return $this->redirectGdprLocked($shopping_user);
|
||||
}
|
||||
CustomerPriority::checkChangeOne($shopping_user, $data, true);
|
||||
$shopping_user->fill($data);
|
||||
$shopping_user->save();
|
||||
|
|
@ -261,7 +277,8 @@ class CustomerController extends Controller
|
|||
$query->select(DB::raw('MAX(id)'))
|
||||
->from('shopping_users')
|
||||
->groupBy('billing_email');
|
||||
})->where('shopping_users.member_id', '=', $user->id)->where('shopping_users.auth_user_id', '=', null);
|
||||
})->where('shopping_users.member_id', '=', $user->id)->where('shopping_users.auth_user_id', '=', null)
|
||||
->withoutGdprDeleted();
|
||||
|
||||
if (Request::get('isfor') === 'ot-member') { // Bestellung für Kunden
|
||||
}
|
||||
|
|
@ -327,4 +344,11 @@ class CustomerController extends Controller
|
|||
->rawColumns(['send_to', 'id', 'subscribed', 'extras', 'status'])
|
||||
->make(true);
|
||||
}
|
||||
|
||||
protected function redirectGdprLocked(ShoppingUser $shopping_user): RedirectResponse
|
||||
{
|
||||
\Session()->flash('alert-error', __('msg.gdpr_customer_locked'));
|
||||
|
||||
return redirect(route('user_customer_detail', [$shopping_user->id]));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -273,7 +273,7 @@ class CheckoutController extends Controller
|
|||
];
|
||||
|
||||
if (Request::get('is_from') === 'shopping') {
|
||||
$rules['customer_order_source_comment'] = 'required|string|max:500';
|
||||
$rules['customer_order_source_comment'] = 'nullable|string|max:500';
|
||||
}
|
||||
|
||||
if (Request::get('same_as_billing')) {
|
||||
|
|
@ -287,9 +287,7 @@ class CheckoutController extends Controller
|
|||
]);
|
||||
}
|
||||
|
||||
return Validator::make(Request::all(), $rules, [
|
||||
'customer_order_source_comment.required' => __('order.source_comment_required'),
|
||||
]);
|
||||
return Validator::make(Request::all(), $rules);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue