get(); foreach ($ShoppingUsers as $shopping_user) { ShoppingUserMemberLog::create([ 'pre_member_id' => $shopping_user->member_id, 'shopping_user_id' => $shopping_user->id, 'new_member_id' => $new_member_id, ]); $shopping_user->member_id = $new_member_id; $shopping_user->save(); } } public static function setNewSponsorToChilds($inactive_sponsor_id, $new_sponsor_id) { // alle User die diesen inaktivien Sponsor haben $child_users = User::where('m_sponsor', $inactive_sponsor_id)->get(); // auch deaktiverte foreach ($child_users as $child_user) { UserCleanUpLog::create([ 'inactive_sponsor_id' => $inactive_sponsor_id, 'child_user_id' => $child_user->id, 'new_sponsor_id' => $new_sponsor_id, ]); $child_user->m_sponsor = $new_sponsor_id; $child_user->save(); } } public static function resetChildsToSponsor($re_sponsor_id) { // alle alten Childs vom re_sponsor_id / User wieder herstellen $UserCleanUpUsers = UserCleanUpLog::where('inactive_sponsor_id', $re_sponsor_id)->get(); foreach ($UserCleanUpUsers as $UserCleanUpUser) { $child_user = User::find($UserCleanUpUser->child_user_id); if ($child_user) { // delete Logs from user child where is newer then this $deleteUserCleanUpLogs = UserCleanUpLog::where('child_user_id', $UserCleanUpUser->child_user_id)->where('created_at', '>', $UserCleanUpUser->created_at)->get(); foreach ($deleteUserCleanUpLogs as $deleteUserCleanUpLog) { $deleteUserCleanUpLog->delete(); } if ($child_user->m_sponsor) { // child is active $child_user->m_sponsor = $re_sponsor_id; } if ($child_user->pre_sponsor) { // child is inactive $child_user->pre_sponsor = $re_sponsor_id; } $child_user->save(); // delete this log $UserCleanUpUser->delete(); } } } public static function setUserToClient($user_id, $sponsor_id) { $user = User::find($user_id); if (! $user) { \Log::channel('cleanup')->error('setUserToClient: User not found, user_id: '.$user_id); return false; } if (! $user->account) { \Log::channel('cleanup')->error('setUserToClient: User has no account data, user_id: '.$user_id); return false; } try { $data = [ 'member_id' => $sponsor_id, 'language' => $user->lang ?? 'de', 'billing_salutation' => $user->account->salutation, 'billing_company' => $user->account->company, 'billing_firstname' => $user->account->first_name, 'billing_lastname' => $user->account->last_name, 'billing_address' => $user->account->address, 'billing_address_2' => $user->account->address_2, 'billing_zipcode' => $user->account->zipcode, 'billing_city' => $user->account->city, 'billing_country_id' => $user->account->country_id, 'billing_phone' => $user->account->getPhoneNumber(), 'billing_email' => $user->email, 'language' => $user->account->getLocale(), 'same_as_billing' => $user->account->same_as_billing, 'shipping_salutation' => $user->account->shipping_salutation, 'shipping_company' => $user->account->shipping_company, 'shipping_firstname' => $user->account->shipping_firstname, 'shipping_lastname' => $user->account->shipping_lastname, 'shipping_address' => $user->account->shipping_address, 'shipping_address_2' => $user->account->shipping_address_2, 'shipping_zipcode' => $user->account->shipping_zipcode, 'shipping_city' => $user->account->shipping_city, 'shipping_country_id' => $user->account->shipping_country_id, 'shipping_phone' => $user->account->getShippingPhoneFull(), 'shipping_postnumber' => $user->account->shipping_postnumber, ]; ShoppingUser::create($data); return true; } catch (\Exception $e) { \Log::channel('cleanup')->error('setUserToClient failed for user_id: '.$user_id.' | Error: '.$e->getMessage()); return false; } } /* find next activ sponsor on user id first $sponsor_id can user_id, looks has m_sponsor or pre_sponsor. */ public static function findNextActiveSponsor($sponsor_id) { $user = User::withTrashed()->find($sponsor_id); if (! $user) { // kein User unter der ID - to root return User::find(6); } // user ist aktiv if ($user->isActiveAccount()) { return $user; } if ($user->m_sponsor) { // hat der User einen m_sponsor return self::findNextActiveSponsor($user->m_sponsor); } if ($user->pre_sponsor) { // hat der User einen pre_sponsor - schon inaktiv return self::findNextActiveSponsor($user->pre_sponsor); } // dump('not sponsor'); return $user; } public static function deactiveUser($user) { $user->pre_sponsor = $user->m_sponsor; // den sponsor speichern für wiederherstellung $user->m_sponsor = null; $user->active = false; $user->save(); } public static function reactiveUser($user) { if ($user->pre_sponsor) { $pre_sponsor = self::findNextActiveSponsor($user->pre_sponsor); $user->m_sponsor = $pre_sponsor->id; // den sponsor wiederherstellen $user->pre_sponsor = null; } $user->active = true; $user->save(); } /** * Praefix fuer pseudonymisierte E-Mail-Adressen geloeschter Benutzer. * Die User-ID gehoert zwingend dazu: ohne sie kollidiert die zweite * Loeschung derselben Adresse mit dem Unique-Index auf users.email. */ public static function buildDeletedEmail(User $user): string { $prefix = 'delete-'.$user->id.'-'; return $prefix.mb_substr(self::stripDeletePrefix((string) $user->email), 0, 255 - mb_strlen($prefix)); } /** * Entfernt das Loesch-Praefix inklusive der optionalen User-ID. * Beruecksichtigt bewusst auch das alte Format ohne ID. */ public static function stripDeletePrefix(?string $email): string { return (string) preg_replace('/^delete-(\d+-)?/', '', (string) $email); } public static function deleteUser(User $user, $complete = false) { // shop wird gelöscht if ($user->shop) { $user->shop->name = 'delete'.$user->shop->id; $user->shop->slug = 'delete'.$user->shop->id; $user->shop->save(); $user->shop->delete(); } // user soll nicht komplett gelöscht werden $user->email = self::buildDeletedEmail($user); // password wird gelöscht $user->password = 'delete'.time(); $user->confirmed = 0; $user->confirmation_code = 'delete'.time(); $user->confirmation_date = null; $user->confirmation_code_to = null; $user->confirmation_code_remider = 2; // $user->agreement = null; $user->active = 0; $user->remember_token = ''; $user->active_date = null; $user->admin = 0; $user->deleted_at = now(); $user->pre_deleted_at = now(); // user soll komplett gelöscht werden if ($complete) { $user->email = 'delete-'.$user->id.'-'.time().'-'.rand(1000, 9999); if ($user->account) { $user->account->delete(); } $user->pre_deleted_at = null; } $user->save(); return true; } public static function checkEmailExists($user) { $email = self::stripDeletePrefix($user->email); $user = User::where('email', $email)->first(); if ($user) { return 'Der Account kann nicht wieder hergestellt werden, da die E-Mail-Adresse '.$email.' bereits in Verwendung ist.'; } return null; } public static function restoreUser($user, $payment_account) { if ($user->pre_sponsor) { $pre_sponsor = self::findNextActiveSponsor($user->pre_sponsor); $user->m_sponsor = $pre_sponsor->id; // den sponsor wiederherstellen $user->pre_sponsor = null; } $user->email = self::stripDeletePrefix($user->email); $user->confirmed = 1; $user->confirmation_date = now(); $user->confirmation_code = null; $user->confirmation_code_to = null; $user->confirmation_code_remider = 0; $user->active = 1; $user->active_date = now(); $user->deleted_at = null; $user->pre_deleted_at = null; $user->payment_account = $payment_account; $user->payment_shop = $payment_account; $user->wizard = 100; $user->save(); $userShop = UserShop::withTrashed()->where('user_id', $user->id)->first(); if ($userShop) { $userShop->name = null; $userShop->slug = null; $userShop->active = 0; $userShop->deleted_at = null; $userShop->save(); } } /** * Haelt fest, wann der Partner zum bezahlten Partner wurde — nur beim ersten * Mal. Verlaengerungen und Wiederherstellungen lassen den Wert stehen, sonst * wuerde ein alter Partner in der Neupartner-Statistik wieder auftauchen. * * @return bool true, wenn der Wert gerade gesetzt wurde */ public static function markPartnerPaid(User $user, ?Carbon $paidAt = null): bool { if ($user->partner_paid_at !== null) { return false; } $user->partner_paid_at = $paidAt ?? now(); return true; } /** * Rueckfuellung von `users.partner_paid_at` fuer bestehende Partner, nur wo * die Spalte leer ist — mehrfach ausfuehrbar. * * Quelle in dieser Reihenfolge: * 1. die Punktebuchung der ersten bezahlten Registrierungsbestellung * (`payment_for = 1`) — sie entsteht im Moment der Zahlung; * 2. ersatzweise das Aenderungsdatum dieser Bestellung; * 3. ohne jede Registrierungsbestellung (Konto vom Admin freigeschaltet) das * Aktivierungsdatum — einen Zahlungszeitpunkt gibt es dort nicht. Gibt es * eine Registrierungsbestellung, die nur noch nicht bezahlt ist (offene * Rechnung), bleibt der Wert leer: er wird bei der Zahlung gesetzt * (Audit 18.09., F1). * * Schreibt ohne Events und ohne `updated_at` anzufassen (Audit 18.09., F5). * * Absichtlich NICHT `payment_account` minus ein Jahr: bei Verlaengerungen * wird das Konto vom alten Ablaufdatum aus verlaengert, das Ergebnis waere der * Jahrestag der Erstzahlung und jeder Verlaengerer ein „Neupartner". * * @return int Anzahl gesetzter Zeilen */ public static function backfillPartnerPaidAt(): int { $set = 0; User::withTrashed() ->whereNull('partner_paid_at') ->whereNotNull('payment_account') ->orderBy('id') ->chunkById(200, function ($users) use (&$set): void { foreach ($users as $user) { $paidAt = self::firstRegistrationPaidAt((int) $user->id); if ($paidAt === null && ! self::hasRegistrationOrder((int) $user->id)) { $paidAt = $user->active_date ? Carbon::parse($user->active_date) : null; } if ($paidAt === null) { continue; } $user->partner_paid_at = $paidAt; $user->timestamps = false; $user->saveQuietly(); $user->timestamps = true; $set++; } }); return $set; } private static function hasRegistrationOrder(int $userId): bool { return ShoppingOrder::query() ->where('auth_user_id', $userId) ->where('payment_for', 1) ->exists(); } private static function firstRegistrationPaidAt(int $userId): ?Carbon { $order = ShoppingOrder::query() ->where('auth_user_id', $userId) ->where('payment_for', 1) ->where('paid', 1) ->orderBy('id') ->first(['id', 'updated_at']); if ($order === null) { return null; } $booking = UserSalesVolume::query() ->where('user_id', $userId) ->where('shopping_order_id', $order->id) ->orderBy('id') ->value('created_at'); return Carbon::parse($booking ?? $order->updated_at); } public static function reactiveUserResetChilds($user_id, $info = '') { $user = User::find($user_id); if (! $user) { \Log::channel('cleanup')->error('reactiveUserResetChilds find no user by user_id:'.$user_id); return 0; } $data = [ 'user_id' => $user->id, 'email' => $user->email, 'm_account' => $user->account ? $user->account->m_account : '', 'm_first_name' => $user->account ? $user->account->m_first_name : '', 'm_last_name' => $user->account ? $user->account->m_last_name : '', ]; \Log::channel('cleanup')->info('reactiveUserResetChilds '.$info.' : '.json_encode($data)); self::reactiveUser($user); self::resetChildsToSponsor($user->id); } public static function deactiveUserNewSponsorChilds($user_id, $info = '') { $user = User::find($user_id); if (! $user) { \Log::channel('cleanup')->error('deactiveUserNewSponsorChilds find no user by user_id:'.$user_id); return 0; } $data = [ 'user_id' => $user->id, 'email' => $user->email, 'm_account' => $user->account ? $user->account->m_account : '', 'm_first_name' => $user->account ? $user->account->m_first_name : '', 'm_last_name' => $user->account ? $user->account->m_last_name : '', ]; $active_sponsor = self::findNextActiveSponsor($user->m_sponsor); if ($active_sponsor) { self::setNewSponsorToChilds($user->id, $active_sponsor->id); } else { \Log::channel('cleanup')->error('cleanUpInActiveUser find no active_sponsor by inactive_user:'.$user->id); } \Log::channel('cleanup')->info('deactiveUserNewSponsorChilds '.$info.' : '.json_encode($data)); self::deactiveUser($user); } }