Recruiting Challenge: Rangliste nach Umsatz der Neupartner, Steuerpflicht

- 50 EUR je Neupartner bleiben; die Top 3 (500/300/200 EUR) ermittelt
  jetzt der Umsatz der Neupartner (wie Montenegro, ohne Einmalpunkte/Abos)
- Gleichstand bei Umsatzwertung: vorn liegt, wessen letzte gezaehlte
  Umsatzbuchung frueher kam
- Challenge-Seite: Praemie und Top-3-Darstellung auch bei Umsatzwertung,
  Ranglisten-Hinweis auf Umsatz (DE/EN/ES/FR)
- Seeder: neue Texte und Bedingungen (Rangliste, Steuerpflicht,
  vergünstigter Einstieg bis 31.10.), gleicht Wertung beim Einspielen ab

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-10-08 16:19:30 +00:00
parent 0a3eb791d4
commit fe1a9478f4
12 changed files with 239 additions and 79 deletions

View file

@ -400,6 +400,23 @@ class Incentive extends Model
return ! $this->includesSalesPoints() && ! $this->usesAbos() && $this->points_partner_onetime > 0; return ! $this->includesSalesPoints() && ! $this->usesAbos() && $this->points_partner_onetime > 0;
} }
/**
* Rangliste nach Umsatzpunkten der Neupartner: keine Einmal- und keine Abopunkte
* (Recruiting-Challenge ab 08.10.2026, Berechnung wie Montenegro).
*/
public function ranksBySalesOfNewPartners(): bool
{
return $this->includesSalesPoints() && ! $this->usesAbos() && $this->points_partner_onetime <= 0;
}
/**
* Darstellung als Challenge mit Geldpraemie (Praemie je Neupartner, Top-Bonus) statt Punktesystem.
*/
public function isCashChallenge(): bool
{
return $this->hasCashPayout() && ($this->ranksByPartnerCount() || $this->ranksBySalesOfNewPartners());
}
/** /**
* Get specific translation for a field and locale. * Get specific translation for a field and locale.
*/ */

View file

@ -13,6 +13,7 @@ use App\Models\UserAboOrder;
use App\Models\UserSalesVolume; use App\Models\UserSalesVolume;
use App\User; use App\User;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
class IncentiveTracker class IncentiveTracker
@ -414,9 +415,37 @@ class IncentiveTracker
} }
} }
if ($incentive->includesSalesPoints()) {
foreach (self::latestCountedSalesVolumeAt($participantIds) as $participantId => $timestamp) {
$reached[$participantId] = max($reached[$participantId] ?? 0, Carbon::parse($timestamp)->getTimestamp());
}
}
return $reached; return $reached;
} }
/**
* Juengste gezaehlte Umsatzbuchung je Teilnehmer, gemessen am Buchungszeitpunkt des
* Sales Volumes (bleibt beim Neuaufbau der Logs stabil).
*
* @param list<int> $participantIds
* @return Collection<int, string> Teilnehmer-ID => Zeitstempel
*/
private static function latestCountedSalesVolumeAt(array $participantIds): Collection
{
$logTable = (new IncentivePointsLog)->getTable();
$volumeTable = (new UserSalesVolume)->getTable();
return IncentivePointsLog::query()
->join($volumeTable, "{$volumeTable}.id", '=', "{$logTable}.user_sales_volume_id")
->whereIn("{$logTable}.participant_id", $participantIds)
->where("{$logTable}.is_storno", false)
->where("{$logTable}.points_accumulated", '>', 0)
->groupBy("{$logTable}.participant_id")
->selectRaw("{$logTable}.participant_id as participant_id, MAX({$volumeTable}.created_at) as reached_at")
->pluck('reached_at', 'participant_id');
}
/** /**
* Log-Eintrag schreiben (Audit-Trail, keine Duplikate). * Log-Eintrag schreiben (Audit-Trail, keine Duplikate).
*/ */

View file

@ -9,12 +9,17 @@ use Illuminate\Database\Seeder;
* Recruiting Challenge 9. Oktober 2026 bis 31. Januar 2027 (Entwicklungsplan E1). * Recruiting Challenge 9. Oktober 2026 bis 31. Januar 2027 (Entwicklungsplan E1).
* *
* Legt die Challenge mit den abgestimmten Texten als Entwurf an oder aktualisiert * Legt die Challenge mit den abgestimmten Texten als Entwurf an oder aktualisiert
* Texte, Uebersetzungen (EN/ES/FR) und den Qualifikationsbeginn, wenn sie schon * Texte, Uebersetzungen (EN/ES/FR), den Qualifikationsbeginn und die Wertung, wenn sie
* existiert (Schluessel: Slug). Der Beginn steht in den Texten und wird deshalb mit * schon existiert (Schluessel: Slug). Beginn und Wertung stehen in den Texten und werden
* ihnen abgeglichen; alle anderen Konfigurationswerte werden nur beim Anlegen gesetzt, * deshalb mit ihnen abgeglichen; alle anderen Konfigurationswerte werden nur beim Anlegen
* damit nachtraegliche Admin-Aenderungen erhalten bleiben. * gesetzt, damit nachtraegliche Admin-Aenderungen erhalten bleiben.
*
* Wertung seit 08.10.2026: 50 EUR je Neupartner bleiben, die Rangliste fuer die Top 3
* zaehlt aber den Umsatz der Neupartner (wie Montenegro, ohne Einmalpunkte und Abos).
* Nach dem Einspielen die Punkte neu aufbauen:
* *
* php artisan db:seed --class=RecruitingChallenge2026Seeder * php artisan db:seed --class=RecruitingChallenge2026Seeder
* php artisan incentive:calculate <ID> --force
* *
* Danach im Admin pruefen und auf "Aktiv" stellen. Das Titelbild liegt unter * Danach im Admin pruefen und auf "Aktiv" stellen. Das Titelbild liegt unter
* public/img/incentive/recruiting-challenge-2026-27/. Zur Abstimmung ist * public/img/incentive/recruiting-challenge-2026-27/. Zur Abstimmung ist
@ -54,12 +59,13 @@ class RecruitingChallenge2026Seeder extends Seeder
'fr' => $this->termsFr(), 'fr' => $this->termsFr(),
], ],
'qualification_start' => self::QUALIFICATION_START, 'qualification_start' => self::QUALIFICATION_START,
'points_partner_onetime' => 0,
'include_sales_points' => true,
]; ];
$config = [ $config = [
'qualification_end' => '2027-01-31', 'qualification_end' => '2027-01-31',
'calculation_end' => '2027-01-31', 'calculation_end' => '2027-01-31',
'points_partner_onetime' => 1,
'points_abo_onetime' => 0, 'points_abo_onetime' => 0,
'min_direct_partners' => 0, 'min_direct_partners' => 0,
'min_customer_abos' => 0, 'min_customer_abos' => 0,
@ -68,7 +74,6 @@ class RecruitingChallenge2026Seeder extends Seeder
'bonus_rank_1' => 500, 'bonus_rank_1' => 500,
'bonus_rank_2' => 300, 'bonus_rank_2' => 300,
'bonus_rank_3' => 200, 'bonus_rank_3' => 200,
'include_sales_points' => false,
'include_abos' => false, 'include_abos' => false,
'status' => 0, 'status' => 0,
'vip_only' => true, 'vip_only' => true,
@ -79,7 +84,7 @@ class RecruitingChallenge2026Seeder extends Seeder
if ($incentive) { if ($incentive) {
$incentive->update($texts); $incentive->update($texts);
$this->command?->info('Recruiting Challenge aktualisiert (Texte, Uebersetzungen, Beginn), ID '.$incentive->id); $this->command?->info('Recruiting Challenge aktualisiert (Texte, Uebersetzungen, Beginn, Wertung), ID '.$incentive->id);
return; return;
} }
@ -91,11 +96,13 @@ class RecruitingChallenge2026Seeder extends Seeder
private function description(): string private function description(): string
{ {
return <<<'HTML' return <<<'HTML'
<p><strong>Jeder neue Partner bringt dir 50 €. Sofort gezählt, im Februar ausgezahlt.</strong></p> <p><strong>Jeder neue Partner bringt dir 50 €. Und die Top 3 holen sich obendrauf einen Extrabonus.</strong></p>
<p>Vom 9. Oktober bis zum 31. Januar zählt jeder neue Partner, der mit dir startet und ein Starterpaket bestellt. Kein Mindestumsatz. Keine Mindestanzahl. Der erste zählt genauso wie der zwanzigste.</p> <p>Vom 9. Oktober bis zum 31. Januar zählt jeder neue Partner, der mit dir startet und ein Starterpaket bestellt. Kein Mindestumsatz. Keine Mindestanzahl. Für jeden gibt es 50 €, der erste zählt genauso wie der zwanzigste.</p>
<p>Und wer am 31. Januar die meisten neuen Partner im Team hat, holt sich obendrauf den Top 3 Bonus: <strong>500 € für Platz 1, 300 € für Platz 2, 200 € für Platz 3.</strong></p> <p>Für die Top 3 zählt der Umsatz deiner neuen Partner: Starterpaket, Eigen- und Kundenumsatz in Punkten, bis zum 31. Januar. Wer dann vorn liegt, holt sich den Top 3 Bonus: <strong>500 € für Platz 1, 300 € für Platz 2, 200 € für Platz 3.</strong></p>
<p>Deine Punkte laufen automatisch mit. Bestätige einmal deine Teilnahme, dann steht dein Name in der Rangliste. Ab da gilt: Jedes Starterpaket zählt.</p> <p><strong>Rückenwind für den Start:</strong> Bis zum 31. Oktober steigen neue Partner noch vergünstigt ein.</p>
<p>Deine Punkte laufen automatisch mit. Bestätige einmal deine Teilnahme, dann steht dein Name in der Rangliste.</p>
<p><strong>Fünf neue Partner? 250 €. Zehn? 500 €. Und Platz 1 legt noch 500 € drauf.</strong></p> <p><strong>Fünf neue Partner? 250 €. Zehn? 500 €. Und Platz 1 legt noch 500 € drauf.</strong></p>
<p><small>Steuerpflicht: Die Boni werden als Bruttobeiträge ausgewiesen und unterliegen der gesetzlichen Steuer- und Sozialversicherungspflicht.</small></p>
HTML; HTML;
} }
@ -103,50 +110,58 @@ HTML;
{ {
return <<<'HTML' return <<<'HTML'
<h5>Teilnahmebedingungen: Recruiting Challenge 2026/27</h5> <h5>Teilnahmebedingungen: Recruiting Challenge 2026/27</h5>
<p><strong>1. Worum es geht.</strong> mivita veranstaltet die Recruiting Challenge 2026/27. Für jeden neuen Partner, den ein Berater im Aktionszeitraum gewinnt, zahlt mivita eine Prämie. Die drei Berater mit den meisten neuen Partnern erhalten zusätzlich einen Bonus.</p> <p><strong>1. Worum es geht.</strong> mivita veranstaltet die Recruiting Challenge 2026/27. Für jeden neuen Partner, den ein Berater im Aktionszeitraum gewinnt, zahlt mivita eine Prämie. Die drei Berater, deren neue Partner den höchsten Umsatz erzielen, erhalten zusätzlich einen Bonus.</p>
<p><strong>2. Wer mitmachen kann.</strong> Alle Berater mit aktivem Beraterkonto. Die Teilnahme wird einmal im Backoffice bestätigt. Neue Partner werden ab dem 9. Oktober 2026 gezählt, egal wann die Bestätigung erfolgt. Ohne Bestätigung erscheint der Berater nicht in der Rangliste und erhält keine Auszahlung.</p> <p><strong>2. Wer mitmachen kann.</strong> Alle Berater mit aktivem Beraterkonto. Die Teilnahme wird einmal im Backoffice bestätigt. Neue Partner werden ab dem 9. Oktober 2026 gezählt, egal wann die Bestätigung erfolgt. Ohne Bestätigung erscheint der Berater nicht in der Rangliste und erhält keine Auszahlung.</p>
<p><strong>3. Aktionszeitraum.</strong> 9. Oktober 2026 bis 31. Januar 2027. Es zählt das Datum der bezahlten Registrierungsbestellung des neuen Partners.</p> <p><strong>3. Aktionszeitraum.</strong> 9. Oktober 2026 bis 31. Januar 2027. Für einen neuen Partner zählt das Datum der bezahlten Registrierungsbestellung.</p>
<p><strong>4. Was zählt.</strong> Ein neuer Partner ist eine Person, die sich im Aktionszeitraum mit dem Teilnehmer als Sponsor als Berater registriert und ein Starterpaket bezahlt hat. Eine Registrierung nur mit Mitgliedschaft zählt nicht. Auch Kunden, die im Aktionszeitraum Berater werden, zählen als neue Partner. Jeder neue Partner wird einmal gezählt. Maßgeblich ist der Sponsor, der im System hinterlegt ist: Wird ein neuer Partner nachträglich einem anderen Sponsor zugeordnet, zum Beispiel nach einer Anmeldung über einen falschen Link, zählt er beim neuen Sponsor. Die Rangliste ergibt sich aus der Anzahl neuer Partner.</p> <p><strong>4. Was zählt.</strong> Ein neuer Partner ist eine Person, die sich im Aktionszeitraum mit dem Teilnehmer als Sponsor als Berater registriert und ein Starterpaket bezahlt hat. Eine Registrierung nur mit Mitgliedschaft zählt nicht. Auch Kunden, die im Aktionszeitraum Berater werden, zählen als neue Partner. Jeder neue Partner wird einmal gezählt. Maßgeblich ist der Sponsor, der im System hinterlegt ist: Wird ein neuer Partner nachträglich einem anderen Sponsor zugeordnet, zum Beispiel nach einer Anmeldung über einen falschen Link, zählt er beim neuen Sponsor.</p>
<p><strong>5. Prämie.</strong> 50 € je neuem Partner, ohne Obergrenze. Die Berater auf den Plätzen 1 bis 3 erhalten zusätzlich 500 €, 300 € und 200 €.</p> <p><strong>5. Rangliste.</strong> Die Rangliste ergibt sich aus dem Umsatz der neuen Partner. Gezählt werden die Umsatzpunkte der neuen Partner bis zum 31. Januar 2027: das Starterpaket sowie ihr Eigen- und Kundenumsatz. Der eigene Umsatz des Teilnehmers zählt nicht.</p>
<p><strong>6. Gleichstand.</strong> Haben mehrere Berater die gleiche Anzahl neuer Partner, liegt vorn, wer diese Anzahl zuerst erreicht hat.</p> <p><strong>6. Gleichstand.</strong> Haben mehrere Berater die gleiche Punktzahl, liegt vorn, wer diese Punktzahl zuerst erreicht hat.</p>
<p><strong>7. Widerruf und Storno.</strong> Widerruft ein neuer Partner seine Registrierung oder wird die Bestellung storniert, entfällt die Wertung für diesen Partner. In der eigenen Berechnung steht er dann als storniert. Stichtag ist die Auszahlung im Februar 2027, danach wird nicht mehr zurückgerechnet.</p> <p><strong>7. Prämie und Bonus.</strong> 50 € je neuem Partner, ohne Obergrenze. Die Berater auf den Plätzen 1 bis 3 der Rangliste erhalten zusätzlich 500 €, 300 € und 200 €. Es gibt genau drei Gewinner.</p>
<p><strong>8. Auszahlung.</strong> Die Prämien werden nach Ende der Challenge im Februar 2027 gesammelt ausgezahlt. Die Prämie ist eine Einnahme aus der Beratertätigkeit. Für die Versteuerung ist der Berater selbst verantwortlich.</p> <p><strong>8. Widerruf und Storno.</strong> Widerruft ein neuer Partner seine Registrierung oder wird die Bestellung storniert, entfällt die Wertung für diesen Partner. In der eigenen Berechnung steht er dann als storniert. Stornierte Umsätze werden von den Punkten abgezogen. Stichtag ist die Auszahlung im Februar 2027, danach wird nicht mehr zurückgerechnet.</p>
<p><strong>9. Ausschluss.</strong> Bei Missbrauch, zum Beispiel Scheinregistrierungen oder Mehrfachkonten, kann mivita einzelne Wertungen streichen oder den Teilnehmer ausschließen.</p> <p><strong>9. Auszahlung.</strong> Prämien und Boni werden nach Ende der Challenge im Februar 2027 gesammelt ausgezahlt.</p>
<p><strong>10. Änderungen.</strong> mivita kann die Bedingungen aus sachlichem Grund anpassen. Änderungen werden im Backoffice bekannt gegeben.</p> <p><strong>10. Steuerpflicht.</strong> Die Boni werden als Bruttobeiträge ausgewiesen und unterliegen der gesetzlichen Steuer- und Sozialversicherungspflicht.</p>
<p><strong>11. Datenschutz.</strong> Nach Bestätigung der Teilnahme sind Name und Punktestand des Teilnehmers in der Rangliste für andere Berater sichtbar.</p> <p><strong>11. Ausschluss.</strong> Bei Missbrauch, zum Beispiel Scheinregistrierungen oder Mehrfachkonten, kann mivita einzelne Wertungen streichen oder den Teilnehmer ausschließen.</p>
<p><strong>12. Änderungen.</strong> mivita kann die Bedingungen aus sachlichem Grund anpassen. Änderungen werden im Backoffice bekannt gegeben.</p>
<p><strong>13. Datenschutz.</strong> Nach Bestätigung der Teilnahme sind Name und Punktestand des Teilnehmers in der Rangliste für andere Berater sichtbar.</p>
HTML; HTML;
} }
private function descriptionEn(): string private function descriptionEn(): string
{ {
return <<<'HTML' return <<<'HTML'
<p><strong>Every new partner earns you €50. Counted right away, paid out in February.</strong></p> <p><strong>Every new partner earns you €50. And the top 3 get an extra bonus on top.</strong></p>
<p>From 9 October to 31 January, every new partner who starts with you and orders a starter kit counts. No minimum sales. No minimum number. The first one counts just as much as the twentieth.</p> <p>From 9 October to 31 January, every new partner who starts with you and orders a starter kit counts. No minimum sales. No minimum number. Each one earns you €50, and the first one counts just as much as the twentieth.</p>
<p>And whoever has the most new partners in their team on 31 January also gets the Top 3 Bonus: <strong>€500 for 1st place, €300 for 2nd place, €200 for 3rd place.</strong></p> <p>For the top 3, the sales of your new partners count: starter kit, own and customer sales in points, up to 31 January. Whoever is ahead then gets the Top 3 Bonus: <strong>€500 for 1st place, €300 for 2nd place, €200 for 3rd place.</strong></p>
<p>Your points are tracked automatically. Confirm your participation once and your name appears in the ranking. From then on: every starter kit counts.</p> <p><strong>A boost for the start:</strong> Until 31 October, new partners can still join at a reduced price.</p>
<p>Your points are tracked automatically. Confirm your participation once and your name appears in the ranking.</p>
<p><strong>Five new partners? €250. Ten? €500. And 1st place adds another €500.</strong></p> <p><strong>Five new partners? €250. Ten? €500. And 1st place adds another €500.</strong></p>
<p><small>Tax liability: The bonuses are stated as gross amounts and are subject to statutory tax and social security contributions.</small></p>
HTML; HTML;
} }
private function descriptionEs(): string private function descriptionEs(): string
{ {
return <<<'HTML' return <<<'HTML'
<p><strong>Cada nuevo socio te aporta 50 €. Se cuenta al momento y se paga en febrero.</strong></p> <p><strong>Cada nuevo socio te aporta 50 €. Y el top 3 se lleva además un bonus extra.</strong></p>
<p>Del 9 de octubre al 31 de enero cuenta cada nuevo socio que empiece contigo y pida un kit de inicio. Sin ventas mínimas. Sin número mínimo. El primero cuenta igual que el vigésimo.</p> <p>Del 9 de octubre al 31 de enero cuenta cada nuevo socio que empiece contigo y pida un kit de inicio. Sin ventas mínimas. Sin número mínimo. Por cada uno recibes 50 €, y el primero cuenta igual que el vigésimo.</p>
<p>Y quien tenga más socios nuevos en su equipo el 31 de enero se lleva además el bonus Top 3: <strong>500 € para el 1.er puesto, 300 € para el 2.º puesto y 200 € para el 3.er puesto.</strong></p> <p>Para el top 3 cuentan las ventas de tus nuevos socios: kit de inicio, ventas propias y de clientes en puntos, hasta el 31 de enero. Quien vaya en cabeza se lleva el bonus Top 3: <strong>500 € para el 1.er puesto, 300 € para el 2.º puesto y 200 € para el 3.er puesto.</strong></p>
<p>Tus puntos se cuentan automáticamente. Confirma una vez tu participación y tu nombre aparecerá en la clasificación. A partir de ahí, cada kit de inicio cuenta.</p> <p><strong>Impulso para empezar:</strong> Hasta el 31 de octubre, los nuevos socios todavía pueden entrar a un precio reducido.</p>
<p>Tus puntos se cuentan automáticamente. Confirma una vez tu participación y tu nombre aparecerá en la clasificación.</p>
<p><strong>¿Cinco socios nuevos? 250 €. ¿Diez? 500 €. Y el 1.er puesto suma otros 500 €.</strong></p> <p><strong>¿Cinco socios nuevos? 250 €. ¿Diez? 500 €. Y el 1.er puesto suma otros 500 €.</strong></p>
<p><small>Obligación fiscal: Los bonus se indican como importes brutos y están sujetos a las obligaciones legales de impuestos y seguridad social.</small></p>
HTML; HTML;
} }
private function descriptionFr(): string private function descriptionFr(): string
{ {
return <<<'HTML' return <<<'HTML'
<p><strong>Chaque nouveau partenaire te rapporte 50 €. Comptabilisé immédiatement, versé en février.</strong></p> <p><strong>Chaque nouveau partenaire te rapporte 50 €. Et le top 3 remporte en plus un bonus supplémentaire.</strong></p>
<p>Du 9 octobre au 31 janvier, chaque nouveau partenaire qui démarre avec toi et commande un kit de démarrage compte. Pas de chiffre d’affaires minimum. Pas de nombre minimum. Le premier compte autant que le vingtième.</p> <p>Du 9 octobre au 31 janvier, chaque nouveau partenaire qui démarre avec toi et commande un kit de démarrage compte. Pas de chiffre d’affaires minimum. Pas de nombre minimum. Chacun te rapporte 50 €, et le premier compte autant que le vingtième.</p>
<p>Et celui ou celle qui a le plus de nouveaux partenaires dans son équipe au 31 janvier remporte en plus le bonus Top 3 : <strong>500 € pour la 1re place, 300 € pour la 2e place, 200 € pour la 3e place.</strong></p> <p>Pour le top 3, c’est le chiffre d’affaires de tes nouveaux partenaires qui compte : kit de démarrage, chiffre d’affaires personnel et clients en points, jusqu’au 31 janvier. Celui ou celle qui est alors en tête remporte le bonus Top 3 : <strong>500 € pour la 1re place, 300 € pour la 2e place, 200 € pour la 3e place.</strong></p>
<p>Tes points sont comptabilisés automatiquement. Confirme une fois ta participation et ton nom apparaît dans le classement. Dès lors, chaque kit de démarrage compte.</p> <p><strong>Un coup de pouce pour démarrer :</strong> Jusqu’au 31 octobre, les nouveaux partenaires peuvent encore démarrer à prix réduit.</p>
<p>Tes points sont comptabilisés automatiquement. Confirme une fois ta participation et ton nom apparaît dans le classement.</p>
<p><strong>Cinq nouveaux partenaires ? 250 €. Dix ? 500 €. Et la 1re place ajoute encore 500 €.</strong></p> <p><strong>Cinq nouveaux partenaires ? 250 €. Dix ? 500 €. Et la 1re place ajoute encore 500 €.</strong></p>
<p><small>Obligation fiscale : Les bonus sont indiqués en montants bruts et sont soumis aux obligations légales en matière d’impôts et de cotisations sociales.</small></p>
HTML; HTML;
} }
@ -154,17 +169,19 @@ HTML;
{ {
return <<<'HTML' return <<<'HTML'
<h5>Terms of participation: Recruiting Challenge 2026/27</h5> <h5>Terms of participation: Recruiting Challenge 2026/27</h5>
<p><strong>1. What it is about.</strong> mivita is running the Recruiting Challenge 2026/27. For every new partner a consultant wins during the promotion period, mivita pays a reward. The three consultants with the most new partners also receive a bonus.</p> <p><strong>1. What it is about.</strong> mivita is running the Recruiting Challenge 2026/27. For every new partner a consultant wins during the promotion period, mivita pays a reward. The three consultants whose new partners generate the highest sales also receive a bonus.</p>
<p><strong>2. Who can take part.</strong> All consultants with an active consultant account. Participation is confirmed once in the back office. New partners are counted from 9 October 2026, regardless of when the confirmation is given. Without confirmation, the consultant does not appear in the ranking and receives no payout.</p> <p><strong>2. Who can take part.</strong> All consultants with an active consultant account. Participation is confirmed once in the back office. New partners are counted from 9 October 2026, regardless of when the confirmation is given. Without confirmation, the consultant does not appear in the ranking and receives no payout.</p>
<p><strong>3. Promotion period.</strong> 9 October 2026 to 31 January 2027. The date on which the new partner paid the registration order counts.</p> <p><strong>3. Promotion period.</strong> 9 October 2026 to 31 January 2027. For a new partner, the date on which the registration order was paid counts.</p>
<p><strong>4. What counts.</strong> A new partner is a person who registers as a consultant during the promotion period with the participant as sponsor and has paid for a starter kit. A registration with membership only does not count. Customers who become consultants during the promotion period also count as new partners. Each new partner is counted once. The sponsor recorded in the system is decisive: if a new partner is later assigned to a different sponsor, for example after registering via the wrong link, they count for the new sponsor. The ranking is based on the number of new partners.</p> <p><strong>4. What counts.</strong> A new partner is a person who registers as a consultant during the promotion period with the participant as sponsor and has paid for a starter kit. A registration with membership only does not count. Customers who become consultants during the promotion period also count as new partners. Each new partner is counted once. The sponsor recorded in the system is decisive: if a new partner is later assigned to a different sponsor, for example after registering via the wrong link, they count for the new sponsor.</p>
<p><strong>5. Reward.</strong> €50 per new partner, with no upper limit. The consultants in places 1 to 3 additionally receive €500, €300 and €200.</p> <p><strong>5. Ranking.</strong> The ranking is based on the sales of the new partners. The sales points of the new partners up to 31 January 2027 count: the starter kit as well as their own and customer sales. The participant's own sales do not count.</p>
<p><strong>6. Tie.</strong> If several consultants have the same number of new partners, whoever reached that number first ranks ahead.</p> <p><strong>6. Tie.</strong> If several consultants have the same score, whoever reached that score first ranks ahead.</p>
<p><strong>7. Withdrawal and cancellation.</strong> If a new partner withdraws their registration or the order is cancelled, that partner no longer counts and is marked as cancelled in the consultant's own calculation. The cut-off is the payout in February 2027; no recalculation takes place after that.</p> <p><strong>7. Reward and bonus.</strong> €50 per new partner, with no upper limit. The consultants in places 1 to 3 of the ranking additionally receive €500, €300 and €200. There are exactly three winners.</p>
<p><strong>8. Payout.</strong> The rewards are paid out together after the end of the challenge in February 2027. The reward is income from the consultant activity. The consultant is responsible for any taxes.</p> <p><strong>8. Withdrawal and cancellation.</strong> If a new partner withdraws their registration or the order is cancelled, that partner no longer counts and is marked as cancelled in the consultant's own calculation. Cancelled sales are deducted from the points. The cut-off is the payout in February 2027; no recalculation takes place after that.</p>
<p><strong>9. Exclusion.</strong> In case of abuse, for example fake registrations or multiple accounts, mivita may remove individual results or exclude the participant.</p> <p><strong>9. Payout.</strong> Rewards and bonuses are paid out together after the end of the challenge in February 2027.</p>
<p><strong>10. Changes.</strong> mivita may adjust these terms for objective reasons. Changes are announced in the back office.</p> <p><strong>10. Tax liability.</strong> The bonuses are stated as gross amounts and are subject to statutory tax and social security contributions.</p>
<p><strong>11. Data protection.</strong> Once participation is confirmed, the participant's name and score are visible to other consultants in the ranking.</p> <p><strong>11. Exclusion.</strong> In case of abuse, for example fake registrations or multiple accounts, mivita may remove individual results or exclude the participant.</p>
<p><strong>12. Changes.</strong> mivita may adjust these terms for objective reasons. Changes are announced in the back office.</p>
<p><strong>13. Data protection.</strong> Once participation is confirmed, the participant's name and score are visible to other consultants in the ranking.</p>
HTML; HTML;
} }
@ -172,17 +189,19 @@ HTML;
{ {
return <<<'HTML' return <<<'HTML'
<h5>Condiciones de participación: Recruiting Challenge 2026/27</h5> <h5>Condiciones de participación: Recruiting Challenge 2026/27</h5>
<p><strong>1. De qué se trata.</strong> mivita organiza la Recruiting Challenge 2026/27. Por cada nuevo socio que un asesor consiga durante el periodo de la promoción, mivita paga una prima. Los tres asesores con más socios nuevos reciben además un bonus.</p> <p><strong>1. De qué se trata.</strong> mivita organiza la Recruiting Challenge 2026/27. Por cada nuevo socio que un asesor consiga durante el periodo de la promoción, mivita paga una prima. Los tres asesores cuyos nuevos socios generen las ventas más altas reciben además un bonus.</p>
<p><strong>2. Quién puede participar.</strong> Todos los asesores con una cuenta de asesor activa. La participación se confirma una vez en el backoffice. Los nuevos socios se cuentan a partir del 9 de octubre de 2026, independientemente de cuándo se confirme. Sin confirmación, el asesor no aparece en la clasificación y no recibe ningún pago.</p> <p><strong>2. Quién puede participar.</strong> Todos los asesores con una cuenta de asesor activa. La participación se confirma una vez en el backoffice. Los nuevos socios se cuentan a partir del 9 de octubre de 2026, independientemente de cuándo se confirme. Sin confirmación, el asesor no aparece en la clasificación y no recibe ningún pago.</p>
<p><strong>3. Periodo de la promoción.</strong> Del 9 de octubre de 2026 al 31 de enero de 2027. Cuenta la fecha en que el nuevo socio pagó el pedido de registro.</p> <p><strong>3. Periodo de la promoción.</strong> Del 9 de octubre de 2026 al 31 de enero de 2027. Para un nuevo socio cuenta la fecha en que se pagó el pedido de registro.</p>
<p><strong>4. Qué cuenta.</strong> Un nuevo socio es una persona que, durante el periodo de la promoción, se registra como asesor con el participante como patrocinador y ha pagado un kit de inicio. Un registro solo con membresía no cuenta. También cuentan como nuevos socios los clientes que se conviertan en asesores durante el periodo de la promoción. Cada nuevo socio se cuenta una vez. Es determinante el patrocinador registrado en el sistema: si un nuevo socio se asigna posteriormente a otro patrocinador, por ejemplo tras registrarse a través de un enlace equivocado, cuenta para el nuevo patrocinador. La clasificación se basa en el número de socios nuevos.</p> <p><strong>4. Qué cuenta.</strong> Un nuevo socio es una persona que, durante el periodo de la promoción, se registra como asesor con el participante como patrocinador y ha pagado un kit de inicio. Un registro solo con membresía no cuenta. También cuentan como nuevos socios los clientes que se conviertan en asesores durante el periodo de la promoción. Cada nuevo socio se cuenta una vez. Es determinante el patrocinador registrado en el sistema: si un nuevo socio se asigna posteriormente a otro patrocinador, por ejemplo tras registrarse a través de un enlace equivocado, cuenta para el nuevo patrocinador.</p>
<p><strong>5. Prima.</strong> 50 € por cada nuevo socio, sin límite. Los asesores en los puestos 1 a 3 reciben además 500 €, 300 € y 200 €.</p> <p><strong>5. Clasificación.</strong> La clasificación se basa en las ventas de los nuevos socios. Cuentan los puntos de venta de los nuevos socios hasta el 31 de enero de 2027: el kit de inicio y sus ventas propias y de clientes. No cuentan las ventas propias del participante.</p>
<p><strong>6. Empate.</strong> Si varios asesores tienen el mismo número de socios nuevos, queda por delante quien alcanzó ese número primero.</p> <p><strong>6. Empate.</strong> Si varios asesores tienen la misma puntuación, queda por delante quien alcanzó esa puntuación primero.</p>
<p><strong>7. Desistimiento y anulación.</strong> Si un nuevo socio revoca su registro o se anula el pedido, ese socio deja de contar y aparece como anulado en el cálculo propio del asesor. La fecha límite es el pago en febrero de 2027; después ya no se recalcula.</p> <p><strong>7. Prima y bonus.</strong> 50 € por cada nuevo socio, sin límite. Los asesores en los puestos 1 a 3 de la clasificación reciben además 500 €, 300 € y 200 €. Hay exactamente tres ganadores.</p>
<p><strong>8. Pago.</strong> Las primas se pagan conjuntamente tras el final de la challenge en febrero de 2027. La prima es un ingreso de la actividad como asesor. El asesor es responsable de su tributación.</p> <p><strong>8. Desistimiento y anulación.</strong> Si un nuevo socio revoca su registro o se anula el pedido, ese socio deja de contar y aparece como anulado en el cálculo propio del asesor. Las ventas anuladas se descuentan de los puntos. La fecha límite es el pago en febrero de 2027; después ya no se recalcula.</p>
<p><strong>9. Exclusión.</strong> En caso de abuso, por ejemplo registros ficticios o cuentas múltiples, mivita puede anular resultados concretos o excluir al participante.</p> <p><strong>9. Pago.</strong> Las primas y los bonus se pagan conjuntamente tras el final de la challenge en febrero de 2027.</p>
<p><strong>10. Cambios.</strong> mivita puede adaptar las condiciones por motivos justificados. Los cambios se anuncian en el backoffice.</p> <p><strong>10. Obligación fiscal.</strong> Los bonus se indican como importes brutos y están sujetos a las obligaciones legales de impuestos y seguridad social.</p>
<p><strong>11. Protección de datos.</strong> Tras confirmar la participación, el nombre y la puntuación del participante son visibles para otros asesores en la clasificación.</p> <p><strong>11. Exclusión.</strong> En caso de abuso, por ejemplo registros ficticios o cuentas múltiples, mivita puede anular resultados concretos o excluir al participante.</p>
<p><strong>12. Cambios.</strong> mivita puede adaptar las condiciones por motivos justificados. Los cambios se anuncian en el backoffice.</p>
<p><strong>13. Protección de datos.</strong> Tras confirmar la participación, el nombre y la puntuación del participante son visibles para otros asesores en la clasificación.</p>
HTML; HTML;
} }
@ -190,17 +209,19 @@ HTML;
{ {
return <<<'HTML' return <<<'HTML'
<h5>Conditions de participation : Recruiting Challenge 2026/27</h5> <h5>Conditions de participation : Recruiting Challenge 2026/27</h5>
<p><strong>1. De quoi s’agit-il.</strong> mivita organise la Recruiting Challenge 2026/27. Pour chaque nouveau partenaire qu’un conseiller recrute pendant la période de l’opération, mivita verse une prime. Les trois conseillers ayant le plus de nouveaux partenaires reçoivent en plus un bonus.</p> <p><strong>1. De quoi s’agit-il.</strong> mivita organise la Recruiting Challenge 2026/27. Pour chaque nouveau partenaire qu’un conseiller recrute pendant la période de l’opération, mivita verse une prime. Les trois conseillers dont les nouveaux partenaires réalisent le chiffre d’affaires le plus élevé reçoivent en plus un bonus.</p>
<p><strong>2. Qui peut participer.</strong> Tous les conseillers disposant d’un compte conseiller actif. La participation est confirmée une fois dans le back-office. Les nouveaux partenaires sont comptés à partir du 9 octobre 2026, quelle que soit la date de confirmation. Sans confirmation, le conseiller n’apparaît pas dans le classement et ne reçoit aucun versement.</p> <p><strong>2. Qui peut participer.</strong> Tous les conseillers disposant d’un compte conseiller actif. La participation est confirmée une fois dans le back-office. Les nouveaux partenaires sont comptés à partir du 9 octobre 2026, quelle que soit la date de confirmation. Sans confirmation, le conseiller n’apparaît pas dans le classement et ne reçoit aucun versement.</p>
<p><strong>3. Période de l’opération.</strong> Du 9 octobre 2026 au 31 janvier 2027. C’est la date à laquelle le nouveau partenaire a payé la commande d’inscription qui compte.</p> <p><strong>3. Période de l’opération.</strong> Du 9 octobre 2026 au 31 janvier 2027. Pour un nouveau partenaire, c’est la date de paiement de la commande d’inscription qui compte.</p>
<p><strong>4. Ce qui compte.</strong> Un nouveau partenaire est une personne qui s’inscrit comme conseiller pendant la période de l’opération avec le participant comme parrain et qui a payé un kit de démarrage. Une inscription avec adhésion seule ne compte pas. Les clients qui deviennent conseillers pendant la période de l’opération comptent également comme nouveaux partenaires. Chaque nouveau partenaire est compté une fois. C’est le parrain enregistré dans le système qui fait foi : si un nouveau partenaire est ensuite rattaché à un autre parrain, par exemple après une inscription via un mauvais lien, il compte pour le nouveau parrain. Le classement se base sur le nombre de nouveaux partenaires.</p> <p><strong>4. Ce qui compte.</strong> Un nouveau partenaire est une personne qui s’inscrit comme conseiller pendant la période de l’opération avec le participant comme parrain et qui a payé un kit de démarrage. Une inscription avec adhésion seule ne compte pas. Les clients qui deviennent conseillers pendant la période de l’opération comptent également comme nouveaux partenaires. Chaque nouveau partenaire est compté une fois. C’est le parrain enregistré dans le système qui fait foi : si un nouveau partenaire est ensuite rattaché à un autre parrain, par exemple après une inscription via un mauvais lien, il compte pour le nouveau parrain.</p>
<p><strong>5. Prime.</strong> 50 € par nouveau partenaire, sans plafond. Les conseillers classés aux places 1 à 3 reçoivent en plus 500 €, 300 € et 200 €.</p> <p><strong>5. Classement.</strong> Le classement se base sur le chiffre d’affaires des nouveaux partenaires. Comptent les points de chiffre d’affaires des nouveaux partenaires jusqu’au 31 janvier 2027 : le kit de démarrage ainsi que leur chiffre d’affaires personnel et clients. Le chiffre d’affaires personnel du participant ne compte pas.</p>
<p><strong>6. Égalité.</strong> Si plusieurs conseillers ont le même nombre de nouveaux partenaires, celui qui a atteint ce nombre en premier est classé devant.</p> <p><strong>6. Égalité.</strong> Si plusieurs conseillers ont le même score, celui qui a atteint ce score en premier est classé devant.</p>
<p><strong>7. Rétractation et annulation.</strong> Si un nouveau partenaire se rétracte ou si la commande est annulée, ce partenaire n’est plus pris en compte et apparaît comme annulé dans le calcul personnel du conseiller. La date limite est le versement en février 2027 ; aucun recalcul n’a lieu ensuite.</p> <p><strong>7. Prime et bonus.</strong> 50 € par nouveau partenaire, sans plafond. Les conseillers classés aux places 1 à 3 reçoivent en plus 500 €, 300 € et 200 €. Il y a exactement trois gagnants.</p>
<p><strong>8. Versement.</strong> Les primes sont versées ensemble après la fin de la challenge, en février 2027. La prime constitue un revenu de l’activité de conseiller. Le conseiller est responsable de sa déclaration fiscale.</p> <p><strong>8. Rétractation et annulation.</strong> Si un nouveau partenaire se rétracte ou si la commande est annulée, ce partenaire n’est plus pris en compte et apparaît comme annulé dans le calcul personnel du conseiller. Le chiffre d’affaires annulé est déduit des points. La date limite est le versement en février 2027 ; aucun recalcul n’a lieu ensuite.</p>
<p><strong>9. Exclusion.</strong> En cas d’abus, par exemple des inscriptions fictives ou des comptes multiples, mivita peut annuler certains résultats ou exclure le participant.</p> <p><strong>9. Versement.</strong> Les primes et les bonus sont versés ensemble après la fin de la challenge, en février 2027.</p>
<p><strong>10. Modifications.</strong> mivita peut adapter les conditions pour un motif objectif. Les modifications sont annoncées dans le back-office.</p> <p><strong>10. Obligation fiscale.</strong> Les bonus sont indiqués en montants bruts et sont soumis aux obligations légales en matière d’impôts et de cotisations sociales.</p>
<p><strong>11. Protection des données.</strong> Après confirmation de la participation, le nom et le score du participant sont visibles par les autres conseillers dans le classement.</p> <p><strong>11. Exclusion.</strong> En cas d’abus, par exemple des inscriptions fictives ou des comptes multiples, mivita peut annuler certains résultats ou exclure le participant.</p>
<p><strong>12. Modifications.</strong> mivita peut adapter les conditions pour un motif objectif. Les modifications sont annoncées dans le back-office.</p>
<p><strong>13. Protection des données.</strong> Après confirmation de la participation, le nom et le score du participant sont visibles par les autres conseillers dans le classement.</p>
HTML; HTML;
} }
} }

View file

@ -211,6 +211,7 @@ return [
'payout_top_bonus_text' => 'Zusatz-Bonus für die Top :n: :list.', 'payout_top_bonus_text' => 'Zusatz-Bonus für die Top :n: :list.',
'payout_rank_label' => 'Platz :n', 'payout_rank_label' => 'Platz :n',
'payout_ranking_hint' => 'Die Rangliste zählt deine Neupartner mit Starterpaket im Qualifikationszeitraum. Die Auszahlung erfolgt gesammelt nach Ende des Zeitraums.', 'payout_ranking_hint' => 'Die Rangliste zählt deine Neupartner mit Starterpaket im Qualifikationszeitraum. Die Auszahlung erfolgt gesammelt nach Ende des Zeitraums.',
'payout_ranking_sales_hint' => 'Die Rangliste zählt den Umsatz deiner Neupartner im Qualifikationszeitraum: Starterpaket, Eigen- und Kundenumsatz in Punkten. Die Auszahlung erfolgt gesammelt nach Ende des Zeitraums.',
'new_partners_short' => 'Neupartner', 'new_partners_short' => 'Neupartner',
'badge_challenge' => 'Challenge', 'badge_challenge' => 'Challenge',
'export_user_id' => 'Berater-ID', 'export_user_id' => 'Berater-ID',

View file

@ -211,6 +211,7 @@ return [
'payout_top_bonus_text' => 'Extra bonus for the top :n: :list.', 'payout_top_bonus_text' => 'Extra bonus for the top :n: :list.',
'payout_rank_label' => 'Rank :n', 'payout_rank_label' => 'Rank :n',
'payout_ranking_hint' => 'The ranking counts your new partners with a starter kit during the qualification period. Payout is made collectively after the period ends.', 'payout_ranking_hint' => 'The ranking counts your new partners with a starter kit during the qualification period. Payout is made collectively after the period ends.',
'payout_ranking_sales_hint' => 'The ranking counts the sales of your new partners during the qualification period: starter kit, own and customer sales in points. Payout is made collectively after the period ends.',
'new_partners_short' => 'New partners', 'new_partners_short' => 'New partners',
'badge_challenge' => 'Challenge', 'badge_challenge' => 'Challenge',
'export_user_id' => 'Consultant ID', 'export_user_id' => 'Consultant ID',

View file

@ -211,6 +211,7 @@ return [
'payout_top_bonus_text' => 'Bono adicional para el top :n: :list.', 'payout_top_bonus_text' => 'Bono adicional para el top :n: :list.',
'payout_rank_label' => 'Puesto :n', 'payout_rank_label' => 'Puesto :n',
'payout_ranking_hint' => 'El ranking cuenta tus nuevos socios con paquete de inicio durante el periodo de cualificación. El pago se realiza de forma conjunta al finalizar el periodo.', 'payout_ranking_hint' => 'El ranking cuenta tus nuevos socios con paquete de inicio durante el periodo de cualificación. El pago se realiza de forma conjunta al finalizar el periodo.',
'payout_ranking_sales_hint' => 'El ranking cuenta las ventas de tus nuevos socios durante el periodo de cualificación: paquete de inicio, ventas propias y de clientes en puntos. El pago se realiza de forma conjunta al finalizar el periodo.',
'new_partners_short' => 'Nuevos socios', 'new_partners_short' => 'Nuevos socios',
'badge_challenge' => 'Reto', 'badge_challenge' => 'Reto',
'export_user_id' => 'ID del asesor', 'export_user_id' => 'ID del asesor',

View file

@ -186,6 +186,7 @@ return [
'payout_top_bonus_text' => 'Bonus supplémentaire pour le top :n : :list.', 'payout_top_bonus_text' => 'Bonus supplémentaire pour le top :n : :list.',
'payout_rank_label' => 'Place :n', 'payout_rank_label' => 'Place :n',
'payout_ranking_hint' => 'Le classement compte tes nouveaux partenaires avec kit de démarrage pendant la période de qualification. Le versement est effectué groupé après la fin de la période.', 'payout_ranking_hint' => 'Le classement compte tes nouveaux partenaires avec kit de démarrage pendant la période de qualification. Le versement est effectué groupé après la fin de la période.',
'payout_ranking_sales_hint' => 'Le classement compte le chiffre d’affaires de tes nouveaux partenaires pendant la période de qualification : kit de démarrage, chiffre d’affaires personnel et clients en points. Le versement est effectué groupé après la fin de la période.',
'new_partners_short' => 'Nouveaux partenaires', 'new_partners_short' => 'Nouveaux partenaires',
'badge_challenge' => 'Challenge', 'badge_challenge' => 'Challenge',
'export_user_id' => 'ID du conseiller', 'export_user_id' => 'ID du conseiller',

View file

@ -23,7 +23,7 @@
</ul> </ul>
<p class="text-muted small mb-0"> <p class="text-muted small mb-0">
<i class="ion ion-md-information-circle mr-1"></i> <i class="ion ion-md-information-circle mr-1"></i>
{{ __('incentive.payout_ranking_hint') }} {{ $incentive->ranksBySalesOfNewPartners() ? __('incentive.payout_ranking_sales_hint') : __('incentive.payout_ranking_hint') }}
</p> </p>
</div> </div>
</div> </div>

View file

@ -1381,7 +1381,7 @@
<span class="tile-label">{{ __('incentive.payout_per_partner_label') }}</span> <span class="tile-label">{{ __('incentive.payout_per_partner_label') }}</span>
</div> </div>
@endif @endif
@if ($incentive->rankBonuses() !== [] && !$incentive->ranksByPartnerCount()) @if ($incentive->rankBonuses() !== [] && !$incentive->isCashChallenge())
<div> <div>
<span class="tile-label d-block mb-1">{{ __('incentive.payout_top_bonus_title', ['n' => count($incentive->rankBonuses())]) }}</span> <span class="tile-label d-block mb-1">{{ __('incentive.payout_top_bonus_title', ['n' => count($incentive->rankBonuses())]) }}</span>
@foreach ($incentive->rankBonuses() as $bonusRank => $bonusAmount) @foreach ($incentive->rankBonuses() as $bonusRank => $bonusAmount)
@ -1415,7 +1415,7 @@
</div> </div>
@endif @endif
@if ($incentive->hasCashPayout() && $incentive->ranksByPartnerCount()) @if ($incentive->isCashChallenge())
{{-- Top 3 Bonus (Recruiting-Challenge) --}} {{-- Top 3 Bonus (Recruiting-Challenge) --}}
<div class="col-md-4"> <div class="col-md-4">
<div class="card info-tile h-100 shadow-sm" id="incentive-bonus-tile"> <div class="card info-tile h-100 shadow-sm" id="incentive-bonus-tile">
@ -1468,7 +1468,7 @@
</div> </div>
{{-- ===== SO FUNKTIONIERT DIE CHALLENGE (Geldpraemie) / PUNKTE-DETAIL ===== --}} {{-- ===== SO FUNKTIONIERT DIE CHALLENGE (Geldpraemie) / PUNKTE-DETAIL ===== --}}
@if ($incentive->hasCashPayout() && $incentive->ranksByPartnerCount()) @if ($incentive->isCashChallenge())
<div class="points-section points-section-wide mb-5" id="incentive-how-it-works"> <div class="points-section points-section-wide mb-5" id="incentive-how-it-works">
<h4 class="points-heading text-left"> <h4 class="points-heading text-left">
<i class="ion ion-md-cash text-warning mr-1"></i> <i class="ion ion-md-cash text-warning mr-1"></i>
@ -1490,7 +1490,7 @@
@if ($incentive->rankBonuses() !== []) @if ($incentive->rankBonuses() !== [])
<li>{{ __('incentive.payout_top_bonus_text', ['n' => count($incentive->rankBonuses()), 'list' => collect($incentive->rankBonuses())->map(fn ($amount, $rank) => __('incentive.payout_rank_label', ['n' => $rank]).' '.\App\Services\Incentive\IncentivePayoutService::formatAmount($amount))->implode(', ')]) }}</li> <li>{{ __('incentive.payout_top_bonus_text', ['n' => count($incentive->rankBonuses()), 'list' => collect($incentive->rankBonuses())->map(fn ($amount, $rank) => __('incentive.payout_rank_label', ['n' => $rank]).' '.\App\Services\Incentive\IncentivePayoutService::formatAmount($amount))->implode(', ')]) }}</li>
@endif @endif
<li>{{ __('incentive.payout_ranking_hint') }}</li> <li>{{ $incentive->ranksBySalesOfNewPartners() ? __('incentive.payout_ranking_sales_hint') : __('incentive.payout_ranking_hint') }}</li>
</ul> </ul>
</div> </div>
</div> </div>

View file

@ -3,6 +3,7 @@
use App\Models\Incentive; use App\Models\Incentive;
use App\Models\IncentiveNewPartner; use App\Models\IncentiveNewPartner;
use App\Models\IncentiveParticipant; use App\Models\IncentiveParticipant;
use App\Models\UserSalesVolume;
use App\Services\Incentive\IncentiveTracker; use App\Services\Incentive\IncentiveTracker;
use App\User; use App\User;
use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\RefreshDatabase;
@ -215,3 +216,64 @@ describe('Gleichstand: wer den Stand zuerst erreicht hat (Recruiting-Challenge,
->and($second->refresh()->rank)->toBe(2); ->and($second->refresh()->rank)->toBe(2);
}); });
}); });
describe('Gleichstand bei Wertung nach Umsatz der Neupartner (Recruiting-Challenge ab 08.10.2026)', function () use ($makeIncentiveRankingUser) {
it('setzt bei gleicher Punktzahl den vor, dessen letzte Umsatzbuchung frueher kam', function () use ($makeIncentiveRankingUser) {
$incentive = Incentive::factory()->create([
'status' => 1,
'qualification_start' => '2026-10-09',
'qualification_end' => '2027-01-31',
'calculation_end' => '2027-01-31',
'points_partner_onetime' => 0,
'points_abo_onetime' => 0,
'min_direct_partners' => 0,
'min_customer_abos' => 0,
'max_winners' => 3,
'amount_per_partner' => 50,
'bonus_rank_1' => 500,
'include_sales_points' => true,
'include_abos' => false,
]);
$participantWithPartnerSales = function (string $bookedAt) use ($incentive, $makeIncentiveRankingUser): IncentiveParticipant {
$participant = IncentiveParticipant::factory()->create([
'incentive_id' => $incentive->id,
'user_id' => $makeIncentiveRankingUser()->id,
'accepted_terms_at' => now(),
'total_points' => 0,
]);
$partner = $makeIncentiveRankingUser();
IncentiveNewPartner::create([
'participant_id' => $participant->id,
'user_id' => $partner->id,
'registered_at' => '2026-10-15 10:00:00',
]);
$this->travelTo($bookedAt);
IncentiveTracker::trackSalesVolume(UserSalesVolume::create([
'user_id' => $partner->id,
'month' => 11,
'year' => 2026,
'date' => '15.11.2026',
'points' => 120,
'total_net' => 150,
'status_points' => 1,
'status' => 1,
'message' => 'Starterpaket Neupartner',
]));
$this->travelBack();
return $participant;
};
$bookedLater = $participantWithPartnerSales('2026-11-20 10:00:00');
$bookedEarlier = $participantWithPartnerSales('2026-11-05 10:00:00');
expect($incentive->ranksBySalesOfNewPartners())->toBeTrue()
->and($bookedLater->refresh()->total_points)->toBe(120)
->and($bookedLater->qualified_partners)->toBe(1)
->and($bookedEarlier->refresh()->total_points)->toBe(120)
->and($bookedEarlier->rank)->toBe(1)
->and($bookedLater->rank)->toBe(2);
});
});

