Statistiken/Abo: Kundenfeedback 2026-07-24 komplett umgesetzt + Steuern: DATEV-Fixes 08+09/2025 (Sammel-Commit Branch-WIP)
Feedback-Umsetzung (dev/2026-07-22/feedback-analyse-2026-07-24.md, alle 10 Punkte):
- VIP-Statistik: eigener Berater ('ich', Linie 0) in Neue-Kundenabos- und beiden Top-10-Listen; Top-10-Umsatz sortiert nach abgerechneten Ist-Punkten + Abo-Anzahl-Spalte; Fußnote nicht-payline-wirksame Punkte (SalesVolumePoints::nonPaylinePoints)
- Führungskräfte-Liste: beide Sichten 'direkt' (an nächster FK abgeschnitten, additiv) und 'gesamt' (komplette Downline), Gesamt-Spalte nach Kundenzählweise
- Team-Abos: je Ebene 'abgerechnet (Monat)' und 'bis zum 25. erwartet'; Payline-Karte mit Teamabo-/Kundenabo-Zählern
- Incentive-Live-Ranking: Qualifizierte zuerst nummeriert (fixt auch isWinner rank<=max_winners)
- Porto: Netto-/Brutto-Kennzeichnung (Berater netto, Endkunden inkl. MwSt., portal_view-Flag; auch CRM-/Shop-Warenkorb + Checkout), Yard::shipping_tax-Fix
- Struktur-Ansicht: Abo-Badges 'A' (eigenes Abo) und '(n)' (Kundenabos) je Teampartner, gebatcht
- Abo-Löschung: Softdelete setzt active=0 (UserAbo deleting-Hook) + Bereinigungs-Migration für gelöschte-aber-aktive Abos
- Doku: technische Analyse + Kundinnen-Feedback-Dokument unter dev/2026-07-22/
- Tests: IncentiveRankingTest, TeamStructureAboBadgesTest, YardShippingTaxTest (neu); BackofficeStatisticsListsTest, TeamAboOverviewTest, PaylineForecastServiceTest, AboAdminDeleteTest, AboOneTimeViewTest erweitert
Außerdem enthalten (Branch-WIP vor dem Feedback): DATEV-Abgleich-Fixes 08+09/2025, USt-ID-Live-Validierung sowie restliche unkommittete Stände (u. a. Abo-Pause-Sprachkeys).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
657d4bd5b7
commit
ac3bd6e8ea
136 changed files with 7610 additions and 2688 deletions
|
|
@ -43,6 +43,24 @@ return [
|
|||
'error_change_locked' => 'Änderungen sind nicht mehr möglich. Die nächste Ausführung ist in :days Tagen. Änderungen müssen mindestens :lock Tage vorher erfolgen.',
|
||||
'error_abo_interval_too_soon' => 'Der gewählte Liefertag liegt nur :days Tage entfernt. Bitte wähle einen Liefertag, der mindestens :lock Tage in der Zukunft liegt.',
|
||||
'error_cancel_locked' => 'Eine Kündigung ist nicht mehr möglich. Die nächste Ausführung ist in :days Tagen. Kündigungen müssen mindestens :lock Tage vorher erfolgen.',
|
||||
'abo_copy_pause' => 'Verschiebt die nächste Ausführung um einen Monat nach hinten. Maximal 1x alle :months Monate möglich.',
|
||||
'payline_abo_turnover' => 'Abo-Umsatz in der Payline',
|
||||
'payline_abo_turnover_hint' => 'Soll = Abo-Punkte pro Zyklus aller aktiven Abos deiner Payline (Berater- und Kundenabos). Ist = im laufenden Monat bereits abgerechnete Abo-Punkte der Payline.',
|
||||
'payline_target_label' => 'Soll (Punkte pro Zyklus)',
|
||||
'payline_actual_label' => 'Ist (im Monat abgerechnet)',
|
||||
'payline_hint' => 'Payline = :lines Ebenen · :members Berater',
|
||||
'payline_abo_counts' => ':team_abos Teamabos + :customer_abos Kundenabos in der Payline',
|
||||
'payline_none' => 'Noch keine Payline vorhanden (kein Provisionslevel erreicht).',
|
||||
'abo_points_per_cycle' => 'Punkte pro Lieferung (Bestand)',
|
||||
'abo_points_billed' => 'abgerechnet (:month)',
|
||||
'abo_points_expected' => 'bis zum :day. erwartet',
|
||||
'abo_points_expected_hint' => 'Bereits abgerechnete Abo-Punkte plus die Punkte aller Abos dieser Ebene, deren Lieferung bis zum :day. des Monats noch ansteht.',
|
||||
'pause_abo' => '1 Monat pausieren',
|
||||
'confirm_pause' => 'Möchtest du das Abo wirklich um einen Monat pausieren? Die nächste Lieferung verschiebt sich auf den Folgemonat.',
|
||||
'pause_success' => 'Dein Abo wurde um einen Monat pausiert. Die nächste Ausführung ist am :date.',
|
||||
'error_pause_interval' => 'Das Abo kann maximal 1x alle :months Monate pausiert werden. Die nächste Pause ist ab dem :date möglich.',
|
||||
'error_pause_not_active' => 'Nur aktive Abos können pausiert werden.',
|
||||
'info_pause_available_from' => 'Eine Pause ist maximal 1x alle :months Monate möglich — wieder ab dem :date.',
|
||||
'error_pause_locked' => 'Das Abo kann nicht mehr pausiert werden. Die nächste Ausführung ist in :days Tagen. Pausieren muss mindestens :lock Tage vorher erfolgen.',
|
||||
'error_next_date' => 'Das Datum für die nächste Ausführung nicht korrekt',
|
||||
'checkout_mail_abo_hl' => 'Dein Abo / regelmäßige Lieferung.',
|
||||
|
|
|
|||
|
|
@ -36,6 +36,12 @@ return [
|
|||
'desc_rollback' => 'Auf Ursprung zurückgesetzt',
|
||||
|
||||
// Channels
|
||||
'status_history_title' => 'Status-Änderungen (Pause & Kündigung)',
|
||||
'status_paused' => 'Pausiert',
|
||||
'status_cancelled' => 'Gekündigt',
|
||||
'status_deactivated' => 'Deaktiviert',
|
||||
'status_reactivated' => 'Reaktiviert',
|
||||
'status_shift' => 'Ausführung von :from auf :to verschoben',
|
||||
'channel_admin' => 'Admin',
|
||||
'channel_user_me' => 'Berater',
|
||||
'channel_user_ot' => 'Berater (Kunde)',
|
||||
|
|
|
|||
|
|
@ -48,6 +48,12 @@ return [
|
|||
'until' => 'bis zum',
|
||||
'welcome_back' => 'Willkommen zurück',
|
||||
'your_shop' => 'Dein Shop',
|
||||
'commission_today' => 'Provision (Stand heute)',
|
||||
'payline_forecast_title' => 'Payline-Prognose zum 5. / 10. / 20. / 25.',
|
||||
'payline_forecast_hint' => 'Basis: aktueller Kundenumsatz + Teamumsatz (Payline). Dazu kommen kumuliert die bis zum jeweiligen Termin noch anstehenden Abo-Punkte deiner Payline (inkl. deiner eigenen Abos und Kundenabos). Prognose: Pausen, Kündigungen oder fehlgeschlagene Zahlungen können den Wert verändern.',
|
||||
'forecast_day' => 'Prognose zum :date',
|
||||
'forecast_upcoming' => 'Abo-Punkte offen',
|
||||
'forecast_done' => 'Termin liegt bereits im Ist-Umsatz',
|
||||
'monthly_statistics' => 'Monatsstatistik',
|
||||
'customer_turnover_points' => 'Kunden-Umsatz Punkte',
|
||||
'team_turnover_points' => 'Team-Umsatz Punkte',
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ return [
|
|||
'homeparty_delete' => 'Auszeitparty gelöscht',
|
||||
'VATID_could_not_be_validated' => 'Die UST-ID konnte nicht validiert werden, Eingabe bitte prüfen',
|
||||
'VATID_successfully_entered' => 'UST-ID erfolgreich eingetragen',
|
||||
'VATID_german_not_allowed' => 'Deutsche USt-IDs können hier nicht verwendet werden. Das Reverse-Charge-Verfahren gilt nur für ausländische EU-USt-IDs.',
|
||||
'VATID_no_longer_valid_taxes_applied' => 'Deine USt-ID ist nicht mehr gültig. Die Bestellung wird daher mit Umsatzsteuer berechnet.',
|
||||
'reverse_charge_procedure_and_VATID_deleted' => 'Reverse Charge Verfahren und UST-ID gelöscht',
|
||||
'no_id_card_deposited_please_upload_first' => 'Kein Ausweis hinterlegt, bitte erst hochladen',
|
||||
'no_trade_licence_deposited_please_upload_first' => 'Kein Gewerbeschein hinterlegt, bitte erst hochladen',
|
||||
|
|
@ -38,6 +40,13 @@ return [
|
|||
'account_released' => 'Account freigeschaltet',
|
||||
'cart_product_not_allowed_for_order_type' => 'Der Warenkorb enthält Artikel, die für diese Bestellart nicht vorgesehen sind. Bitte leere den Warenkorb und wähle nur Produkte, die zu dieser Bestellung passen.',
|
||||
'cart_max_weight_reached' => 'Das maximale Versandgewicht ist erreicht. Es können keine weiteren Produkte hinzugefügt werden.',
|
||||
'gdpr_delete_success' => 'DSGVO-Löschung ausgeführt: Alle personenbezogenen Daten wurden unwiderruflich anonymisiert.',
|
||||
'gdpr_delete_customer_success' => 'DSGVO-Löschung ausgeführt: Alle personenbezogenen Daten des Kunden wurden unwiderruflich anonymisiert.',
|
||||
'gdpr_delete_customer_button' => 'Kunde DSGVO-löschen',
|
||||
'gdpr_confirm_checkbox_missing' => 'Bitte bestätige die DSGVO-Löschung über die Checkbox.',
|
||||
'gdpr_error_is_admin' => 'DSGVO-Löschung nicht möglich: Der Account hat Admin-Rechte. Bitte entziehe zuerst die Admin-Rechte.',
|
||||
'gdpr_error_active_abo' => 'DSGVO-Löschung nicht möglich: Es besteht noch ein aktives Abo. Bitte kündige das Abo zuerst.',
|
||||
'gdpr_error_customer_is_member' => 'DSGVO-Löschung nicht möglich: Dieser Kundendatensatz gehört zu einem Berater-Account. Bitte nutze die DSGVO-Löschung in der User-Verwaltung.',
|
||||
];
|
||||
/*
|
||||
{{ __('msg.') }}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ return [
|
|||
'gross' => 'brutto',
|
||||
'gross_price' => 'Preis brutto',
|
||||
'incentives' => 'Incentives',
|
||||
'incl_VAT' => 'inkl. MwSt.',
|
||||
'included_VAT' => 'Enthaltene MwSt',
|
||||
'invoice' => 'Rechnung',
|
||||
'invoice_address' => 'Rechnungsadresse',
|
||||
|
|
|
|||
|
|
@ -70,6 +70,10 @@ return [
|
|||
'in_progress_yellow' => 'In Arbeit (gelb)',
|
||||
'no_level_red' => 'Kein Level (rot)',
|
||||
|
||||
// Abo-Kennzeichen (Struktur-Ansicht)
|
||||
'badge_own_abo' => 'hat ein eigenes Abo',
|
||||
'badge_customer_abos' => '{1} 1 eigenes Kundenabo|[2,*] :count eigene Kundenabos',
|
||||
|
||||
// Performance & Badges
|
||||
'optimized' => 'OPTIMIERT',
|
||||
'standard_monitoring' => 'STANDARD + MONITORING',
|
||||
|
|
|
|||
|
|
@ -169,6 +169,24 @@ return [
|
|||
'error_change_locked' => 'Changes are no longer possible. The next execution is in :days days. Changes must be made at least :lock days in advance.',
|
||||
'error_abo_interval_too_soon' => 'The selected delivery day is only :days days away. Please choose a delivery day at least :lock days in the future.',
|
||||
'error_cancel_locked' => 'Cancellation is no longer possible. The next execution is in :days days. Cancellations must be made at least :lock days in advance.',
|
||||
'abo_copy_pause' => 'Moves the next execution back by one month. Possible at most once every :months months.',
|
||||
'payline_abo_turnover' => 'Subscription turnover in the payline',
|
||||
'payline_abo_turnover_hint' => 'Target = subscription points per cycle of all active subscriptions in your payline (consultant and customer subscriptions). Actual = subscription points of the payline already billed in the current month.',
|
||||
'payline_target_label' => 'Target (points per cycle)',
|
||||
'payline_actual_label' => 'Actual (billed this month)',
|
||||
'payline_hint' => 'Payline = :lines levels · :members consultants',
|
||||
'payline_abo_counts' => ':team_abos team subscriptions + :customer_abos customer subscriptions in the payline',
|
||||
'payline_none' => 'No payline yet (no commission level reached).',
|
||||
'abo_points_per_cycle' => 'Points per delivery (current stock)',
|
||||
'abo_points_billed' => 'billed (:month)',
|
||||
'abo_points_expected' => 'expected by day :day',
|
||||
'abo_points_expected_hint' => 'Subscription points already billed plus the points of all subscriptions on this level whose delivery is still due by day :day of the month.',
|
||||
'pause_abo' => 'Pause for 1 month',
|
||||
'confirm_pause' => 'Do you really want to pause the subscription for one month? The next delivery will move to the following month.',
|
||||
'pause_success' => 'Your subscription has been paused for one month. The next execution is on :date.',
|
||||
'error_pause_interval' => 'The subscription can be paused at most once every :months months. The next pause is possible from :date.',
|
||||
'error_pause_not_active' => 'Only active subscriptions can be paused.',
|
||||
'info_pause_available_from' => 'A pause is possible at most once every :months months — available again from :date.',
|
||||
'error_pause_locked' => 'The subscription can no longer be paused. The next execution is in :days days. Pausing must be done at least :lock days in advance.',
|
||||
'cancel_abo' => 'Cancel subscription',
|
||||
'confirm_cancel' => 'Do you really want to cancel the subscription?',
|
||||
|
|
|
|||
|
|
@ -36,6 +36,12 @@ return [
|
|||
'desc_rollback' => 'Reset to original',
|
||||
|
||||
// Channels
|
||||
'status_history_title' => 'Status changes (pause & cancellation)',
|
||||
'status_paused' => 'Paused',
|
||||
'status_cancelled' => 'Cancelled',
|
||||
'status_deactivated' => 'Deactivated',
|
||||
'status_reactivated' => 'Reactivated',
|
||||
'status_shift' => 'Execution moved from :from to :to',
|
||||
'channel_admin' => 'Admin',
|
||||
'channel_user_me' => 'Consultant',
|
||||
'channel_user_ot' => 'Consultant (Customer)',
|
||||
|
|
|
|||
|
|
@ -47,6 +47,12 @@ return [
|
|||
'until' => 'until',
|
||||
'welcome_back' => 'welcome back',
|
||||
'your_shop' => 'your shop',
|
||||
'commission_today' => 'Commission (as of today)',
|
||||
'payline_forecast_title' => 'Payline forecast for the 5th / 10th / 20th / 25th',
|
||||
'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',
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
return [
|
||||
'VATID_could_not_be_validated' => 'The VAT ID could not be validated, please check your entry',
|
||||
'VATID_successfully_entered' => 'VAT ID entered successfully',
|
||||
'VATID_german_not_allowed' => 'German VAT IDs cannot be used here. The reverse charge procedure only applies to foreign EU VAT IDs.',
|
||||
'VATID_no_longer_valid_taxes_applied' => 'Your VAT ID is no longer valid. VAT will therefore be applied to this order.',
|
||||
'abo_deaktivert' => 'subscription option disabled',
|
||||
'account_released' => 'Account activated',
|
||||
'booked_package_has_been_changed' => 'booked package has been changed.',
|
||||
|
|
@ -40,4 +42,11 @@ return [
|
|||
],
|
||||
'cart_product_not_allowed_for_order_type' => 'Your cart contains items that are not allowed for this order type. Please clear the cart and only add products that match this order.',
|
||||
'cart_max_weight_reached' => 'The maximum shipping weight has been reached. No further products can be added.',
|
||||
'gdpr_delete_success' => 'GDPR deletion executed: All personal data has been irreversibly anonymized.',
|
||||
'gdpr_delete_customer_success' => 'GDPR deletion executed: All personal data of the customer has been irreversibly anonymized.',
|
||||
'gdpr_delete_customer_button' => 'GDPR-delete customer',
|
||||
'gdpr_confirm_checkbox_missing' => 'Please confirm the GDPR deletion via the checkbox.',
|
||||
'gdpr_error_is_admin' => 'GDPR deletion not possible: The account has admin rights. Please remove the admin rights first.',
|
||||
'gdpr_error_active_abo' => 'GDPR deletion not possible: There is still an active subscription. Please cancel the subscription first.',
|
||||
'gdpr_error_customer_is_member' => 'GDPR deletion not possible: This customer record belongs to a consultant account. Please use the GDPR deletion in the user administration.',
|
||||
];
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ return [
|
|||
'gross' => 'gross',
|
||||
'gross_price' => 'gross price',
|
||||
'incentives' => 'incentives',
|
||||
'incl_VAT' => 'incl. VAT',
|
||||
'included_VAT' => 'VAT included',
|
||||
'invoice' => 'invoice',
|
||||
'invoice_address' => 'billing address',
|
||||
|
|
|
|||
|
|
@ -68,6 +68,10 @@ return [
|
|||
'in_progress_yellow' => 'In Progress (yellow)',
|
||||
'no_level_red' => 'No Level (red)',
|
||||
|
||||
// Abo badges (structure view)
|
||||
'badge_own_abo' => 'has an own subscription',
|
||||
'badge_customer_abos' => '{1} 1 own customer subscription|[2,*] :count own customer subscriptions',
|
||||
|
||||
// Performance & Badges
|
||||
'optimized' => 'OPTIMIZED',
|
||||
'standard_monitoring' => 'STANDARD + MONITORING',
|
||||
|
|
|
|||
|
|
@ -152,6 +152,24 @@ return [
|
|||
'error_change_locked' => 'Los cambios ya no son posibles. La próxima ejecución es en :days días. Los cambios deben realizarse al menos :lock días antes.',
|
||||
'error_abo_interval_too_soon' => 'El día de entrega seleccionado está a solo :days días. Elija un día de entrega con al menos :lock días de anticipación.',
|
||||
'error_cancel_locked' => 'La cancelación ya no es posible. La próxima ejecución es en :days días. Las cancelaciones deben realizarse al menos :lock días antes.',
|
||||
'abo_copy_pause' => 'Retrasa la próxima ejecución un mes. Posible como máximo 1 vez cada :months meses.',
|
||||
'payline_abo_turnover' => 'Volumen de suscripciones en la payline',
|
||||
'payline_abo_turnover_hint' => 'Objetivo = puntos de suscripción por ciclo de todas las suscripciones activas de tu payline (de asesores y clientes). Real = puntos de suscripción de la payline ya facturados en el mes en curso.',
|
||||
'payline_target_label' => 'Objetivo (puntos por ciclo)',
|
||||
'payline_actual_label' => 'Real (facturado este mes)',
|
||||
'payline_hint' => 'Payline = :lines niveles · :members asesores',
|
||||
'payline_abo_counts' => ':team_abos suscripciones de asesores + :customer_abos suscripciones de clientes en la payline',
|
||||
'payline_none' => 'Aún no hay payline (no se ha alcanzado ningún nivel de comisión).',
|
||||
'abo_points_per_cycle' => 'Puntos por entrega (cartera actual)',
|
||||
'abo_points_billed' => 'facturado (:month)',
|
||||
'abo_points_expected' => 'previsto hasta el día :day',
|
||||
'abo_points_expected_hint' => 'Puntos de suscripción ya facturados más los puntos de todas las suscripciones de este nivel cuya entrega aún está pendiente hasta el día :day del mes.',
|
||||
'pause_abo' => 'Pausar 1 mes',
|
||||
'confirm_pause' => '¿Realmente quieres pausar la suscripción un mes? La próxima entrega se trasladará al mes siguiente.',
|
||||
'pause_success' => 'Tu suscripción se ha pausado un mes. La próxima ejecución es el :date.',
|
||||
'error_pause_interval' => 'La suscripción puede pausarse como máximo 1 vez cada :months meses. La próxima pausa es posible a partir del :date.',
|
||||
'error_pause_not_active' => 'Solo se pueden pausar suscripciones activas.',
|
||||
'info_pause_available_from' => 'Una pausa es posible como máximo 1 vez cada :months meses — de nuevo a partir del :date.',
|
||||
'error_pause_locked' => 'La suscripción ya no puede pausarse. La próxima ejecución es en :days días. La pausa debe realizarse al menos :lock días antes.',
|
||||
'cancel_abo' => 'Cancelar suscripción',
|
||||
'confirm_cancel' => '¿Realmente desea cancelar la suscripción?',
|
||||
|
|
|
|||
|
|
@ -36,6 +36,12 @@ return [
|
|||
'desc_rollback' => 'Restablecido al original',
|
||||
|
||||
// Canales
|
||||
'status_history_title' => 'Cambios de estado (pausa y cancelación)',
|
||||
'status_paused' => 'Pausado',
|
||||
'status_cancelled' => 'Cancelado',
|
||||
'status_deactivated' => 'Desactivado',
|
||||
'status_reactivated' => 'Reactivado',
|
||||
'status_shift' => 'Ejecución trasladada del :from al :to',
|
||||
'channel_admin' => 'Admin',
|
||||
'channel_user_me' => 'Consultor',
|
||||
'channel_user_ot' => 'Consultor (Cliente)',
|
||||
|
|
|
|||
|
|
@ -47,6 +47,12 @@ return [
|
|||
'until' => 'hasta',
|
||||
'welcome_back' => 'bienvenido de nuevo',
|
||||
'your_shop' => 'tu tienda',
|
||||
'commission_today' => 'Comisión (a día de hoy)',
|
||||
'payline_forecast_title' => 'Pronóstico de payline para el 5 / 10 / 20 / 25',
|
||||
'payline_forecast_hint' => 'Base: volumen de clientes actual + volumen del equipo (payline). Más, de forma acumulada, los puntos de suscripción de tu payline pendientes hasta la fecha correspondiente (incl. tus propias suscripciones y las de tus clientes). Pronóstico: pausas, cancelaciones o pagos fallidos pueden cambiar el valor.',
|
||||
'forecast_day' => 'Pronóstico para el :date',
|
||||
'forecast_upcoming' => 'puntos de suscripción pendientes',
|
||||
'forecast_done' => 'Fecha ya incluida en el volumen real',
|
||||
'monthly_statistics' => 'Estadísticas mensuales',
|
||||
'customer_turnover_points' => 'Puntos de venta de clientes',
|
||||
'team_turnover_points' => 'Puntos de venta del equipo',
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
return [
|
||||
'VATID_could_not_be_validated' => 'No se pudo validar el ID de IVA, verifique su entrada',
|
||||
'VATID_successfully_entered' => 'ID de IVA ingresado exitosamente',
|
||||
'VATID_german_not_allowed' => 'Los ID de IVA alemanes no se pueden utilizar aquí. El procedimiento de inversión del sujeto pasivo solo se aplica a ID de IVA extranjeros de la UE.',
|
||||
'VATID_no_longer_valid_taxes_applied' => 'Tu ID de IVA ya no es válido. Por lo tanto, el pedido se calculará con IVA.',
|
||||
'abo_deaktivert' => 'opción de suscripción deshabilitada',
|
||||
'account_released' => 'Cuenta activada',
|
||||
'booked_package_has_been_changed' => 'El paquete reservado ha sido modificado.',
|
||||
|
|
@ -40,4 +42,11 @@ return [
|
|||
'' => 'Su carrito de compras está vacío, agregue productos primero',
|
||||
],
|
||||
'cart_product_not_allowed_for_order_type' => 'El carrito contiene artículos que no están previstos para este tipo de pedido. Vacía el carrito y elige solo productos que correspondan a este pedido.',
|
||||
'gdpr_delete_success' => 'Eliminación RGPD ejecutada: Todos los datos personales han sido anonimizados de forma irreversible.',
|
||||
'gdpr_delete_customer_success' => 'Eliminación RGPD ejecutada: Todos los datos personales del cliente han sido anonimizados de forma irreversible.',
|
||||
'gdpr_delete_customer_button' => 'Eliminar cliente (RGPD)',
|
||||
'gdpr_confirm_checkbox_missing' => 'Por favor confirma la eliminación RGPD mediante la casilla de verificación.',
|
||||
'gdpr_error_is_admin' => 'Eliminación RGPD no posible: La cuenta tiene derechos de administrador. Por favor retira primero los derechos de administrador.',
|
||||
'gdpr_error_active_abo' => 'Eliminación RGPD no posible: Todavía existe una suscripción activa. Por favor cancela primero la suscripción.',
|
||||
'gdpr_error_customer_is_member' => 'Eliminación RGPD no posible: Este registro de cliente pertenece a una cuenta de asesor. Por favor utiliza la eliminación RGPD en la administración de usuarios.',
|
||||
];
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ return [
|
|||
'gross' => 'bruto',
|
||||
'gross_price' => 'precio bruto',
|
||||
'incentives' => 'incentivos',
|
||||
'incl_VAT' => 'IVA incl.',
|
||||
'included_VAT' => 'VAT incluido',
|
||||
'invoice' => 'La factura',
|
||||
'invoice_address' => 'dirección de Envio',
|
||||
|
|
|
|||
|
|
@ -68,6 +68,10 @@ return [
|
|||
'in_progress_yellow' => 'En Progreso (amarillo)',
|
||||
'no_level_red' => 'Sin Nivel (rojo)',
|
||||
|
||||
// Distintivos de suscripción (vista de estructura)
|
||||
'badge_own_abo' => 'tiene una suscripción propia',
|
||||
'badge_customer_abos' => '{1} 1 suscripción propia de cliente|[2,*] :count suscripciones propias de clientes',
|
||||
|
||||
// Performance & Badges
|
||||
'optimized' => 'OPTIMIZADO',
|
||||
'standard_monitoring' => 'ESTÁNDAR + MONITOREO',
|
||||
|
|
|
|||
|
|
@ -43,6 +43,24 @@ return [
|
|||
'error_change_locked' => 'Les modifications ne sont plus possibles. La prochaine exécution est dans :days jours. Les modifications doivent être effectuées au moins :lock jours avant.',
|
||||
'error_abo_interval_too_soon' => 'Le jour de livraison choisi n’est qu’à :days jours. Veuillez choisir un jour de livraison situé au moins :lock jours dans le futur.',
|
||||
'error_cancel_locked' => 'Une résiliation n’est plus possible. La prochaine exécution est dans :days jours. Les résiliations doivent être effectuées au moins :lock jours avant.',
|
||||
'abo_copy_pause' => 'Reporte la prochaine exécution d’un mois. Possible au maximum 1 fois tous les :months mois.',
|
||||
'payline_abo_turnover' => 'Chiffre d’affaires des abonnements dans la payline',
|
||||
'payline_abo_turnover_hint' => 'Objectif = points d’abonnement par cycle de tous les abonnements actifs de ta payline (abonnements conseillers et clients). Réel = points d’abonnement de la payline déjà facturés au cours du mois.',
|
||||
'payline_target_label' => 'Objectif (points par cycle)',
|
||||
'payline_actual_label' => 'Réel (facturé ce mois-ci)',
|
||||
'payline_hint' => 'Payline = :lines niveaux · :members conseillers',
|
||||
'payline_abo_counts' => ':team_abos abonnements conseillers + :customer_abos abonnements clients dans la payline',
|
||||
'payline_none' => 'Pas encore de payline (aucun niveau de commission atteint).',
|
||||
'abo_points_per_cycle' => 'Points par livraison (portefeuille actuel)',
|
||||
'abo_points_billed' => 'facturé (:month)',
|
||||
'abo_points_expected' => 'prévu jusqu’au :day',
|
||||
'abo_points_expected_hint' => 'Points d’abonnement déjà facturés plus les points de tous les abonnements de ce niveau dont la livraison est encore à venir d’ici le :day du mois.',
|
||||
'pause_abo' => 'Suspendre 1 mois',
|
||||
'confirm_pause' => 'Veux-tu vraiment suspendre l’abonnement pendant un mois ? La prochaine livraison sera reportée au mois suivant.',
|
||||
'pause_success' => 'Ton abonnement a été suspendu pour un mois. La prochaine exécution aura lieu le :date.',
|
||||
'error_pause_interval' => 'L’abonnement ne peut être suspendu qu’une fois tous les :months mois. La prochaine pause est possible à partir du :date.',
|
||||
'error_pause_not_active' => 'Seuls les abonnements actifs peuvent être suspendus.',
|
||||
'info_pause_available_from' => 'Une pause est possible au maximum 1 fois tous les :months mois — de nouveau à partir du :date.',
|
||||
'error_pause_locked' => 'L’abonnement ne peut plus être mis en pause. La prochaine exécution est dans :days jours. La pause doit être effectuée au moins :lock jours avant.',
|
||||
'error_next_date' => 'La date de la prochaine exécution est incorrecte',
|
||||
'checkout_mail_abo_hl' => 'Votre abonnement / livraison régulière.',
|
||||
|
|
|
|||
|
|
@ -27,6 +27,12 @@ return [
|
|||
'desc_comp_added' => 'Ajouté par le système',
|
||||
'desc_comp_removed' => 'Supprimé par le système',
|
||||
'desc_rollback' => 'Réinitialisé à l’origine',
|
||||
'status_history_title' => 'Changements de statut (pause et résiliation)',
|
||||
'status_paused' => 'Suspendu',
|
||||
'status_cancelled' => 'Résilié',
|
||||
'status_deactivated' => 'Désactivé',
|
||||
'status_reactivated' => 'Réactivé',
|
||||
'status_shift' => 'Exécution reportée du :from au :to',
|
||||
'channel_admin' => 'Admin',
|
||||
'channel_user_me' => 'Conseiller',
|
||||
'channel_user_ot' => 'Conseiller (client)',
|
||||
|
|
|
|||
|
|
@ -48,6 +48,12 @@ return [
|
|||
'until' => 'jusqu’au',
|
||||
'welcome_back' => 'Bon retour',
|
||||
'your_shop' => 'Votre boutique',
|
||||
'commission_today' => 'Commission (à ce jour)',
|
||||
'payline_forecast_title' => 'Prévision payline pour le 5 / 10 / 20 / 25',
|
||||
'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',
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ return [
|
|||
'homeparty_delete' => 'Auszeitparty supprimée',
|
||||
'VATID_could_not_be_validated' => 'Le numéro de TVA n’a pas pu être validé, veuillez vérifier la saisie',
|
||||
'VATID_successfully_entered' => 'Numéro de TVA saisi avec succès',
|
||||
'VATID_german_not_allowed' => 'Les numéros de TVA allemands ne peuvent pas être utilisés ici. L’autoliquidation ne s’applique qu’aux numéros de TVA étrangers de l’UE.',
|
||||
'VATID_no_longer_valid_taxes_applied' => 'Ton numéro de TVA n’est plus valide. La TVA sera donc appliquée à cette commande.',
|
||||
'reverse_charge_procedure_and_VATID_deleted' => 'Procédure d’autoliquidation et numéro de TVA supprimés',
|
||||
'no_id_card_deposited_please_upload_first' => 'Aucune pièce d’identité déposée, veuillez d’abord la téléverser',
|
||||
'no_trade_licence_deposited_please_upload_first' => 'Aucun extrait d’activité déposé, veuillez d’abord le téléverser',
|
||||
|
|
@ -38,4 +40,11 @@ return [
|
|||
'account_released' => 'Compte activé',
|
||||
'cart_product_not_allowed_for_order_type' => 'Le panier contient des articles qui ne sont pas prévus pour ce type de commande. Veuillez vider le panier et sélectionner uniquement les produits adaptés à cette commande.',
|
||||
'cart_max_weight_reached' => "Le poids d'expédition maximal est atteint. Aucun autre produit ne peut être ajouté.",
|
||||
'gdpr_delete_success' => 'Suppression RGPD exécutée : Toutes les données personnelles ont été anonymisées de manière irréversible.',
|
||||
'gdpr_delete_customer_success' => 'Suppression RGPD exécutée : Toutes les données personnelles du client ont été anonymisées de manière irréversible.',
|
||||
'gdpr_delete_customer_button' => 'Supprimer le client (RGPD)',
|
||||
'gdpr_confirm_checkbox_missing' => 'Veuillez confirmer la suppression RGPD via la case à cocher.',
|
||||
'gdpr_error_is_admin' => "Suppression RGPD impossible : Le compte dispose de droits d'administrateur. Veuillez d'abord retirer les droits d'administrateur.",
|
||||
'gdpr_error_active_abo' => "Suppression RGPD impossible : Un abonnement actif existe encore. Veuillez d'abord résilier l'abonnement.",
|
||||
'gdpr_error_customer_is_member' => "Suppression RGPD impossible : Cette fiche client appartient à un compte de conseiller. Veuillez utiliser la suppression RGPD dans l'administration des utilisateurs.",
|
||||
];
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ return [
|
|||
'gross' => 'brut',
|
||||
'gross_price' => 'Prix brut',
|
||||
'incentives' => 'Incentives',
|
||||
'incl_VAT' => 'TVA incl.',
|
||||
'included_VAT' => 'TVA incluse',
|
||||
'invoice' => 'Facture',
|
||||
'invoice_address' => 'Adresse de facturation',
|
||||
|
|
|
|||
|
|
@ -67,6 +67,8 @@ return [
|
|||
'qualified_green' => 'Qualifié (vert)',
|
||||
'in_progress_yellow' => 'En cours (jaune)',
|
||||
'no_level_red' => 'Aucun niveau (rouge)',
|
||||
'badge_own_abo' => 'a son propre abonnement',
|
||||
'badge_customer_abos' => '{1} 1 abonnement client propre|[2,*] :count abonnements clients propres',
|
||||
'optimized' => 'OPTIMISÉ',
|
||||
'standard_monitoring' => 'STANDARD + MONITORING',
|
||||
'fallback' => 'FALLBACK',
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
@php
|
||||
$changeHistory = $user_abo->getChangeHistory();
|
||||
$statusHistory = $user_abo->status_histories()->with('actor.account')->orderByDesc('created_at')->orderByDesc('id')->get();
|
||||
$priceLabel = $user_abo->is_for === 'me' ? __('abo_history.price_net') : __('abo_history.price_gross');
|
||||
@endphp
|
||||
|
||||
|
|
@ -20,6 +21,34 @@
|
|||
@endif
|
||||
</div>
|
||||
|
||||
@if($statusHistory->isNotEmpty())
|
||||
<h6 class="font-weight-semibold text-muted mb-2">{{ __('abo_history.status_history_title') }}</h6>
|
||||
<div class="table-responsive mb-4">
|
||||
<table class="table table-sm table-striped mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ __('abo_history.col_date') }}</th>
|
||||
<th>{{ __('abo_history.col_action') }}</th>
|
||||
<th>{{ __('abo_history.col_details') }}</th>
|
||||
<th>{{ __('abo_history.col_changed_by') }}</th>
|
||||
<th>{{ __('abo_history.col_channel') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($statusHistory as $statusEntry)
|
||||
<tr>
|
||||
<td class="text-nowrap small">{{ $statusEntry->getFormattedDate() }}</td>
|
||||
<td>{!! $statusEntry->getActionBadge() !!}</td>
|
||||
<td class="small">{{ $statusEntry->getDescription() }}</td>
|
||||
<td class="small">{{ $statusEntry->getActorName() }}</td>
|
||||
<td>{!! $statusEntry->getChannelBadge() !!}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if($changeHistory->isEmpty())
|
||||
<p class="text-muted mb-0">
|
||||
<i class="fas fa-info-circle"></i> {{ __('abo_history.no_changes') }}
|
||||
|
|
|
|||
|
|
@ -112,11 +112,11 @@
|
|||
|
||||
<div class="col-md-3 mb-3">
|
||||
{!! $user_abo->getIsForFormated() !!}
|
||||
@if ($user_abo->is_for === 'me')
|
||||
@if ($user_abo->is_for === 'me' && Route::has('user_edit'))
|
||||
<a class="btn btn-xs btn-secondary" href="{{ route('user_edit') }}"><i class="fa fa-edit"></i></a>
|
||||
@endif
|
||||
|
||||
@if ($user_abo->is_for === 'ot')
|
||||
@if ($user_abo->is_for === 'ot' && $user_abo->shopping_user && Route::has('user_customer_edit'))
|
||||
<a class="btn btn-xs btn-secondary"
|
||||
href="{{ route('user_customer_edit', $user_abo->shopping_user->id) }}"><i
|
||||
class="fa fa-edit"></i></a>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
@php($cartInstance = \App\Services\AboOrderCart::INSTANCE)
|
||||
@php($change_locked = isset($change_locked) ? $change_locked : false)
|
||||
{{-- Kunden-Portal: Versand brutto ("inkl. MwSt."), Berater/Admin: netto ("netto") --}}
|
||||
@php($portal_view = $portal_view ?? false)
|
||||
@if(isset($error_message) && $error_message)
|
||||
<div class="alert alert-danger mt-2" id="insert_show_error_message">{{ $error_message }}</div>
|
||||
@endif
|
||||
|
|
@ -88,9 +90,10 @@
|
|||
<td colspan="3" class="text-right small no-border-top"><strong>{{ __('Delivery country') }}:</strong></td>
|
||||
<td class="text-right small no-border-top">{{ Yard::instance($cartInstance)->getShippingCountryName() }}</td>
|
||||
</tr>
|
||||
@php($shippingGross = $portal_view && ! $taxFree)
|
||||
<tr>
|
||||
<td colspan="3" class="text-right small no-border-top"><strong>{{ __('order.shipping_costs') }}:</strong></td>
|
||||
<td class="text-right small no-border-top">{{ $taxFree ? Yard::instance($cartInstance)->shippingNet() : Yard::instance($cartInstance)->shipping() }} € </td>
|
||||
<td colspan="3" class="text-right small no-border-top"><strong>{{ __('order.shipping_costs') }} ({{ $shippingGross ? __('order.incl_VAT') : __('order.net') }}):</strong></td>
|
||||
<td class="text-right small no-border-top">{{ $shippingGross ? Yard::instance($cartInstance)->shipping() : Yard::instance($cartInstance)->shippingNet() }} € </td>
|
||||
</tr>
|
||||
@if($taxFree)
|
||||
<tr>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
@php
|
||||
$cartInstance = \App\Services\AboOrderCart::INSTANCE;
|
||||
$taxFree = Yard::instance($cartInstance)->getUserTaxFree();
|
||||
// Kunden-Portal: Versand brutto ("inkl. MwSt."), Berater/Admin: netto ("netto")
|
||||
$portal_view = $portal_view ?? false;
|
||||
$shippingGross = $portal_view && ! $taxFree;
|
||||
@endphp
|
||||
<div class="card-header bg-primary">
|
||||
<h5 class="font-weight-semibold mb-0 text-white"> <i class="fa fa-shopping-cart text-white"></i>
|
||||
|
|
@ -26,9 +29,10 @@
|
|||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="small no-border-top"><strong>{{ __('order.shipping_costs') }}:</strong></td>
|
||||
<td class="small no-border-top"><strong>{{ __('order.shipping_costs') }}
|
||||
({{ $shippingGross ? __('order.incl_VAT') : __('order.net') }}):</strong></td>
|
||||
<td class="text-right small no-border-top">
|
||||
{{ $taxFree ? Yard::instance($cartInstance)->shippingNet() : Yard::instance($cartInstance)->shipping() }}
|
||||
{{ $shippingGross ? Yard::instance($cartInstance)->shipping() : Yard::instance($cartInstance)->shippingNet() }}
|
||||
€</td>
|
||||
</tr>
|
||||
@if ($taxFree)
|
||||
|
|
|
|||
|
|
@ -90,8 +90,7 @@
|
|||
$canCancel = App\Services\AboHelper::canCancelAbo($user_abo, $data['view']);
|
||||
@endphp
|
||||
<hr>
|
||||
@if($canCancel || $data['view'] == 'admin')
|
||||
|
||||
@if($data['view'] === 'admin')
|
||||
<div class="form-row">
|
||||
<div class="col-sm-12">
|
||||
<label class="switcher switcher-primary">
|
||||
|
|
@ -106,23 +105,49 @@
|
|||
<div class="col-sm-12 mt-1">
|
||||
<i class="text-muted">{{ __('abo.abo_copy_active') }}</i>
|
||||
</div>
|
||||
|
||||
@if($data['view'] !== 'admin')
|
||||
<div class="col-sm-12 mt-3">
|
||||
<button type="submit" name="abo_cancel" value="true" class="btn btn-danger btn-sm" onclick="return confirm('{{ __('abo.confirm_cancel') }}')">
|
||||
<i class="ion ion-ios-trash"></i> {{ __('abo.cancel_abo') }}
|
||||
</button>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@else
|
||||
<input type="hidden" name="abo_is_active" value="{{ $user_abo->active }}">
|
||||
<div class="mt-1">
|
||||
<div class="alert alert-warning">
|
||||
{{ __('abo.info_min_duration_orders_left', ['count' => App\Services\AboHelper::getAboMinDuration() - $user_abo->getCountPaidOrders()]) }}
|
||||
@elseif($canCancel)
|
||||
{{-- Selfservice: kein Aktiv-Schalter mehr (die Pause übernimmt diese Rolle),
|
||||
aktueller Zustand wird unverändert mitgesendet. --}}
|
||||
<input type="hidden" name="abo_is_active" value="{{ $user_abo->active }}">
|
||||
|
||||
@php
|
||||
$canPause = App\Services\AboHelper::canPauseAbo($user_abo, $data['view']);
|
||||
$nextPossiblePause = App\Services\AboHelper::nextPossiblePauseDate($user_abo);
|
||||
@endphp
|
||||
@if($canPause || ($user_abo->active && $nextPossiblePause))
|
||||
<div class="form-row">
|
||||
<div class="col-sm-12">
|
||||
@if($canPause)
|
||||
<button type="submit" name="abo_pause" value="true" class="btn btn-outline-primary btn-sm" onclick="return confirm('{{ __('abo.confirm_pause') }}')">
|
||||
<i class="ion ion-md-pause"></i> {{ __('abo.pause_abo') }}
|
||||
</button>
|
||||
<div class="mt-1">
|
||||
<i class="text-muted">{{ __('abo.abo_copy_pause', ['months' => App\Services\AboHelper::getPauseIntervalMonths()]) }}</i>
|
||||
</div>
|
||||
@else
|
||||
<i class="text-muted">{{ __('abo.info_pause_available_from', ['date' => $nextPossiblePause->format(Util::formatDateDB()), 'months' => App\Services\AboHelper::getPauseIntervalMonths()]) }}</i>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
@endif
|
||||
|
||||
<div class="form-row">
|
||||
<div class="col-sm-12">
|
||||
<button type="submit" name="abo_cancel" value="true" class="btn btn-outline-danger btn-sm" onclick="return confirm('{{ __('abo.confirm_cancel') }}')">
|
||||
<i class="ion ion-ios-trash"></i> {{ __('abo.cancel_abo') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
<input type="hidden" name="abo_is_active" value="{{ $user_abo->active }}">
|
||||
<div class="mt-1">
|
||||
<div class="alert alert-warning">
|
||||
{{ __('abo.info_min_duration_orders_left', ['count' => App\Services\AboHelper::getAboMinDuration() - $user_abo->getCountPaidOrders()]) }}
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -9,4 +9,40 @@
|
|||
@include('admin.customer._detail')
|
||||
<a href="{{route('admin_customers')}}" class="btn btn-sm btn-default mt-2 float-right">{{ __('back') }}</a>
|
||||
|
||||
@if (Auth::user()->isSuperAdmin() && !$shopping_user->auth_user_id)
|
||||
<button type="button" class="btn btn-sm btn-danger mt-2" data-toggle="modal"
|
||||
data-target="#modals-customer-gdpr-delete">{{ __('msg.gdpr_delete_customer_button') }}</button>
|
||||
|
||||
<!-- Modal DSGVO-Löschung -->
|
||||
<div class="modal fade" id="modals-customer-gdpr-delete">
|
||||
<div class="modal-dialog">
|
||||
<form class="modal-content" action="{{ route('admin_customer_gdpr_delete', [$shopping_user->id]) }}"
|
||||
method="post">
|
||||
@csrf
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">{{ __('msg.gdpr_delete_customer_button') }}</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Alle personenbezogenen Daten dieses Kunden werden <b>unwiderruflich anonymisiert</b>
|
||||
(alle Einträge mit der Kundennummer {{ $shopping_user->number }}).
|
||||
Bei Bestellungen mit Rechnung bleiben Name und Rechnungsadresse wegen der
|
||||
gesetzlichen Aufbewahrungspflichten erhalten; alle Kontaktdaten
|
||||
(E-Mail, Telefon, Notizen, Newsletter) werden entfernt.
|
||||
Aktive Abos müssen vorher gekündigt werden.</p>
|
||||
<label class="custom-control custom-checkbox m-0">
|
||||
<input type="checkbox" class="custom-control-input" name="gdpr_delete_customer" value="1">
|
||||
<span class="custom-control-label">DSGVO-Löschung unwiderruflich ausführen?</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">{{ __('close') }}</button>
|
||||
<button type="submit"
|
||||
class="btn btn-danger">{{ __('msg.gdpr_delete_customer_button') }}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@endsection
|
||||
|
|
@ -50,15 +50,15 @@
|
|||
--}}
|
||||
<tr class="unselectable">
|
||||
<td>Bankinhaber</td>
|
||||
<td><div class="selectall">{{ $UserCredit->user->account->bank_owner }}</div></td>
|
||||
<td><div class="selectall">{{ $UserCredit->user?->account?->bank_owner }}</div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>IBAN:</td>
|
||||
<td><div class="selectall">{{ $UserCredit->user->account->bank_iban }}</div></td>
|
||||
<td><div class="selectall">{{ $UserCredit->user?->account?->bank_iban }}</div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>BIC:</td>
|
||||
<td><div class="selectall">{{ $UserCredit->user->account->bank_bic }}</div></td>
|
||||
<td><div class="selectall">{{ $UserCredit->user?->account?->bank_bic }}</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
|
|||
|
|
@ -124,6 +124,14 @@
|
|||
<small class="form-text text-muted">Anzahl Tage vor der Ausführung, ab der das Abo nicht mehr pausiert oder gekündigt werden kann (Standard: 3).</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-sm-6">
|
||||
<label class="form-label">Pause-Intervall (Monate)*</label>
|
||||
{{ Form::text('settings[abo-pause-interval-months][val]', \App\Models\Setting::getContentBySlug('abo-pause-interval-months'), array('class'=>'form-control')) }}
|
||||
{{ Form::hidden('settings[abo-pause-interval-months][type]', 'int') }}
|
||||
<small class="form-text text-muted">Maximal eine Pause pro X Monate (rollierend ab der letzten Pause, Standard: 6).</small>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" name="action" value="save_prepayment" class="btn btn-primary btn-sm mb-2"><i class="ion ion-ios-save"></i> speichern</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -359,6 +359,19 @@
|
|||
<span class="custom-control-label">User komplett ohne Wiederherstellung löschen?</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<hr>
|
||||
<h5 class="text-danger">DSGVO-Löschung (Art. 17 DSGVO)</h5>
|
||||
<p>Alle personenbezogenen Daten dieses Users werden <b>unwiderruflich anonymisiert</b>
|
||||
(Stammdaten, Adressen, Bankdaten, Uploads, Zahlungs-Tokens, Kontaktdaten).
|
||||
Die Downline wird auf den nächsten aktiven Sponsor übertragen.
|
||||
Rechnungen, Gutschriften und Provisionsdaten bleiben wegen der gesetzlichen
|
||||
Aufbewahrungspflichten erhalten. Aktive Abos müssen vorher gekündigt werden.</p>
|
||||
<label class="custom-control custom-checkbox m-0">
|
||||
<input type="checkbox" class="custom-control-input" name="gdpr_delete_user">
|
||||
<span class="custom-control-label">DSGVO-Löschung unwiderruflich ausführen?</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">{{ __('close') }}</button>
|
||||
|
|
|
|||
|
|
@ -13,12 +13,17 @@
|
|||
? route('user_backoffice_statistics_details', ['line' => 0, 'metric' => 'new_partners', 'month' => $m, 'year' => $y])
|
||||
: null;
|
||||
|
||||
// "+N"-Badge der Team-Abo-Kacheln: VIP-Drilldown gefiltert auf neue Abos im Monat.
|
||||
$newAbosLink = fn (string $metric) => $isVip
|
||||
? route('user_backoffice_statistics_details', ['line' => 0, 'metric' => $metric, 'month' => $m, 'year' => $y, 'only_new' => 1])
|
||||
: null;
|
||||
|
||||
$fmt = fn ($value) => number_format((float) $value, 0, ',', '.');
|
||||
|
||||
$clusters = [
|
||||
[
|
||||
'title' => __('home.stats_group_turnover'),
|
||||
'col' => 'col-md-6 col-lg-4',
|
||||
'col' => 'col-md-6 col-lg-3',
|
||||
'tiles' => [
|
||||
[
|
||||
'label' => __('home.customer_turnover_points'), 'value' => $fmt($s['customer_points']),
|
||||
|
|
@ -32,6 +37,12 @@
|
|||
'label' => __('abo.shop_1000'), 'value' => $fmt($s['shop_1000']),
|
||||
'icon' => 'ion-md-trophy', 'color' => 'success', 'link' => $shop1000Link, 'new' => null, 'live' => false,
|
||||
],
|
||||
[
|
||||
'label' => __('home.commission_today'),
|
||||
'value' => number_format((float) ($s['commission']['total'] ?? 0), 2, ',', '.') . ' €',
|
||||
'icon' => 'ion-md-cash', 'color' => 'warning', 'link' => null, 'new' => null,
|
||||
'live' => (bool) ($s['commission']['is_live'] ?? false),
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
|
|
@ -62,11 +73,11 @@
|
|||
],
|
||||
[
|
||||
'label' => __('home.team_subscriptions'), 'value' => $fmt($s['team_partner_abos']),
|
||||
'icon' => 'ion-md-sync', 'color' => 'dark', 'link' => $teamShow, 'new' => $s['team_partner_abos_new'], 'live' => false,
|
||||
'icon' => 'ion-md-sync', 'color' => 'dark', 'link' => $teamShow, 'new' => $s['team_partner_abos_new'], 'new_link' => $newAbosLink('team_partner_abos'), 'live' => false,
|
||||
],
|
||||
[
|
||||
'label' => __('home.team_customer_subscriptions'), 'value' => $fmt($s['team_customer_abos']),
|
||||
'icon' => 'ion-md-git-network', 'color' => 'dark', 'link' => $teamShow, 'new' => $s['team_customer_abos_new'], 'live' => false,
|
||||
'icon' => 'ion-md-git-network', 'color' => 'dark', 'link' => $teamShow, 'new' => $s['team_customer_abos_new'], 'new_link' => $newAbosLink('team_customer_abos'), 'live' => false,
|
||||
],
|
||||
],
|
||||
],
|
||||
|
|
@ -129,8 +140,14 @@
|
|||
<div class="font-weight-bold text-large">
|
||||
{{ $tile['value'] }}
|
||||
@if (! empty($tile['new']) && $tile['new'] > 0)
|
||||
<span class="badge badge-pill badge-success ml-1"
|
||||
title="{{ __('abo.new_this_month') }}">+{{ $tile['new'] }}</span>
|
||||
@if (! empty($tile['new_link']))
|
||||
<span class="badge badge-pill badge-success ml-1 dashboard-stat-new-badge"
|
||||
data-href="{{ $tile['new_link'] }}" role="link" tabindex="0"
|
||||
title="{{ __('abo.new_this_month') }}">+{{ $tile['new'] }}</span>
|
||||
@else
|
||||
<span class="badge badge-pill badge-success ml-1"
|
||||
title="{{ __('abo.new_this_month') }}">+{{ $tile['new'] }}</span>
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -143,6 +160,37 @@
|
|||
@endforeach
|
||||
</div>
|
||||
@endforeach
|
||||
|
||||
@if (! empty($s['payline_forecast']['days']))
|
||||
<h6 class="text-muted text-uppercase font-weight-bold small mb-3 mt-2 pt-3 border-top">
|
||||
{{ __('home.payline_forecast_title') }}
|
||||
<span class="badge badge-pill badge-info ml-1"
|
||||
title="{{ __('home.payline_forecast_hint') }}">Live</span>
|
||||
</h6>
|
||||
<div class="row">
|
||||
@foreach ($s['payline_forecast']['days'] as $forecastDay)
|
||||
<div class="col-sm-6 col-lg-3 mb-3">
|
||||
<div class="card h-100 {{ $forecastDay['is_past'] ? 'bg-light' : '' }}">
|
||||
<div class="card-body py-3 text-center">
|
||||
<div class="text-muted small">
|
||||
{{ __('home.forecast_day', ['date' => $forecastDay['date']]) }}
|
||||
</div>
|
||||
<div class="font-weight-bold text-large">{{ $fmt($forecastDay['total']) }}</div>
|
||||
@if ($forecastDay['upcoming'] > 0)
|
||||
<div class="small text-success">
|
||||
+{{ $fmt($forecastDay['upcoming']) }} {{ __('home.forecast_upcoming') }}
|
||||
</div>
|
||||
@else
|
||||
<div class="small text-muted">
|
||||
{{ $forecastDay['is_past'] ? __('home.forecast_done') : '—' }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -175,6 +223,14 @@
|
|||
$('#stats-month-filter, #stats-year-filter').on('change', function() {
|
||||
updateStatsFilter();
|
||||
});
|
||||
|
||||
// Das "+N"-Badge liegt innerhalb des Kachel-Links: eigenen Ziel-Link
|
||||
// öffnen statt der Kachel-Navigation (kein verschachteltes <a> möglich).
|
||||
$('.dashboard-stat-new-badge').css('cursor', 'pointer').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
window.location.href = $(this).data('href');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endif
|
||||
|
|
|
|||
|
|
@ -152,10 +152,13 @@
|
|||
{{ Yard::instance('subscription')->getShippingCountryName() }}
|
||||
</td>
|
||||
</tr>
|
||||
@php($checkTaxFree = Yard::instance('subscription')->getUserTaxFree())
|
||||
<tr>
|
||||
<td>{{ __('order.shipping_costs') }}:</td>
|
||||
<td>{{ __('order.shipping_costs') }}
|
||||
({{ $checkTaxFree ? __('order.net') : __('order.incl_VAT') }}):</td>
|
||||
<td class="text-right">
|
||||
{{ Yard::instance('subscription')->shipping() }} €
|
||||
{{ $checkTaxFree ? Yard::instance('subscription')->shippingNet() : Yard::instance('subscription')->shipping() }}
|
||||
€
|
||||
</td>
|
||||
</tr>
|
||||
@if (Yard::instance('subscription')->getUserTaxFree())
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@
|
|||
'split_mode' => true,
|
||||
'summary' => $summary,
|
||||
'change_locked' => $aboChangeLocked,
|
||||
'portal_view' => true,
|
||||
])
|
||||
</div>
|
||||
<div id="holder_html_view_comp_product">
|
||||
|
|
@ -106,7 +107,7 @@
|
|||
</div>
|
||||
<div class="col-lg-4" id="combined_summary_col">
|
||||
<div class="card js-abo-sticky" id="combined_summary_card">
|
||||
@include('admin.abo._order_combined_summary', ['summary' => $summary])
|
||||
@include('admin.abo._order_combined_summary', ['summary' => $summary, 'portal_view' => true])
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -115,6 +116,7 @@
|
|||
@include('admin.abo._order_abo', [
|
||||
'add_only_mode' => $addOnlyMode,
|
||||
'change_locked' => $aboChangeLocked,
|
||||
'portal_view' => true,
|
||||
])
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -23,8 +23,6 @@
|
|||
class="ion ion-ios-arrow-forward"></i> Kundenhoheit prüfen</a>
|
||||
<a href="{{ route('sysadmin_tool', ['cronjobs']) }}" class="d-block mb-3"><i
|
||||
class="ion ion-ios-arrow-forward"></i> Cron Jobs</a>
|
||||
<a href="{{ route('sysadmin_tool', ['domainssl']) }}" class="d-block mb-3"><i
|
||||
class="ion ion-ios-arrow-forward"></i> Subdomains prüfen SSL/Aktiv</a>
|
||||
<a href="{{ route('sysadmin_tool', ['shopping_orders']) }}" class="d-block mb-3"><i
|
||||
class="ion ion-ios-arrow-forward"></i> Shopping Orders Käufe</a>
|
||||
<a href="{{ route('sysadmin_tool', ['import']) }}" class="d-block mb-3"><i
|
||||
|
|
|
|||
|
|
@ -1,228 +0,0 @@
|
|||
@extends('layouts.layout-2')
|
||||
|
||||
@section('content')
|
||||
|
||||
@if ($errors->any())
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="alert alert-danger">
|
||||
<ul>
|
||||
@foreach ($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
<h4 class="font-weight-bold mb-4">
|
||||
Subdomains prüfen SSL/Aktiv
|
||||
</h4>
|
||||
|
||||
<div class="card mb-4">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@if(count($dobbleDomains)>0)
|
||||
{!! Form::open(['action' => route('sysadmin_tool_store', ['domainssl']), 'class' => '']) !!}
|
||||
<div class="card-body">
|
||||
<div class="card-datatable table-responsive">
|
||||
<table class="datatables-style table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="max-width: 60px;">ID</th>
|
||||
<th style="max-width: 60px;">User-ID</th>
|
||||
<th>SubDomain</th>
|
||||
<th>#</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($dobbleDomains as $userId=>$domains)
|
||||
@foreach($domains as $domainId=>$slug)
|
||||
<tr>
|
||||
<td>{{ $domainId }}</td>
|
||||
<td>{{ $userId }}</td>
|
||||
|
||||
<td><a href="{{ $slug }}" target="_blank">{{ $slug }}</a></td>
|
||||
<td>
|
||||
<button type="submit" class="btn btn-warning btn-xs" name="delete_user_shop" value="{{ $domainId }}"
|
||||
onclick="return confirm('Shop {{ $slug }} wirklich löschen?');"><i class="ion"></i>Shop löschen</button>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
@endforeach
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{!! Form::close() !!}
|
||||
@endif
|
||||
|
||||
@if(count($SubDomains)>0)
|
||||
{!! Form::open(['action' => route('sysadmin_tool_store', ['domainssl']), 'class' => '']) !!}
|
||||
<div class="card-body">
|
||||
<div class="card-datatable table-responsive">
|
||||
<table class="datatables-style table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>SubDomain</th>
|
||||
<th>SSL</th>
|
||||
<th>#</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($SubDomains as $SubDomain=>$ssl)
|
||||
<tr>
|
||||
<td><a href="{{ $SubDomain }}" target="_blank">{{ $SubDomain }}</a></td>
|
||||
<td>@if(!is_array($ssl)){{ $ssl }}@endif</td>
|
||||
<td>
|
||||
<button type="submit" class="btn btn-danger btn-xs" name="delete_sub_kas" value="{{ $SubDomain }}"><i class="ion"></i> löschen</button>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{!! Form::close() !!}
|
||||
@endif
|
||||
|
||||
@if(count($values)>0)
|
||||
{!! Form::open(['action' => route('sysadmin_tool_store', ['domainssl']), 'class' => '']) !!}
|
||||
|
||||
<div class="card-body">
|
||||
<div class="card-datatable table-responsive">
|
||||
<table class="datatables-style table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="max-width: 60px;">ID</th>
|
||||
<th style="max-width: 60px;">User-ID</th>
|
||||
<th>Domain</th>
|
||||
<th>Sub</th>
|
||||
<th>SSL</th>
|
||||
<th>#</th>
|
||||
<th>PHP</th>
|
||||
<th>seit</th>
|
||||
<th>Datum</th>
|
||||
<th>Erreichbar</th>
|
||||
<th>Status</th>
|
||||
<th>User Account</th>
|
||||
<th>User Shop</th>
|
||||
<th>User seit</th>
|
||||
|
||||
<th>#</th>
|
||||
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($values as $value)
|
||||
<tr>
|
||||
<td>{{ $value->id }}</td>
|
||||
<td>{{ $value->user_id }}</td>
|
||||
<td><a href="https://{{ $value->slug }}.mivita.care" target="_blank">{{ $value->slug }}.mivita.care</a></td>
|
||||
<td> {!! get_active_badge($value->hasSubdomain) !!} </td>
|
||||
<td> {!! get_active_badge($value->hasSSL) !!} </td>
|
||||
<td><button type="submit" class="btn btn-success btn-xs" name="update_ssl" value="{{ $value->id }}"><i class="ion"></i>update</button></td>
|
||||
<td> {!! $value->PHPversion !!} </td>
|
||||
|
||||
<td>{{ $value->getActiveDateFormatSmall() }}</td>
|
||||
<td>
|
||||
@if($value->user && $value->user->payment_shop)
|
||||
@if($value->user->isActiveShop())
|
||||
<span class="badge badge-pill badge-success"><i class="fa fa-check"></i> {{ $value->user->getPaymentShopDateFormat() }}</span>
|
||||
@else
|
||||
<span class="badge badge-pill badge-warning"><i class="fa fa-ban"></i>{{ $value->user->getPaymentShopDateFormat() }}</span></a>
|
||||
@endif
|
||||
@else
|
||||
<span class="badge badge-pill badge-danger"><i class="fa fa-times"></i></span>
|
||||
@endif
|
||||
|
||||
</td>
|
||||
<td>
|
||||
--
|
||||
{{--
|
||||
@if($value->getSubdomainAvailable())
|
||||
<span class="badge badge-pill badge-success"><i class="fa fa-check"> {{ __('available') }} </i>
|
||||
@if($value->getSubdomainSslSin()) HTTPS @else HTTP @endif
|
||||
</span>
|
||||
@else
|
||||
<span class="badge badge-pill badge-danger"><i class="fa fa-times"> {{ __('not available') }} </i> HTTP </span>
|
||||
@endif
|
||||
--}}
|
||||
</td>
|
||||
<td>{!! get_active_badge($value->active) !!}</td>
|
||||
<td>@if($value->user)
|
||||
@if($value->user->payment_account)
|
||||
@if($value->user->isActiveAccount())
|
||||
<span class="badge badge-pill badge-success"><i class="fa fa-check"></i> {{ $value->user->getPaymentAccountDateFormat() }}</span></a>
|
||||
@else
|
||||
<span class="badge badge-pill badge-warning"><i class="fa fa-ban"></i>{{ $value->user->getPaymentAccountDateFormat() }}</span></a>
|
||||
@endif
|
||||
@else
|
||||
<span class="badge badge-pill badge-danger"><i class="fa fa-times"></i></span></a>
|
||||
@endif
|
||||
@else
|
||||
-
|
||||
@endif
|
||||
</td>
|
||||
|
||||
<td>
|
||||
@if($value->user)
|
||||
@if($value->user->payment_shop)
|
||||
@if($value->user->isActiveShop())
|
||||
<span class="badge badge-pill badge-success"><i class="fa fa-check"></i> {{ $value->user->getPaymentShopDateFormat() }}</span></a>
|
||||
@else
|
||||
<span class="badge badge-pill badge-warning"><i class="fa fa-ban"></i>{{ $value->user->getPaymentShopDateFormat() }}</span></a>
|
||||
@endif
|
||||
@else
|
||||
<span class="badge badge-pill badge-danger"><i class="fa fa-times"></i></span></a>
|
||||
@endif
|
||||
@else
|
||||
-
|
||||
@endif
|
||||
</td>
|
||||
|
||||
<td>
|
||||
@if($value->user)
|
||||
@if($value->user->shop)
|
||||
@if($value->user->shop->active)
|
||||
<span class="badge badge-pill badge-success"><i class="fa fa-check"></i> {{ $value->user->shop->getActiveDateFormatSmall() }}</span></a>
|
||||
@else
|
||||
<span class="badge badge-pill badge-warning"><i class="fa fa-ban"></i>{{ $value->user->shop->getActiveDateFormatSmall() }}</span></a>
|
||||
@endif
|
||||
@else
|
||||
<span class="badge badge-pill badge-danger"><i class="fa fa-times"></i></span></a>
|
||||
@endif
|
||||
@else
|
||||
-
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
@if(!$value->user || !$value->user->payment_shop || !$value->user->isActiveShop())
|
||||
<button type="submit" class="btn btn-danger btn-xs" name="delete_user_shop" value="{{ $value->id }}"><i class="ion"></i>Shop löschen</button>
|
||||
@else
|
||||
<button type="submit" class="btn btn-warning btn-xs" name="delete_user_shop" value="{{ $value->id }}"
|
||||
onclick="return confirm('Shop {{ $value->slug }}.mivita.care wirklich löschen?');"><i class="ion"></i>Shop löschen</button>
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{!! Form::close() !!}
|
||||
@endif
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
|
|
@ -5,6 +5,9 @@
|
|||
<div>
|
||||
{{ __('navigation.statistics') }} / {{ $details['metric_label'] }}
|
||||
<span class="badge badge-secondary ml-2">VIP</span>
|
||||
@if (! empty($details['only_new']))
|
||||
<span class="badge badge-success ml-1">Nur neue im {{ $details['month'] }}/{{ $details['year'] }}</span>
|
||||
@endif
|
||||
</div>
|
||||
<div>
|
||||
<a href="{{ route('user_backoffice_statistics_export', [
|
||||
|
|
@ -12,6 +15,7 @@
|
|||
'metric' => $details['metric'],
|
||||
'month' => $selectedMonth,
|
||||
'year' => $selectedYear,
|
||||
'only_new' => ($details['only_new'] ?? false) ? 1 : 0,
|
||||
]) }}"
|
||||
class="btn btn-sm btn-outline-secondary mr-2">
|
||||
<span class="ion ion-md-download mr-1"></span> CSV
|
||||
|
|
@ -95,6 +99,11 @@
|
|||
<th class="text-right" data-sortable="true" data-sort-type="number"><span class="sortable-label justify-content-end">Sonstige Punkte <i class="ion ion-ios-swap sort-icon"></i></span></th>
|
||||
<th class="text-right" data-sortable="true" data-sort-type="number" style="background-color:#d4edda;"><span class="sortable-label justify-content-end">Kundenpunkte <i class="ion ion-ios-swap sort-icon"></i></span></th>
|
||||
<th class="text-right" data-sortable="true" data-sort-type="number"><span class="sortable-label justify-content-end">Gesamtpunkte <i class="ion ion-ios-swap sort-icon"></i></span></th>
|
||||
@elseif ($details['metric'] === 'new_partners')
|
||||
<th data-sortable="true"><span class="sortable-label">Sponsor <i class="ion ion-ios-swap sort-icon"></i></span></th>
|
||||
<th class="text-right" data-sortable="true" data-sort-type="number"><span class="sortable-label justify-content-end">Kundenpunkte <i class="ion ion-ios-swap sort-icon"></i></span></th>
|
||||
<th data-sortable="true" data-sort-type="date"><span class="sortable-label">Aktiv seit <i class="ion ion-ios-swap sort-icon"></i></span></th>
|
||||
<th data-sortable="true" data-sort-type="date"><span class="sortable-label">Account gültig bis <i class="ion ion-ios-swap sort-icon"></i></span></th>
|
||||
@else
|
||||
<th data-sortable="true" data-sort-type="date"><span class="sortable-label">Aktiv seit <i class="ion ion-ios-swap sort-icon"></i></span></th>
|
||||
<th data-sortable="true" data-sort-type="date"><span class="sortable-label">Account gültig bis <i class="ion ion-ios-swap sort-icon"></i></span></th>
|
||||
|
|
@ -157,6 +166,11 @@
|
|||
<td class="text-right">{{ \App\Services\Util::formatNumber($row['customer_other_points']) }}</td>
|
||||
<td class="text-right font-weight-bold"><span class="badge" style="background-color:#d4edda;color:#155724;font-size:90%;">{{ \App\Services\Util::formatNumber($row['external_points']) }}</span></td>
|
||||
<td class="text-right font-weight-bold">{{ \App\Services\Util::formatNumber($row['total_points']) }}</td>
|
||||
@elseif ($details['metric'] === 'new_partners')
|
||||
<td>{{ $row['sponsor'] ?? '-' }}</td>
|
||||
<td class="text-right font-weight-bold">{{ \App\Services\Util::formatNumber($row['customer_points'] ?? 0) }}</td>
|
||||
<td>{{ $row['active_date'] ?? '-' }}</td>
|
||||
<td>{{ $row['payment_account'] ?? '-' }}</td>
|
||||
@else
|
||||
<td>{{ $row['active_date'] ?? '-' }}</td>
|
||||
<td>
|
||||
|
|
@ -194,6 +208,11 @@
|
|||
<td class="text-right">{{ \App\Services\Util::formatNumber($details['summary']['customer_other_points']) }}</td>
|
||||
<td class="text-right" style="background-color:#d4edda;">{{ \App\Services\Util::formatNumber($details['summary']['external_points']) }}</td>
|
||||
<td class="text-right">{{ \App\Services\Util::formatNumber($details['summary']['total_points']) }}</td>
|
||||
@elseif ($details['metric'] === 'new_partners')
|
||||
<td></td>
|
||||
<td class="text-right">{{ \App\Services\Util::formatNumber($details['summary']['customer_points'] ?? 0) }}</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
@else
|
||||
<td></td>
|
||||
<td></td>
|
||||
|
|
|
|||
|
|
@ -26,6 +26,9 @@
|
|||
@if (!empty($performance['calculated_at']))
|
||||
<span class="ml-2">Snapshot vom {{ $performance['calculated_at'] }}</span>
|
||||
@endif
|
||||
@if (!empty($statistics['abo_stock_live']))
|
||||
<span class="badge badge-success ml-2" title="Abo-Bestandszahlen (Teamabos, Teamkundenabos, Führungskräfte, Top 10) zeigen den heutigen Stand; Punkte und Umsätze bleiben auf dem Stand des gewählten Monats.">Abo-Bestände tagesaktuell</span>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
|
@ -86,11 +89,32 @@
|
|||
};
|
||||
};
|
||||
|
||||
// Ziel-Link des grünen "+N"-Badges: Neupartner-Liste bzw. Abo-Drilldown
|
||||
// gefiltert auf die im Monat neuen Abos (only_new).
|
||||
$newBadgeLink = function (int $lineNo, string $metric) use ($selectedMonth, $selectedYear): string {
|
||||
if ($metric === 'consultants') {
|
||||
return route('user_backoffice_statistics_details', [
|
||||
'line' => $lineNo,
|
||||
'metric' => 'new_partners',
|
||||
'month' => $selectedMonth,
|
||||
'year' => $selectedYear,
|
||||
]);
|
||||
}
|
||||
|
||||
return route('user_backoffice_statistics_details', [
|
||||
'line' => $lineNo,
|
||||
'metric' => $metric,
|
||||
'month' => $selectedMonth,
|
||||
'year' => $selectedYear,
|
||||
'only_new' => 1,
|
||||
]);
|
||||
};
|
||||
|
||||
$selectedMonthName = $filterMonths[(int) $selectedMonth] ?? $selectedMonth;
|
||||
@endphp
|
||||
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6 mb-3 mb-md-0">
|
||||
<div class="col-md-4 mb-3 mb-md-0">
|
||||
<a href="{{ route('user_backoffice_statistics_details', [
|
||||
'line' => 0,
|
||||
'metric' => 'new_partners',
|
||||
|
|
@ -112,7 +136,7 @@
|
|||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-4 mb-3 mb-md-0">
|
||||
<a href="{{ route('user_backoffice_statistics_details', [
|
||||
'line' => 0,
|
||||
'metric' => 'shop_1000',
|
||||
|
|
@ -135,6 +159,32 @@
|
|||
</div>
|
||||
</a>
|
||||
</div>
|
||||
@if (isset($commission))
|
||||
<div class="col-md-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-body d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<div class="text-muted small">
|
||||
Provision ({{ $selectedMonthName }} {{ $selectedYear }})
|
||||
@if (! empty($commission['is_live']))
|
||||
<span class="badge badge-pill badge-info ml-1"
|
||||
title="Vorläufig, live berechnet — final nach Monatsabschluss. Aktualisierung ca. alle 6 Stunden.">Live</span>
|
||||
@endif
|
||||
</div>
|
||||
<div class="display-4 font-weight-bold text-warning">
|
||||
{{ number_format((float) ($commission['total'] ?? 0), 2, ',', '.') }} €
|
||||
</div>
|
||||
<div class="text-muted small mt-1">
|
||||
Payline {{ number_format((float) ($commission['pp'] ?? 0), 2, ',', '.') }} €
|
||||
· Shop {{ number_format((float) ($commission['shop'] ?? 0), 2, ',', '.') }} €
|
||||
· WB {{ number_format((float) ($commission['growth'] ?? 0), 2, ',', '.') }} €
|
||||
</div>
|
||||
</div>
|
||||
<span class="ion ion-md-cash display-4 text-muted"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="card mb-4">
|
||||
|
|
@ -167,8 +217,9 @@
|
|||
</a>
|
||||
@php $newMetric = $newAboMetric($line, $metric); @endphp
|
||||
@if ($newMetric && $line[$newMetric] > 0)
|
||||
<span
|
||||
class="badge badge-pill badge-success ml-1">+{{ number_format($line[$newMetric], 0, ',', '.') }}</span>
|
||||
<a href="{{ $newBadgeLink($line['line'], $metric) }}"
|
||||
class="badge badge-pill badge-success ml-1 backoffice-statistics-click-badge"
|
||||
title="Neue im Monat anzeigen">+{{ number_format($line[$newMetric], 0, ',', '.') }}</a>
|
||||
@endif
|
||||
@else
|
||||
<span
|
||||
|
|
@ -196,8 +247,9 @@
|
|||
</a>
|
||||
@php $newMetric = $newAboMetric($statistics['totals'], $metric); @endphp
|
||||
@if ($newMetric && $statistics['totals'][$newMetric] > 0)
|
||||
<span
|
||||
class="badge badge-pill badge-success ml-1">+{{ number_format($statistics['totals'][$newMetric], 0, ',', '.') }}</span>
|
||||
<a href="{{ $newBadgeLink(0, $metric) }}"
|
||||
class="badge badge-pill badge-success ml-1 backoffice-statistics-click-badge"
|
||||
title="Neue im Monat anzeigen">+{{ number_format($statistics['totals'][$newMetric], 0, ',', '.') }}</a>
|
||||
@endif
|
||||
@else
|
||||
<span
|
||||
|
|
@ -209,6 +261,17 @@
|
|||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
@php $nonPaylinePoints = $statistics['non_payline_points'] ?? null; @endphp
|
||||
@if ($nonPaylinePoints !== null && $nonPaylinePoints > 0)
|
||||
<div class="card-body py-2 border-top">
|
||||
<p class="text-muted small mb-0">
|
||||
In den Gesamtpunkten enthalten:
|
||||
<strong>{{ \App\Services\Util::formatNumber($nonPaylinePoints) }} Punkte</strong>,
|
||||
die nicht in die Payline fließen (z. B. Neupartner-Einschreibungspunkte) —
|
||||
die Punkte-Summe der Struktur-/Provisionsansicht fällt deshalb um diesen Betrag niedriger aus.
|
||||
</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -253,8 +316,13 @@
|
|||
@foreach ($newCustomerAbos as $row)
|
||||
<tr>
|
||||
<td>
|
||||
<div class="font-weight-semibold">{{ $row['name'] }}</div>
|
||||
<div class="text-muted small">Linie {{ $row['line'] }} · {{ $row['career_level'] }}</div>
|
||||
<div class="font-weight-semibold">
|
||||
{{ $row['name'] }}
|
||||
@if (!empty($row['is_self']))
|
||||
<span class="badge badge-pill badge-info ml-1">ich</span>
|
||||
@endif
|
||||
</div>
|
||||
<div class="text-muted small">{{ !empty($row['is_self']) ? 'Eigene Kundenabos' : 'Linie '.$row['line'] }} · {{ $row['career_level'] }}</div>
|
||||
</td>
|
||||
<td class="text-right align-middle">
|
||||
<span class="badge badge-pill badge-outline-default backoffice-statistics-click-badge">
|
||||
|
|
@ -288,7 +356,9 @@
|
|||
@if ($leaderAbos !== null)
|
||||
<div class="text-muted small">
|
||||
{{ number_format((float) ($leaderAbos['total_own'] ?? 0), 0, ',', '.') }} eigene ·
|
||||
{{ number_format((float) ($leaderAbos['total_customer'] ?? 0), 0, ',', '.') }} Kunden
|
||||
{{ number_format((float) ($leaderAbos['total_customer'] ?? 0), 0, ',', '.') }} Kunden ·
|
||||
{{ number_format((float) ($leaderAbos['total_team'] ?? 0), 0, ',', '.') }} Team ·
|
||||
{{ number_format((float) ($leaderAbos['total_team_customer'] ?? 0), 0, ',', '.') }} Teamkunden
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
|
@ -313,32 +383,171 @@
|
|||
<th>Führungskraft</th>
|
||||
<th class="text-right">Eigene Abos</th>
|
||||
<th class="text-right">Kundenabos</th>
|
||||
<th class="text-right" title="Berater-Abos im eigenen Team bis zur nächsten Führungskraft — diese Spalten überschneiden sich nicht und ergeben die Kopf-Summe.">Teamabos (direkt)</th>
|
||||
<th class="text-right" title="Kundenabos im eigenen Team bis zur nächsten Führungskraft.">Team-Kundenabos (direkt)</th>
|
||||
<th class="text-right" title="Berater-Abos der kompletten Downline — Teams untergeordneter Führungskräfte zählen hier mit, die Spalte lässt sich deshalb nicht aufsummieren.">Teamabos (gesamt)</th>
|
||||
<th class="text-right" title="Kundenabos der kompletten Downline — inklusive der Teams untergeordneter Führungskräfte.">Team-Kundenabos (gesamt)</th>
|
||||
<th class="text-right" title="Eigenes Abo + Kundenabos + Teamabos (gesamt) + Team-Kundenabos (gesamt)">Gesamt</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($leaderAbos['rows'] as $row)
|
||||
@php
|
||||
$leaderTotal = $row['total_abo_count_full']
|
||||
?? (($row['own_abo_count'] ?? 0) + ($row['customer_abo_count'] ?? 0) + ($row['team_abo_count_total'] ?? ($row['team_abo_count'] ?? 0)) + ($row['team_customer_abo_count_total'] ?? ($row['team_customer_abo_count'] ?? 0)));
|
||||
@endphp
|
||||
<tr>
|
||||
<td>
|
||||
<div class="font-weight-semibold">{{ $row['name'] }}</div>
|
||||
<div class="text-muted small">Linie {{ $row['line'] }} · {{ $row['career_level'] }}</div>
|
||||
</td>
|
||||
<td class="text-right align-middle">
|
||||
@if (($row['own_abo_count'] ?? 0) > 0)
|
||||
<span class="badge badge-pill badge-outline-default backoffice-statistics-click-badge">
|
||||
{{ number_format((float) $row['own_abo_count'], 0, ',', '.') }}
|
||||
</span>
|
||||
@else
|
||||
<span class="badge badge-pill badge-light backoffice-statistics-empty-badge">0</span>
|
||||
@endif
|
||||
@foreach (['own_abo_count', 'customer_abo_count', 'team_abo_count', 'team_customer_abo_count', 'team_abo_count_total', 'team_customer_abo_count_total'] as $countKey)
|
||||
<td class="text-right align-middle">
|
||||
@if (($row[$countKey] ?? 0) > 0)
|
||||
<span class="badge badge-pill badge-outline-default backoffice-statistics-click-badge">
|
||||
{{ number_format((float) $row[$countKey], 0, ',', '.') }}
|
||||
</span>
|
||||
@else
|
||||
<span class="badge badge-pill badge-light backoffice-statistics-empty-badge">0</span>
|
||||
@endif
|
||||
</td>
|
||||
@endforeach
|
||||
<td class="text-right align-middle font-weight-bold">
|
||||
{{ number_format((float) $leaderTotal, 0, ',', '.') }}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="card-body pt-2 pb-3">
|
||||
<p class="text-muted small mb-0">
|
||||
<strong>direkt</strong> = Team bis zur nächsten Führungskraft (überschneidungsfrei, ergibt die Kopf-Summe).
|
||||
<strong>gesamt</strong> = komplette Downline inklusive der Teams untergeordneter Führungskräfte — dieselben Abos
|
||||
können dort bei mehreren Führungskräften zählen, die Gesamt-Spalte lässt sich deshalb nicht aufsummieren.
|
||||
</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@php
|
||||
$topCustomerAbos = $statistics['top_customer_abos'] ?? null;
|
||||
@endphp
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Top 10 Kundenabos (Anzahl)</h5>
|
||||
<div class="text-muted small"
|
||||
title="Zählt den heutigen Bestand aktiver Kundenabos. Die Incentive-Rangliste zählt anders: dort bleiben alle im Aktionszeitraum gestarteten Abos dauerhaft gezählt (inkl. Eigenabo und inzwischen beendeter Abos) — die Zahlen weichen deshalb bewusst voneinander ab.">
|
||||
aktueller Bestand aktiver Kundenabos · weicht bewusst von der Incentive-Zählung ab
|
||||
<span class="ion ion-md-information-circle-outline"></span>
|
||||
</div>
|
||||
</div>
|
||||
@if ($topCustomerAbos === null)
|
||||
<div class="card-body">
|
||||
<p class="text-muted mb-0">
|
||||
Für diesen Monat liegt noch ein älterer Snapshot ohne diese Liste vor.
|
||||
</p>
|
||||
</div>
|
||||
@elseif (count($topCustomerAbos['by_count']) === 0)
|
||||
<div class="card-body">
|
||||
<p class="text-muted mb-0">Im Team gibt es aktuell keine aktiven Kundenabos.</p>
|
||||
</div>
|
||||
@else
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 4rem;">Platz</th>
|
||||
<th>Berater</th>
|
||||
<th class="text-right">Kundenabos</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($topCustomerAbos['by_count'] as $row)
|
||||
<tr>
|
||||
<td class="align-middle font-weight-bold">{{ $loop->iteration }}.</td>
|
||||
<td>
|
||||
<div class="font-weight-semibold">
|
||||
{{ $row['name'] }}
|
||||
@if (!empty($row['is_self']))
|
||||
<span class="badge badge-pill badge-info ml-1">ich</span>
|
||||
@endif
|
||||
</div>
|
||||
<div class="text-muted small">{{ !empty($row['is_self']) ? 'Eigene Kundenabos' : 'Linie '.$row['line'] }} · {{ $row['career_level'] }}</div>
|
||||
</td>
|
||||
<td class="text-right align-middle">
|
||||
@if (($row['customer_abo_count'] ?? 0) > 0)
|
||||
<span class="badge badge-pill badge-outline-default backoffice-statistics-click-badge">
|
||||
{{ number_format((float) $row['customer_abo_count'], 0, ',', '.') }}
|
||||
</span>
|
||||
@else
|
||||
<span class="badge badge-pill badge-light backoffice-statistics-empty-badge">0</span>
|
||||
@endif
|
||||
<span class="badge badge-pill badge-outline-default backoffice-statistics-click-badge">
|
||||
{{ number_format((float) $row['abo_count'], 0, ',', '.') }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Top 10 Kundenabos (Umsatz)</h5>
|
||||
<div class="text-muted small"
|
||||
title="Abgerechnet = Kundenabo-Punkte, die im gewählten Monat tatsächlich angerechnet wurden (Hauptwert, Sortierung). Bestand/Lieferung = Punkte, die die heute aktiven Kundenabos pro Lieferung bringen — kann abweichen, wenn Abos im Monat dazukamen oder beendet wurden.">
|
||||
sortiert nach abgerechneten Kundenabo-Punkten {{ $selectedMonthName }} {{ $selectedYear }}
|
||||
<span class="ion ion-md-information-circle-outline"></span>
|
||||
</div>
|
||||
</div>
|
||||
@if ($topCustomerAbos === null)
|
||||
<div class="card-body">
|
||||
<p class="text-muted mb-0">
|
||||
Für diesen Monat liegt noch ein älterer Snapshot ohne diese Liste vor.
|
||||
</p>
|
||||
</div>
|
||||
@elseif (count($topCustomerAbos['by_points']) === 0)
|
||||
<div class="card-body">
|
||||
<p class="text-muted mb-0">Im Team gibt es aktuell keine Kundenabo-Umsätze.</p>
|
||||
</div>
|
||||
@else
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 4rem;">Platz</th>
|
||||
<th>Berater</th>
|
||||
<th class="text-right">Abos</th>
|
||||
<th class="text-right" title="Im gewählten Monat abgerechnete Kundenabo-Punkte">Abgerechnet (Punkte)</th>
|
||||
<th class="text-right" title="Punkte der heute aktiven Kundenabos pro Lieferung">Bestand/Lieferung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($topCustomerAbos['by_points'] as $row)
|
||||
<tr>
|
||||
<td class="align-middle font-weight-bold">{{ $loop->iteration }}.</td>
|
||||
<td>
|
||||
<div class="font-weight-semibold">
|
||||
{{ $row['name'] }}
|
||||
@if (!empty($row['is_self']))
|
||||
<span class="badge badge-pill badge-info ml-1">ich</span>
|
||||
@endif
|
||||
</div>
|
||||
<div class="text-muted small">{{ !empty($row['is_self']) ? 'Eigene Kundenabos' : 'Linie '.$row['line'] }} · {{ $row['career_level'] }}</div>
|
||||
</td>
|
||||
<td class="text-right align-middle">
|
||||
<span class="badge badge-pill badge-outline-default backoffice-statistics-click-badge">
|
||||
{{ number_format((float) ($row['abo_count'] ?? 0), 0, ',', '.') }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-right align-middle font-weight-bold">
|
||||
{{ \App\Services\Util::formatNumber($row['points_actual']) }}
|
||||
</td>
|
||||
<td class="text-right align-middle">
|
||||
{{ \App\Services\Util::formatNumber($row['points_target']) }}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
|
|
|
|||
|
|
@ -80,32 +80,6 @@
|
|||
</div>
|
||||
</li>
|
||||
|
||||
{{-- <li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<div class="text-muted">{{ __('Status') }}</div>
|
||||
<div class="text-right">
|
||||
@if($user->shop->getSubdomainStatus())
|
||||
<span class="badge badge-pill badge-success"><i class="fa fa-check"> {{ __('shop.available') }} </i> DNS</span><br>
|
||||
@else
|
||||
<span class="badge badge-pill badge-danger"><i class="fa fa-times"> {{ __('shop.not_available') }} </i> DNS</span>
|
||||
@endif
|
||||
|
||||
@if($user->shop->getSubdomainAvailable())
|
||||
<span class="badge badge-pill badge-success"><i class="fa fa-check"> {{ __('shop.available') }} </i>
|
||||
@if($user->shop->getSubdomainSslSin()) HTTPS @else HTTP @endif
|
||||
</span>
|
||||
@else
|
||||
<span class="badge badge-pill badge-danger"><i class="fa fa-times"> {{ __('shop.not_available') }} </i> HTTP </span>
|
||||
@endif
|
||||
|
||||
@if($user->shop->getSubdomainSslSinActive())
|
||||
<span class="badge badge-pill badge-success"><i class="fa fa-check"> {{ __('shop.available') }} </i> SSL
|
||||
</span>
|
||||
@else
|
||||
<span class="badge badge-pill badge-danger"><i class="fa fa-times"> {{ __('shop.not_available') }} </i> SSL </span>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
</li> --}}
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<div class="text-muted">{{ __('shop.active_since') }}</div>
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -287,7 +287,7 @@
|
|||
<td>{{ Yard::instance('shopping')->getShippingCountryName() }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-left">{{ __('order.shipping_costs') }}:</td>
|
||||
<td class="text-left">{{ __('order.shipping_costs') }} ({{ __('order.net') }}):</td>
|
||||
<td>
|
||||
|
||||
@php($shippingFree = Yard::instance('shopping')->getShippingFree())
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
@endforeach
|
||||
<tr>
|
||||
<td>
|
||||
<strong>{{ __('order.total_shipping_costs') }}</strong>
|
||||
<strong>{{ __('order.total_shipping_costs') }} ({{ __('order.net') }})</strong>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
</td>
|
||||
|
|
|
|||
|
|
@ -38,6 +38,46 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Abo-Umsatz in der Payline (Soll/Ist, Live) --}}
|
||||
@if (isset($paylineAboTurnover))
|
||||
<div class="row mb-2">
|
||||
<div class="col-lg-6 col-12 mb-3">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<div class="text-muted small">
|
||||
{{ __('abo.payline_abo_turnover') }}
|
||||
<span class="badge badge-pill badge-info ml-1"
|
||||
title="{{ __('abo.payline_abo_turnover_hint') }}">Live</span>
|
||||
</div>
|
||||
@if (($paylineAboTurnover['paylines'] ?? 0) > 0)
|
||||
<div class="row mt-2">
|
||||
<div class="col-6 text-center">
|
||||
<div class="text-muted small">{{ __('abo.payline_target_label') }}</div>
|
||||
<div class="display-5 font-weight-bold text-primary">
|
||||
{{ \App\Services\Util::formatNumber($paylineAboTurnover['target']) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6 text-center">
|
||||
<div class="text-muted small">{{ __('abo.payline_actual_label') }}</div>
|
||||
<div class="display-5 font-weight-bold">
|
||||
{{ \App\Services\Util::formatNumber($paylineAboTurnover['actual']) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-muted small mt-2 text-center">
|
||||
{{ __('abo.payline_hint', ['lines' => $paylineAboTurnover['paylines'], 'members' => $paylineAboTurnover['members']]) }}
|
||||
<br>
|
||||
{{ __('abo.payline_abo_counts', ['team_abos' => $paylineAboTurnover['team_abo_count'] ?? 0, 'customer_abos' => $paylineAboTurnover['team_customer_abo_count'] ?? 0]) }}
|
||||
</div>
|
||||
@else
|
||||
<p class="text-muted mb-0 mt-2">{{ __('abo.payline_none') }}</p>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Linien-/Ebenen-Tabelle --}}
|
||||
<div class="card mb-4">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
|
|
@ -53,7 +93,9 @@
|
|||
<th class="text-center">{{ __('abo.team_customer_abos') }}</th>
|
||||
<th class="text-center">{{ __('abo.new_this_month') }} ({{ $currentMonthName }})</th>
|
||||
<th class="text-center">{{ __('abo.team_total') }}</th>
|
||||
<th class="text-right">{{ __('abo.abo_count_points') }}</th>
|
||||
<th class="text-right">{{ __('abo.abo_points_per_cycle') }}</th>
|
||||
<th class="text-right">{{ __('abo.abo_points_billed', ['month' => $currentMonthName]) }}</th>
|
||||
<th class="text-right" title="{{ __('abo.abo_points_expected_hint', ['day' => 25]) }}">{{ __('abo.abo_points_expected', ['day' => 25]) }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
@ -77,9 +119,11 @@
|
|||
<td class="text-center text-success font-weight-bold">+{{ $line['own_abos_new'] + $line['customer_abos_new'] }}</td>
|
||||
<td class="text-center font-weight-bold text-primary">{{ $line['total_abos'] }}</td>
|
||||
<td class="text-right font-weight-bold">{{ \App\Services\Util::formatNumber($line['own_abo_points'] + $line['customer_abo_points']) }}</td>
|
||||
<td class="text-right">{{ \App\Services\Util::formatNumber($line['abo_points_billed'] ?? 0) }}</td>
|
||||
<td class="text-right text-muted">{{ \App\Services\Util::formatNumber($line['abo_points_expected'] ?? 0) }}</td>
|
||||
</tr>
|
||||
<tr class="p-0">
|
||||
<td colspan="7" class="p-0 border-0">
|
||||
<td colspan="9" class="p-0 border-0">
|
||||
<div class="collapse {{ $line['line'] === 1 ? 'show' : '' }}" id="{{ $collapseId }}">
|
||||
<div class="p-3 bg-lightest">
|
||||
<table class="table table-sm table-borderless mb-0">
|
||||
|
|
@ -129,7 +173,7 @@
|
|||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="7" class="text-muted text-center py-4">{{ __('tables.no_data_available') }}</td>
|
||||
<td colspan="9" class="text-muted text-center py-4">{{ __('tables.no_data_available') }}</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
|
|
@ -143,6 +187,8 @@
|
|||
<td class="text-center text-success">+{{ $totals['own_abos_new'] + $totals['customer_abos_new'] }}</td>
|
||||
<td class="text-center text-primary">{{ $totals['total_abos'] }}</td>
|
||||
<td class="text-right">{{ \App\Services\Util::formatNumber($totals['own_abo_points'] + $totals['customer_abo_points']) }}</td>
|
||||
<td class="text-right">{{ \App\Services\Util::formatNumber($totals['abo_points_billed'] ?? 0) }}</td>
|
||||
<td class="text-right text-muted">{{ \App\Services\Util::formatNumber($totals['abo_points_expected'] ?? 0) }}</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
@endif
|
||||
|
|
|
|||
|
|
@ -337,9 +337,10 @@
|
|||
</div>
|
||||
</div>--}}
|
||||
|
||||
@php($cardShippingTaxFree = Yard::instance($yard_instance)->getUserTaxFree())
|
||||
<div class="clearfix mb-2">
|
||||
<span class="pull-right small">{{ Yard::instance($yard_instance)->shipping() }} € </span>
|
||||
<span class="pull-left small"><a href="{{ legal_url('/versandkosten') }}" style="color:#666666;text-decoration: underline">{{ __('order.shipping_costs') }}</a>:</span>
|
||||
<span class="pull-right small">{{ $cardShippingTaxFree ? Yard::instance($yard_instance)->shippingNet() : Yard::instance($yard_instance)->shipping() }} € </span>
|
||||
<span class="pull-left small"><a href="{{ legal_url('/versandkosten') }}" style="color:#666666;text-decoration: underline">{{ __('order.shipping_costs') }}</a> ({{ $cardShippingTaxFree ? __('order.net') : __('order.incl_VAT') }}):</span>
|
||||
</div>
|
||||
<hr class="mt-4 mb-4">
|
||||
@if(Yard::instance($yard_instance)->getUserTaxFree())
|
||||
|
|
|
|||
|
|
@ -339,9 +339,10 @@
|
|||
<td colspan="4" class="text-right small no-border-top"><strong>{{ __('Delivery country') }}:</strong></td>
|
||||
<td class="text-right small no-border-top">{{ Yard::instance($yard_instance)->getShippingCountryName() }}</td>
|
||||
</tr>
|
||||
@php($checkoutShippingTaxFree = Yard::instance($yard_instance)->getUserTaxFree())
|
||||
<tr>
|
||||
<td colspan="4" class="text-right small no-border-top"><strong>{{ __('order.shipping_costs') }}:</strong></td>
|
||||
<td class="text-right small no-border-top">{{ Yard::instance($yard_instance)->shipping() }} € </td>
|
||||
<td colspan="4" class="text-right small no-border-top"><strong>{{ __('order.shipping_costs') }} ({{ $checkoutShippingTaxFree ? __('order.net') : __('order.incl_VAT') }}):</strong></td>
|
||||
<td class="text-right small no-border-top">{{ $checkoutShippingTaxFree ? Yard::instance($yard_instance)->shippingNet() : Yard::instance($yard_instance)->shipping() }} € </td>
|
||||
</tr>
|
||||
@if(Yard::instance($yard_instance)->getUserTaxFree())
|
||||
<tr>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue