mivita/resources/lang/en/home.php
Kevin 5a38f4ac3e Statistik: uebrige Audit-Korrekturen (Abo-Regeln, Prognose, Sortierung)
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>
2026-09-10 11:19:38 +00:00

109 lines
6.5 KiB
PHP

<?php
return [
'MIVITA_Consultancy_agreement' => 'MIVITA_Consultant contract',
'active_role' => 'active role',
'activities' => 'activities',
'adjust_data' => 'adjust data',
'adviser_membership_active' => 'consultant membership active',
'adviser_onlineshop_active' => 'consultant online shop active',
'adviser_onlineshop_inactive' => 'consultant shop inactive',
'advisor_account_inactive' => 'consultant account inactive',
'at' => 'at the',
'change_your_email_address' => 'Change your email address.',
'change_your_personal_data' => 'Change your personal information.',
'change_your_personal_password' => 'Change your personal password.',
'create_your_personal_password' => [
'' => 'Create your personal password.',
],
'current_points_for' => 'current points for',
'data' => 'data',
'data_complete_unlocked' => 'data complete, unlocked',
'declaration_of_consent' => 'consent form',
'email_verified' => 'verify email',
'expired_on' => 'expired on',
'log_out_and_see_you_soon' => 'Sign out and see you soon.',
'login' => 'registration',
'manage_membership' => 'manage membership',
'manage_membership_now_here' => 'manage your membership here now',
'membership' => 'membership',
'news_updates' => 'News & Updates',
'news_archive' => 'News Archive',
'news_archive_title' => 'All News & Updates',
'news_archive_current' => 'Current News',
'news_archive_older' => 'Older Posts',
'news_archive_empty' => 'No older posts available.',
'news_archive_link' => 'View all news',
'news_back_to_dashboard' => 'Back to Dashboard',
'open_since' => 'opened since',
'open_your_shop' => 'open your own mivita shop',
'read_less' => 'Show less',
'read_more' => 'Read more',
'privacy_policy_approved' => 'privacy policy agreed',
'security' => 'security',
'settings_your_shop' => 'your shop settings',
'shop_not_booked' => 'shop not booked',
'today_is' => 'today is',
'until' => 'until',
'welcome_back' => 'welcome back',
'your_shop' => 'your shop',
'commission_today' => 'Commission (as of today)',
'commission_unavailable' => 'The commission calculation is currently unavailable. The value will appear once it runs again.',
'payline_forecast_title' => 'Payline forecast for the 5th / 10th / 20th / 25th',
'payline_forecast_basis' => 'Basis: payline points + personal volume',
'payline_forecast_hint' => 'Basis: current customer turnover + team turnover (payline). Plus, cumulatively, the subscription points of your payline still due up to the respective date (incl. your own subscriptions and customer subscriptions). Forecast: pauses, cancellations or failed payments can change the value.',
'forecast_day' => 'Forecast for :date',
'forecast_upcoming' => 'subscription points due',
'forecast_done' => 'Date already included in actual turnover',
'monthly_statistics' => 'Monthly Statistics',
'customer_turnover_points' => 'Customer Turnover Points',
'team_turnover_points' => 'Team Turnover Points',
'direct_new_partners' => 'Direct New Partners',
'team_new_partners' => 'New Partners in Team',
'customer_subscriptions' => 'Customer Subscriptions',
'team_subscriptions' => 'Team Subscriptions',
'team_customer_subscriptions' => 'Team Customer Subscriptions',
'own_subscriptions' => 'Own Subscriptions',
'own_customer_subscriptions' => 'Own Customer Subscriptions',
'stats_group_turnover' => 'Turnover',
'stats_group_new_partners' => 'New Partners',
'stats_group_subscriptions' => 'Subscriptions',
'own' => 'Own',
'live_calculation_hint' => 'Live calculation (not yet finalized)',
'live_calculation_hint_text' => 'Will be calculated at the end of the month.',
'' => '',
'stats_group_team' => 'Team',
'firstlines_count' => 'Firstlines',
'team_partner_total' => 'Team partners total',
'payline_partner_count' => 'Team partners in the payline',
'payline_abo_count' => 'Subscriptions in the payline',
'payline_career_fallback_hint' => 'Counted across the levels of your career rank: your qualification for this month is still pending. Once it is set, the tile counts across the levels of the qualification rank.',
'level_current' => 'Qualification this month',
'level_career' => 'Career level',
'level_next_missing' => 'You still need :points payline points to qualify as :level this month.',
'level_next_missing_personal' => 'Additionally :points points of personal volume are missing.',
'level_not_qualified_yet' => 'Not yet qualified',
'level_next_missing_personal_only' => 'You still need :points points of personal volume to qualify as :level this month.',
'level_top_reached' => 'Highest level reached.',
'level_hint' => 'Monthly qualification level from the live run. Payline points = team points of your paid levels including your customer points surplus.',
'forecast_level_title' => 'Level & commission according to forecast (as of the 25th)',
'forecast_unverbindlich' => 'non-binding',
'forecast_level_disclaimer' => 'Estimate based on today\'s points plus the still open subscription deliveries. Rank/structure changes in the team are not taken into account - only the monthly closing is binding.',
'forecast_level_needs_qualification' => 'The level and commission forecast appears as soon as your qualification for this month is set — the commission rates depend on the qualification rank.',
'forecast_level_reached' => 'According to the forecast you will reach the next level :level - provided your personal volume of :volume points is reached.',
'forecast_level_missing' => 'According to the forecast, :points payline points are still missing for the next level :level.',
'forecast_level_missing_personal' => 'Additionally :points points of personal volume are missing.',
'forecast_commission' => 'Expected commission according to forecast: :amount (based on level :level).',
'forecast_commission_no_level' => 'Projected commission: :amount. Team commission is added once the first qualification level is reached.',
// N6: "Best results of the month" (team-internal)
'top_results_title' => 'Best results of the month (team)',
'top_results_volume' => 'Top 3 personal volume',
'top_results_recruiters' => 'Top 3 new partners',
'top_results_new_abos' => 'Top 3 new subscriptions',
'top_results_self' => 'me',
'top_results_empty' => 'No results yet this month.',
'top_results_unit_points' => 'points',
'top_results_unit_partners' => 'new partners',
'top_results_unit_abos' => 'subscriptions',
];