View file

@ -230,6 +230,23 @@ describe('Incentive-Seite: Teilnahme-Block oben, Rangliste unten', function () {
}); });
describe('Teaser-Seite der Challenge', function () { describe('Teaser-Seite der Challenge', function () {
it('zeigt bei Wertung nach Umsatz der Neupartner Praemie, Top-Bonus und Umsatz-Hinweis statt Punktesystem', function () {
$incentive = vipOnlyChallenge([
'vip_only' => false, 'points_partner_onetime' => 0, 'include_sales_points' => true, 'include_abos' => false,
'bonus_rank_2' => 300, 'bonus_rank_3' => 200,
]);
$this->actingAs(vipTestUser());
$this->get(route('user_incentive_teaser', [$incentive->slug]))
->assertOk()
->assertSee('id="incentive-payout-tile"', false)
->assertSee('id="incentive-bonus-tile"', false)
->assertSee('id="incentive-how-it-works"', false)
->assertSee(__('incentive.payout_ranking_sales_hint'))
->assertDontSee(__('incentive.payout_ranking_hint'))
->assertDontSee(__('incentive.section_points'));
});
it('zeigt den Call to Action ganz oben, die Praemie je Teampartner und keine Galerie', function () { it('zeigt den Call to Action ganz oben, die Praemie je Teampartner und keine Galerie', function () {
$incentive = vipOnlyChallenge(['vip_only' => false, 'image' => 'challenge.jpg', 'bonus_rank_2' => 300, 'bonus_rank_3' => 200]); $incentive = vipOnlyChallenge(['vip_only' => false, 'image' => 'challenge.jpg', 'bonus_rank_2' => 300, 'bonus_rank_3' => 200]);
$this->actingAs(vipTestUser()); $this->actingAs(vipTestUser());

View file

@ -8,9 +8,10 @@ uses(RefreshDatabase::class);
/** /**
* E1: Der Seeder legt die Recruiting Challenge mit den abgestimmten Texten als Entwurf an * E1: Der Seeder legt die Recruiting Challenge mit den abgestimmten Texten als Entwurf an
* und ueberschreibt bei einem zweiten Lauf nur die Texte, nicht die Admin-Werte. * und ueberschreibt bei einem zweiten Lauf nur Texte und Wertung, nicht die Admin-Werte.
* Seit 08.10.2026 zaehlt die Rangliste den Umsatz der Neupartner, die 50 EUR je Partner bleiben.
*/ */
it('legt die Challenge als Entwurf mit Praemie und Wertung nach Neupartnern an', function () { it('legt die Challenge als Entwurf mit Praemie und Wertung nach Umsatz der Neupartner an', function () {
$this->seed(RecruitingChallenge2026Seeder::class); $this->seed(RecruitingChallenge2026Seeder::class);
$incentive = Incentive::where('slug', RecruitingChallenge2026Seeder::SLUG)->firstOrFail(); $incentive = Incentive::where('slug', RecruitingChallenge2026Seeder::SLUG)->firstOrFail();
@ -23,16 +24,21 @@ it('legt die Challenge als Entwurf mit Praemie und Wertung nach Neupartnern an',
->and((float) $incentive->amount_per_partner)->toBe(50.0) ->and((float) $incentive->amount_per_partner)->toBe(50.0)
->and($incentive->rankBonuses())->toBe([1 => 500.0, 2 => 300.0, 3 => 200.0]) ->and($incentive->rankBonuses())->toBe([1 => 500.0, 2 => 300.0, 3 => 200.0])
->and($incentive->max_winners)->toBe(3) ->and($incentive->max_winners)->toBe(3)
->and($incentive->ranksByPartnerCount())->toBeTrue() ->and($incentive->ranksByPartnerCount())->toBeFalse()
->and($incentive->ranksBySalesOfNewPartners())->toBeTrue()
->and($incentive->isCashChallenge())->toBeTrue()
->and($incentive->includesAbos())->toBeFalse()
->and($incentive->hasMinimumRequirements())->toBeFalse() ->and($incentive->hasMinimumRequirements())->toBeFalse()
->and($incentive->description)->toContain('50 €') ->and($incentive->description)->toContain('50 €')
->and($incentive->terms)->toContain('6. Gleichstand') ->and($incentive->terms)->toContain('6. Gleichstand')->toContain('5. Rangliste')->toContain('Umsatz der neuen Partner')
->and($incentive->terms)->toContain('Die Boni werden als Bruttobeiträge ausgewiesen und unterliegen der gesetzlichen Steuer- und Sozialversicherungspflicht.')
->and($incentive->description)->toContain('Steuerpflicht: Die Boni werden als Bruttobeiträge ausgewiesen')->toContain('31. Oktober')
->and($incentive->description.$incentive->subtitle.$incentive->terms)->not->toContain('–') ->and($incentive->description.$incentive->subtitle.$incentive->terms)->not->toContain('–')
->and($incentive->description.$incentive->subtitle.$incentive->terms)->not->toContain('—') ->and($incentive->description.$incentive->subtitle.$incentive->terms)->not->toContain('—')
->and($incentive->description.$incentive->terms)->toContain('9. Oktober')->not->toContain('1. Oktober'); ->and($incentive->description.$incentive->terms)->toContain('9. Oktober')->not->toMatch('/(?<!3)1\. Oktober/');
}); });
it('liefert Name, Untertitel, Beschreibung und Bedingungen auf EN, ES und FR', function (string $locale, string $date) { it('liefert Name, Untertitel, Beschreibung und Bedingungen auf EN, ES und FR', function (string $locale, string $date, string $tax) {
$this->seed(RecruitingChallenge2026Seeder::class); $this->seed(RecruitingChallenge2026Seeder::class);
$incentive = Incentive::where('slug', RecruitingChallenge2026Seeder::SLUG)->firstOrFail(); $incentive = Incentive::where('slug', RecruitingChallenge2026Seeder::SLUG)->firstOrFail();
@ -40,20 +46,22 @@ it('liefert Name, Untertitel, Beschreibung und Bedingungen auf EN, ES und FR', f
expect($incentive->getLang('subtitle'))->toContain('50')->not->toBe($incentive->subtitle) expect($incentive->getLang('subtitle'))->toContain('50')->not->toBe($incentive->subtitle)
->and($incentive->getLang('description'))->toContain($date)->not->toBe($incentive->description) ->and($incentive->getLang('description'))->toContain($date)->not->toBe($incentive->description)
->and($incentive->getLang('terms'))->toContain($date)->toContain('6.') ->and($incentive->getLang('terms'))->toContain($date)->toContain('6.')->toContain($tax)
->and($incentive->getLang('description'))->toContain($tax)
->and($incentive->getLang('name'))->toBe('Recruiting Challenge 2026/27'); ->and($incentive->getLang('name'))->toBe('Recruiting Challenge 2026/27');
})->with([ })->with([
'en' => ['en', '9 October'], 'en' => ['en', '9 October', 'gross amounts'],
'es' => ['es', '9 de octubre'], 'es' => ['es', '9 de octubre', 'importes brutos'],
'fr' => ['fr', '9 octobre'], 'fr' => ['fr', '9 octobre', 'montants bruts'],
]); ]);
it('aktualisiert beim zweiten Lauf Texte und Beginn und laesst Admin-Werte stehen', function () { it('aktualisiert beim zweiten Lauf Texte, Beginn und Wertung und laesst Admin-Werte stehen', function () {
$this->seed(RecruitingChallenge2026Seeder::class); $this->seed(RecruitingChallenge2026Seeder::class);
$incentive = Incentive::where('slug', RecruitingChallenge2026Seeder::SLUG)->firstOrFail(); $incentive = Incentive::where('slug', RecruitingChallenge2026Seeder::SLUG)->firstOrFail();
$incentive->update([ $incentive->update([
'status' => 1, 'image' => 'challenge.jpg', 'bonus_rank_1' => 999, 'description' => 'alt', 'status' => 1, 'image' => 'challenge.jpg', 'bonus_rank_1' => 999, 'description' => 'alt',
'qualification_start' => '2026-10-01', 'trans_description' => ['en' => null, 'es' => null, 'fr' => null], 'qualification_start' => '2026-10-01', 'trans_description' => ['en' => null, 'es' => null, 'fr' => null],
'points_partner_onetime' => 1, 'include_sales_points' => false,
]); ]);
$this->seed(RecruitingChallenge2026Seeder::class); $this->seed(RecruitingChallenge2026Seeder::class);
@ -65,5 +73,7 @@ it('aktualisiert beim zweiten Lauf Texte und Beginn und laesst Admin-Werte stehe
->and((float) $incentive->bonus_rank_1)->toBe(999.0) ->and((float) $incentive->bonus_rank_1)->toBe(999.0)
->and($incentive->description)->toContain('50 €') ->and($incentive->description)->toContain('50 €')
->and($incentive->qualification_start->toDateString())->toBe('2026-10-09') ->and($incentive->qualification_start->toDateString())->toBe('2026-10-09')
->and($incentive->points_partner_onetime)->toBe(0)
->and($incentive->includesSalesPoints())->toBeTrue()
->and($incentive->getTrans('description', 'en'))->toContain('9 October'); ->and($incentive->getTrans('description', 'en'))->toContain('9 October');
}); });