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>
208 lines
7.5 KiB
PHP
208 lines
7.5 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\ShoppingOrder;
|
|
use App\Models\ShoppingUser;
|
|
use App\User;
|
|
use Illuminate\Database\QueryException;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class ShoppingUserService
|
|
{
|
|
/**
|
|
* Gibt alle Bestellungen eines Mitglieds zurück
|
|
*
|
|
* @param ShoppingUser $shopping_user Das Mitglied, dessen Bestellungen zurückgegeben werden sollen
|
|
* @return Collection Die Bestellungen des Mitglieds
|
|
*/
|
|
public static function getAllOrdersByMember($shopping_user)
|
|
{
|
|
$users = ShoppingUser::where('billing_email', '=', $shopping_user->billing_email)->where('member_id', '=', $shopping_user->member_id)->get();
|
|
|
|
return $users->flatMap(function ($user) {
|
|
return $user->shopping_orders;
|
|
})->sortByDesc('created_at');
|
|
}
|
|
|
|
public static function syncOrdersByEmail($user)
|
|
{
|
|
$maxAttempts = 3;
|
|
$attempt = 1;
|
|
|
|
while ($attempt <= $maxAttempts) {
|
|
try {
|
|
DB::beginTransaction();
|
|
|
|
$shopping_user = ShoppingUser::where('member_id', $user->id)
|
|
->first();
|
|
|
|
if (! $shopping_user) {
|
|
DB::commit();
|
|
|
|
return;
|
|
}
|
|
|
|
$shopping_users = ShoppingUser::where('billing_email', '=', $shopping_user->billing_email)
|
|
->whereHas('shopping_order', function ($q) {
|
|
$q->where('txaction', 'paid')
|
|
->orWhere('txaction', 'appointed')
|
|
->orWhere('txaction', 'extern')
|
|
->orWhere('txaction', 'invoice_open')
|
|
->orWhere('txaction', 'invoice_paid');
|
|
})
|
|
->lockForUpdate()
|
|
->get();
|
|
|
|
$order_count = $shopping_users->count();
|
|
|
|
foreach ($shopping_users as $user) {
|
|
$user->orders = $order_count;
|
|
$user->save();
|
|
}
|
|
|
|
DB::commit();
|
|
|
|
return; // Erfolgreicher Fall
|
|
|
|
} catch (QueryException $e) {
|
|
DB::rollBack();
|
|
|
|
// Wenn es ein Deadlock ist, versuchen wir es erneut
|
|
if ($e->getCode() == 40001 && $attempt < $maxAttempts) {
|
|
$sleepTime = pow(2, $attempt) * 100000; // Exponentielles Backoff in Mikrosekunden
|
|
usleep($sleepTime);
|
|
$attempt++;
|
|
|
|
continue;
|
|
}
|
|
|
|
throw $e; // Andere Fehler oder zu viele Versuche
|
|
}
|
|
}
|
|
}
|
|
|
|
/*public static function syncOrdersByEmail($user){
|
|
ShoppingUser::where('member_id', $user->id)
|
|
->whereNotNull('billing_email')
|
|
->where('billing_email', '!=', '')
|
|
->select('billing_email')
|
|
->groupBy('billing_email')
|
|
->get()
|
|
->each(function($shopping_user) {
|
|
self::snycOrdersByShoppingUser($shopping_user);
|
|
});
|
|
}*/
|
|
/**
|
|
* Synchronisiert die Bestellungen eines ShoppingOrders mit den Bestellungen des zugehörigen ShoppingUsers
|
|
*
|
|
* @param ShoppingOrder $shopping_order Der zu synchronisierende ShoppingOrder
|
|
*/
|
|
public static function snycOrdersByShoppingOrder(ShoppingOrder $shopping_order)
|
|
{
|
|
$shopping_user = $shopping_order->shopping_user ? $shopping_order->shopping_user : null;
|
|
if ($shopping_user) {
|
|
self::snycOrdersByShoppingUser($shopping_user);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Synchronisiert die Bestellungen eines ShoppingUsers mit den Bestellungen des zugehörigen Benutzers
|
|
*
|
|
* @param ShoppingUser $shopping_user Der zu synchronisierende ShoppingUser
|
|
*/
|
|
public static function snycOrdersByShoppingUser(ShoppingUser $shopping_user)
|
|
{
|
|
|
|
// Aktualisiere alle Benutzer mit einer einzigen Datenbankabfrage
|
|
ShoppingUser::where('billing_email', $shopping_user->billing_email)
|
|
->update([
|
|
'orders' => ShoppingUser::where('billing_email', $shopping_user->billing_email)
|
|
->whereHas('shopping_order', function ($q) {
|
|
$q->whereIn('txaction', ['paid', 'appointed', 'extern', 'invoice_open', 'invoice_paid']);
|
|
})
|
|
->count(),
|
|
]);
|
|
|
|
}
|
|
|
|
public static function snycOrdersByNumber($number)
|
|
{
|
|
if ($number <= 0) {
|
|
return;
|
|
}
|
|
// Aktualisiere alle Benutzer mit einer einzigen Datenbankabfrage
|
|
|
|
ShoppingUser::where('number', '=', $number)
|
|
->update([
|
|
'orders' => ShoppingUser::where('number', '=', $number)
|
|
->whereHas('shopping_order', function ($q) {
|
|
$q->whereIn('txaction', ['paid', 'appointed', 'extern', 'invoice_open', 'invoice_paid']);
|
|
})
|
|
->count(),
|
|
]);
|
|
// Setze orders auf NULL für alle anderen
|
|
ShoppingUser::where('number', '=', $number)
|
|
->whereDoesntHave('shopping_order', function ($q) {
|
|
$q->whereIn('txaction', ['paid', 'appointed', 'extern', 'extern_paid']);
|
|
})
|
|
->update(['orders' => null]);
|
|
}
|
|
|
|
/**
|
|
* Synchronisiert die Nummern aller ShoppingUser eines Benutzers anhand der E-Mails
|
|
*
|
|
* @param User $user Der Benutzer, dessen ShoppingUser synchronisiert werden sollen
|
|
*/
|
|
public static function syncNumbersByEmail($user)
|
|
{
|
|
// Hole alle ShoppingUser mit E-Mail gruppiert
|
|
$emailGroups = ShoppingUser::where('member_id', $user->id)
|
|
->whereNotNull('billing_email')
|
|
->where('billing_email', '!=', '')
|
|
->get()
|
|
->groupBy('billing_email');
|
|
|
|
foreach ($emailGroups as $email => $users) {
|
|
// Suche ob es bereits eine Nummer für diese E-Mail gibt
|
|
$existingNumber = ($users->whereNotNull('number')->first()) ? $users->whereNotNull('number')->first()->number : null;
|
|
|
|
if ($existingNumber) {
|
|
// Wenn eine Nummer existiert, nutze diese für alle User mit der E-Mail
|
|
ShoppingUser::where('member_id', $user->id)
|
|
->where('billing_email', $email)
|
|
->whereNull('number')
|
|
->update(['number' => $existingNumber]);
|
|
} else {
|
|
// Wenn keine Nummer existiert, generiere eine neue
|
|
$maxNumber = ShoppingUser::max('number') ?: 1000;
|
|
$newNumber = $maxNumber + 1;
|
|
|
|
ShoppingUser::where('member_id', $user->id)
|
|
->where('billing_email', $email)
|
|
->update(['number' => $newNumber]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Setzt alle Faker-E-Mails für einen Benutzer auf 1
|
|
*
|
|
* @param User $user Der Benutzer, dessen Faker-E-Mails gesetzt werden sollen
|
|
*/
|
|
public static function setFakerMail($user)
|
|
{
|
|
// Aktualisiere alle Faker-E-Mails für den Benutzer in einem einzigen Update
|
|
// Schneller da nur ein einzelner SQL Query ausgeführt wird
|
|
ShoppingUser::where('member_id', $user->id)
|
|
->where('faker_mail', '!=', 1)
|
|
->where('billing_email', 'LIKE', '%faker@mivita.care')
|
|
->update(['faker_mail' => 1]);
|
|
|
|
// Setze alle anderen auf NULL zurück
|
|
ShoppingUser::where('member_id', $user->id)
|
|
->where('billing_email', 'NOT LIKE', '%faker@mivita.care')
|
|
->whereNull('gdpr_deleted_at')
|
|
->update(['faker_mail' => null]);
|
|
}
|
|
}
|