A01 — Abo-Regeln waren ueber das Aktiv-Feld umgehbar. Das Selbstbedienungsformular hat gar keinen Aktiv-Schalter, es spiegelt den Zustand nur in einem versteckten Feld zurueck; `updateStatus()` hat den Wert trotzdem uebernommen. Wer den Request manipulierte, konnte sein eigenes Abo dauerhaft deaktivieren und so die Mindestlaufzeit umgehen, am Pausenpfad mit seinen Sperren vorbei. Das Feld wirkt jetzt nur noch im Admin-Pfad. A16 — Statuswechsel wurden nur aus dem Formular protokolliert. Recovery-Zahlung, Retry, externe Erledigung und die DSGVO-Anonymisierung schreiben `active` direkt auf das Modell. Das ist heikel, weil die historische Bestandsrueckrechnung ein Abo verwirft, solange eine protokollierte Deaktivierung nicht durch eine spaetere protokollierte Reaktivierung aufgehoben ist — ein stiller `active = true` nimmt es dauerhaft aus allen Folgemonaten. Der Eintrag liegt deshalb jetzt am Model (`UserAbo::logStatusTransition()`) und nicht in den einzelnen Diensten: so kann ihn ein kuenftiger Schreibpfad nicht vergessen, und er entsteht in derselben Transaktion wie die Statusaenderung. Nebeneffekt: Die DSGVO-Anonymisierung setzt `active = false` ohne `cancel_date` — bisher fiel ein so abgeschaltetes Abo rueckwirkend aus allen vergangenen Monaten, jetzt bleibt die Historie korrekt. A13 — Ein heute faelliges Abo galt ab Mitternacht als erledigt, der Ausfuehrungsjob laeuft aber erst um 04:00. In diesem Fenster fehlten die Punkte in der Prognose UND im Ist. Der neue Scope `UserAbo::scopeOpenExecutionUntil()` zaehlt den heutigen Liefertag mit, solange keine Ausfuehrung angelegt ist — genau diese Bedingung verhindert die Doppelzaehlung. Alle drei Prognosen nutzen jetzt denselben Scope statt je einer eigenen Kopie der Datumsregel. A11 — Der Namens-Tiebreak der Top 3 lief nach dem Abschneiden auf 25 Kandidaten, bei Gleichstand entschied also die Reihenfolge der Abfrage. Die Auswahlgrenze wird jetzt um alle Gleichstaende an dieser Grenze erweitert, und Kandidaten ohne Account fallen vorher weg statt die Plaetze zu blockieren. Als letzte Regel entscheidet die user_id, damit eine gecachte Rangliste reproduzierbar bleibt. A14 — Sortiert wurde ueber den angezeigten Zellentext. Unter `en` liefert die Anwendung `Y-m-d` und `1,000.00`, damit ergab jedes Datum 0 und `1,000.00` wurde zur 1. Die Zellen tragen jetzt `data-sort-value` mit dem unformatierten Wert; ohne Attribut gilt weiter der Textweg. Dabei mitgenommen: Umlaute landeten hinter dem Z (jetzt localeCompare), leere Werte lagen als 0 zwischen den negativen Stornowerten, und `next_date` wurde doppelt formatiert. Ausserdem A08 (Prognose auch ohne erreichte Qualifikationsstufe), A09 (Summenzeile im Neupartner-CSV), A10 (Lieferungszahl vorgeladen), A17 (Faelligkeitsgruppen ohne Monatsueberlauf), A18 (Formelinhalte im CSV als Text) und A19 (fehlgeschlagene Provisionsberechnung ist als solche erkennbar statt 0,00 EUR). Audit-Befunde A01, A08, A09, A10, A11, A13, A14, A16, A17, A18, A19. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
109 lines
7.2 KiB
PHP
109 lines
7.2 KiB
PHP
<?php
|
||
|
||
return [
|
||
'' => '',
|
||
'MIVITA_Consultancy_agreement' => 'Contrat_conseiller_MIVITA',
|
||
'active_role' => 'Rôle actif',
|
||
'activities' => 'Activités',
|
||
'adjust_data' => 'Adapter les données',
|
||
'adviser_membership_active' => 'Adhésion conseiller active',
|
||
'adviser_onlineshop_active' => 'Boutique en ligne conseiller active',
|
||
'adviser_onlineshop_inactive' => 'Boutique conseiller inactive',
|
||
'advisor_account_inactive' => 'Compte conseiller inactif',
|
||
'at' => 'le',
|
||
'change_your_email_address' => 'Modifiez votre adresse e-mail.',
|
||
'change_your_personal_data' => 'Modifiez vos données personnelles.',
|
||
'change_your_personal_password' => 'Modifiez votre mot de passe personnel.',
|
||
'create_your_personal_password' => [
|
||
'' => 'Créez votre mot de passe personnel.',
|
||
],
|
||
'current_points_for' => 'Points actuels pour',
|
||
'data' => 'Données',
|
||
'data_complete_unlocked' => 'Données complètes, activées',
|
||
'declaration_of_consent' => 'Déclaration de consentement',
|
||
'email_verified' => 'E-mail vérifié',
|
||
'expired_on' => 'expiré le',
|
||
'log_out_and_see_you_soon' => 'Se déconnecter et à bientôt.',
|
||
'login' => 'Connexion',
|
||
'manage_membership' => 'Gérer l’adhésion',
|
||
'manage_membership_now_here' => 'Gérer l’adhésion ici maintenant',
|
||
'membership' => 'Adhésion',
|
||
'news_updates' => 'Actualités & mises à jour',
|
||
'news_archive' => 'Archive des actualités',
|
||
'news_archive_title' => 'Toutes les actualités & mises à jour',
|
||
'news_archive_current' => 'Actualités actuelles',
|
||
'news_archive_older' => 'Messages plus anciens',
|
||
'news_archive_empty' => 'Aucun message plus ancien disponible.',
|
||
'news_archive_link' => 'Voir toutes les actualités',
|
||
'news_back_to_dashboard' => 'Retour au tableau de bord',
|
||
'open_since' => 'Ouvert depuis',
|
||
'open_your_shop' => 'Ouvrez votre propre boutique mivita',
|
||
'read_less' => 'Afficher moins',
|
||
'read_more' => 'Lire la suite',
|
||
'privacy_policy_approved' => 'Politique de confidentialité acceptée',
|
||
'security' => 'Sécurité',
|
||
'settings_your_shop' => 'Paramètres de votre boutique',
|
||
'shop_not_booked' => 'Boutique non réservée',
|
||
'today_is' => 'Nous sommes le',
|
||
'until' => 'jusqu’au',
|
||
'welcome_back' => 'Bon retour',
|
||
'your_shop' => 'Votre boutique',
|
||
'commission_today' => 'Commission (à ce jour)',
|
||
'commission_unavailable' => 'Le calcul des commissions n\'est pas disponible actuellement. La valeur apparaitra des qu\'il fonctionnera de nouveau.',
|
||
'payline_forecast_title' => 'Prévision payline pour le 5 / 10 / 20 / 25',
|
||
'payline_forecast_basis' => 'Base : points payline + volume personnel',
|
||
'payline_forecast_hint' => 'Base : chiffre d’affaires clients actuel + chiffre d’affaires équipe (payline). S’y ajoutent, de manière cumulée, les points d’abonnement de ta payline encore à venir jusqu’à la date concernée (y compris tes propres abonnements et abonnements clients). Prévision : pauses, résiliations ou paiements échoués peuvent modifier la valeur.',
|
||
'forecast_day' => 'Prévision pour le :date',
|
||
'forecast_upcoming' => 'points d’abonnement à venir',
|
||
'forecast_done' => 'Date déjà incluse dans le chiffre réel',
|
||
'monthly_statistics' => 'Statistique mensuelle',
|
||
'customer_turnover_points' => 'Points chiffre d’affaires clients',
|
||
'team_turnover_points' => 'Points chiffre d’affaires équipe',
|
||
'direct_new_partners' => 'Nouveaux partenaires directs',
|
||
'team_new_partners' => 'Nouveaux partenaires dans l’équipe',
|
||
'customer_subscriptions' => 'Abonnements clients',
|
||
'team_subscriptions' => 'Abonnements équipe',
|
||
'team_customer_subscriptions' => 'Abonnements clients équipe',
|
||
'own_subscriptions' => 'Abonnements propres',
|
||
'own_customer_subscriptions' => 'Abonnements clients propres',
|
||
'stats_group_turnover' => 'Chiffre d\'affaires',
|
||
'stats_group_new_partners' => 'Nouveaux partenaires',
|
||
'stats_group_subscriptions' => 'Abonnements',
|
||
'own' => 'Propres',
|
||
'live_calculation_hint' => 'Calcul en direct (pas encore terminé)',
|
||
'live_calculation_hint_text' => 'Ne sera calculé qu’à la fin du mois.',
|
||
'stats_group_team' => 'Équipe',
|
||
'firstlines_count' => 'Firstlines',
|
||
'team_partner_total' => 'Partenaires au total',
|
||
'payline_partner_count' => 'Partenaires dans la payline',
|
||
'payline_abo_count' => 'Abonnements dans la payline',
|
||
'payline_career_fallback_hint' => 'Compté sur les niveaux de ton niveau de carrière : ta qualification pour ce mois n\'est pas encore établie. Dès qu\'elle le sera, la tuile comptera sur les niveaux du niveau de qualification.',
|
||
'level_current' => 'Qualification de ce mois',
|
||
'level_career' => 'Niveau de carrière',
|
||
'level_next_missing' => 'Pour te qualifier comme :level ce mois-ci, il te manque encore :points points de payline.',
|
||
'level_next_missing_personal' => 'Il manque en plus :points points de volume personnel.',
|
||
'level_not_qualified_yet' => 'Pas encore qualifié',
|
||
'level_next_missing_personal_only' => 'Pour te qualifier comme :level ce mois-ci, il te manque encore :points points de volume personnel.',
|
||
'level_top_reached' => 'Niveau le plus élevé atteint.',
|
||
'level_hint' => 'Niveau de qualification mensuel issu du calcul en direct. Points de payline = points d’équipe de tes niveaux payés, y compris ton excédent de points clients.',
|
||
'forecast_level_title' => 'Niveau et commission selon la prévision (au 25)',
|
||
'forecast_unverbindlich' => 'sans engagement',
|
||
'forecast_level_disclaimer' => 'Estimation basée sur les points actuels plus les livraisons d’abonnement encore ouvertes. Les changements de rang/structure dans l’équipe ne sont pas pris en compte - seule la clôture mensuelle fait foi.',
|
||
'forecast_level_needs_qualification' => 'La prévision de niveau et de commission apparaît dès que ta qualification pour ce mois est établie : les taux de commission dépendent du niveau de qualification.',
|
||
'forecast_level_reached' => 'Selon la prévision, tu atteindras le niveau suivant :level - à condition que ton volume personnel de :volume points soit atteint.',
|
||
'forecast_level_missing' => 'Selon la prévision, il manque encore :points points de payline pour le niveau suivant :level.',
|
||
'forecast_level_missing_personal' => 'Il manque en plus :points points de volume personnel.',
|
||
'forecast_commission' => 'Commission prévisionnelle selon la prévision : :amount (sur la base du niveau :level).',
|
||
'forecast_commission_no_level' => 'Commission prevue selon la prevision : :amount. La commission d\'equipe s\'ajoute des que le premier niveau de qualification est atteint.',
|
||
|
||
// N6 : « Les meilleurs résultats du mois » (interne à l'équipe)
|
||
'top_results_title' => 'Les meilleurs résultats du mois (équipe)',
|
||
'top_results_volume' => 'Top 3 volume personnel',
|
||
'top_results_recruiters' => 'Top 3 nouveaux partenaires',
|
||
'top_results_new_abos' => 'Top 3 nouveaux abonnements',
|
||
'top_results_self' => 'moi',
|
||
'top_results_empty' => 'Pas encore de résultats ce mois-ci.',
|
||
'top_results_unit_points' => 'points',
|
||
'top_results_unit_partners' => 'nouveaux partenaires',
|
||
'top_results_unit_abos' => 'abonnements',
|
||
];
|