New Ops report to surface clients whose net monthly Internet bill exceeds a threshold — for spotting plans that should be revised. Hub (lib/legacy-reports.js — new module, read-only MariaDB): - GET /reports/legacy/overpriced-internet (+ .csv variant) - Queries the legacy gestionclient DB directly via a small mysql2 pool (reuses cfg.LEGACY_DB_* — same vars as auth.js sync-legacy; added LEGACY_DB_PASS to the hub .env which was previously unset). - Grain = delivery (service address), NOT account: a multi-unit building (account 13166 has 82 doors / 205 services) would otherwise show a single bogus $2117 line instead of ~45 per door. - Net monthly Internet = SUM of effective per-line price across Internet categories (32 fibre, 4 wireless, 23 camping + optional add-ons 16/17/21), discounts included (products with price<0 are recurring credits like RAB24M -15$). - Effective price = service.hijack ? hijack_price : product.price. - Only recurring lines (product.price_recurr_type=1) — excludes one-time equipment/install charges. - Annual plans (SKU LIKE '%ANN', e.g. FTTH_ANN @ 480$/yr) normalized /12 so they compare correctly against a monthly threshold (was falsely showing $480 → now $40, drops below 90$). - Excludes TV (33,34) and téléphonie (9) entirely. Validated counts at 90$/mo: 983 residential, 297 commercial addresses. Ops UI: - src/pages/ReportInternetCherPage.vue — threshold/segment/add-ons filters, summary cards (count, total monthly, avg, discounts), sortable+filterable table (client, address, net, gross, discount, plan detail with full tooltip, contact), CSV download. - Card on the Rapports hub + route /rapports/internet-cher. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
113 lines
3.8 KiB
Vue
113 lines
3.8 KiB
Vue
<template>
|
|
<q-page padding>
|
|
<div class="text-h6 text-weight-bold q-mb-md">Rapports</div>
|
|
|
|
<!-- Comptabilité section -->
|
|
<div class="text-subtitle2 text-grey-7 text-weight-bold q-mb-sm">Comptabilité & Finances</div>
|
|
<div class="row q-col-gutter-md q-mb-lg">
|
|
<div class="col-12 col-md-6 col-lg-4" v-for="report in financeReports" :key="report.title">
|
|
<div class="ops-card cursor-pointer" style="min-height:120px" @click="$router.push(report.route)">
|
|
<div class="row items-center q-mb-sm">
|
|
<q-icon :name="report.icon" size="28px" :color="report.color" class="q-mr-sm" />
|
|
<div class="text-subtitle1 text-weight-bold">{{ report.title }}</div>
|
|
</div>
|
|
<div class="text-caption text-grey-6">{{ report.description }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Opérations section -->
|
|
<div class="text-subtitle2 text-grey-7 text-weight-bold q-mb-sm">Opérations</div>
|
|
<div class="row q-col-gutter-md">
|
|
<div class="col-12 col-md-6 col-lg-4" v-for="report in opsReports" :key="report.title">
|
|
<div class="ops-card cursor-pointer" style="min-height:120px;opacity:0.6" @click="report.action">
|
|
<div class="row items-center q-mb-sm">
|
|
<q-icon :name="report.icon" size="28px" :color="report.color" class="q-mr-sm" />
|
|
<div class="text-subtitle1 text-weight-bold">{{ report.title }}</div>
|
|
<q-badge class="q-ml-sm" color="grey-4" text-color="grey-7" label="Bientôt" />
|
|
</div>
|
|
<div class="text-caption text-grey-6">{{ report.description }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</q-page>
|
|
</template>
|
|
|
|
<script setup>
|
|
const financeReports = [
|
|
{
|
|
title: 'Revenus par compte',
|
|
description: 'Évolution mensuelle des revenus par compte GL (4000-5000). Graphique stacked + export CSV.',
|
|
icon: 'trending_up',
|
|
color: 'green-6',
|
|
route: '/rapports/revenus',
|
|
},
|
|
{
|
|
title: 'Ventes détaillées',
|
|
description: 'Liste des factures avec sous-total, TPS, TVQ et total. Inclut les notes de crédit.',
|
|
icon: 'receipt_long',
|
|
color: 'indigo-6',
|
|
route: '/rapports/ventes',
|
|
},
|
|
{
|
|
title: 'Rapport de taxes (TPS/TVQ)',
|
|
description: 'Taxes perçues vs payées par période mensuelle ou trimestrielle. Pour les déclarations fiscales.',
|
|
icon: 'account_balance',
|
|
color: 'purple-6',
|
|
route: '/rapports/taxes',
|
|
},
|
|
{
|
|
title: 'Âge des comptes',
|
|
description: 'Comptes à recevoir par tranche d\'ancienneté: courant, 30, 60, 90, 120+ jours.',
|
|
icon: 'account_balance_wallet',
|
|
color: 'red-6',
|
|
route: '/rapports/ar',
|
|
},
|
|
{
|
|
title: 'Clients qui paient cher — Internet',
|
|
description: 'Adresses dont la facture Internet mensuelle (forfait + rabais, hors TV/téléphonie) dépasse un seuil. Pour cibler les forfaits à réviser.',
|
|
icon: 'trending_up',
|
|
color: 'deep-orange-6',
|
|
route: '/rapports/internet-cher',
|
|
},
|
|
]
|
|
|
|
const opsReports = [
|
|
{
|
|
title: 'Clients par territoire',
|
|
description: 'Répartition des clients actifs par zone géographique.',
|
|
icon: 'map',
|
|
color: 'teal-6',
|
|
action: () => {},
|
|
},
|
|
{
|
|
title: 'Tickets par priorité',
|
|
description: 'Analyse des tickets ouverts et temps de résolution moyen.',
|
|
icon: 'bug_report',
|
|
color: 'orange-6',
|
|
action: () => {},
|
|
},
|
|
{
|
|
title: 'Équipements déployés',
|
|
description: 'Inventaire des ONT, routeurs et modems par statut.',
|
|
icon: 'router',
|
|
color: 'blue-6',
|
|
action: () => {},
|
|
},
|
|
{
|
|
title: 'Abonnements actifs',
|
|
description: 'Liste des abonnements avec plan, montant et ancienneté.',
|
|
icon: 'subscriptions',
|
|
color: 'purple-6',
|
|
action: () => {},
|
|
},
|
|
{
|
|
title: 'Dispatch performance',
|
|
description: 'Taux de complétion des tâches et temps moyen par technicien.',
|
|
icon: 'speed',
|
|
color: 'red-6',
|
|
action: () => {},
|
|
},
|
|
]
|
|
</script>
|