mivita/resources/views/admin/customer/index.blade.php
Kevin 3d0864713b 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>
2026-10-06 12:36:02 +00:00

124 lines
5.7 KiB
PHP

@extends('layouts.layout-2')
@section('content')
<h4 class="font-weight-bold py-2 mb-2">
{{ __('Kunden') }}
</h4>
<div class="card">
<div class="card-header">
<div class="form-row align-items-center">
<div class="col-sm-7 mb-2">
<label class="form-label" for="filter_user_shop_id">Filter zugewiesener Berater</label>
<select class="selectpicker" data-style="btn-default" name="filter_member_id" id="filter_member_id" data-live-search="true">
<option value="">Filter aus</option>
@foreach($filter_members as $member)
<option value="{{$member->id}}" @if(get_user_attr('filter_member_id') == $member->id) selected @endif>{{$member->first_name}} {{$member->last_name}} | {{$member->email}}</option>
@endforeach
</select>
</div>
<div class="col-sm-3 mb-2">
<label class="form-label" for="filter_gdpr_deleted">DSGVO-gelöschte Kunden</label>
<select class="custom-select" name="filter_gdpr_deleted" id="filter_gdpr_deleted">
<option value="">ausblenden</option>
<option value="all" @if(get_user_attr('filter_gdpr_deleted') === 'all') selected @endif>mit anzeigen</option>
<option value="only" @if(get_user_attr('filter_gdpr_deleted') === 'only') selected @endif>nur gelöschte</option>
</select>
</div>
<div class="col-2 col-sm-2 mb-2 mt-4">
<a href="{{ route('admin_customers') }}?reset=filter" data-toggle="tooltip" data-placement="top" title="Reset Filter" class="btn icon-btn btn-sm btn-outline-dark float-right">
<span class="fa fa-sync"></span>
</a>
</div>
</div>
</div>
<div class="card-datatable table-responsive">
<div class="ml-4">
<!--<a href="{{ route('admin_lead_edit', ['new']) }}" class="btn btn-sm btn-primary">{{__('Neuen Berater erstellen')}}</a> -->
</div>
<table class="datatables-customers table table-striped table-bordered" id="datatables-customers">
<thead>
<tr>
<th>#</th>
<th>{{__('Nummer')}}</th>
<th>{{__('E-Mail')}}</th>
<th>{{__('ist Berater')}}</th>
<th>{{ __('Salutation') }}</th>
<th>{{ __('Company') }}</th>
<th>{{ __('First name') }}</th>
<th>{{__('Last name')}}</th>
<th>{{ __('Postcode') }}</th>
<th>{{ __('City') }}</th>
<th>{{ __('Country') }}</th>
<th>{{__('Käufe')}}</th>
<th>{{__('Newsletter')}}</th>
<th>{{__('zugewiesener Berater')}}</th>
<th>{{__('Datum')}}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div class="mt-4 ml-4">
<!-- <a href="{{ route('admin_lead_edit', ['new']) }}" class="btn btn-sm btn-primary">{{__('Neuen Berater erstellen')}}</a> -->
</div>
</div>
</div>
<script>
$( document ).ready(function() {
var oTable = $('#datatables-customers').DataTable({
"processing": true,
"serverSide": true,
ajax: {
url: '{!! route( 'admin_customer_datatable') !!}',
data: function(d) {
d.filter_member_id = $('select[name=filter_member_id]').val();
d.filter_customer_member = $('select[name=filter_customer_member]').val();
d.filter_gdpr_deleted = $('select[name=filter_gdpr_deleted]').val();
}
},
"order": [[0, "desc" ]],
"columns": [
{ data: 'id', searchable: false},
{ data: 'number', name: 'number'},
{ data: 'billing_email', name: 'billing_email' },
{ data: 'isMember', name: 'isMember' },
{ data: 'billing_salutation', name: 'billing_salutation' },
{ data: 'billing_company', name: 'billing_company' },
{ data: 'billing_firstname', name: 'billing_firstname' },
{ data: 'billing_lastname', name: 'billing_lastname' },
{ data: 'billing_zipcode', name: 'billing_zipcode' },
{ data: 'billing_city', name: 'billing_city' },
{ data: 'billing_country_id', name: 'billing_country_id' },
{ data: 'orders', name: 'orders' },
{ data: 'subscribed', name: 'subscribed' },
{ data: 'member_id', name: 'member_id', searchable: false, orderable: false },
{ data: 'created_at', name: 'created_at' },
],
"bLengthChange": false,
"iDisplayLength": 50,
"language": {
"url": "/js/datatables-{{ \App::getLocale() }}.json"
}
});
$('#filter_member_id').on('change', function(){
oTable.draw();
});
$('#filter_customer_member').on('change', function(){
oTable.draw();
});
$('#filter_gdpr_deleted').on('change', function(){
oTable.draw();
});
});
</script>
@endsection