---
name: s08-depenses-par-cost-center-employe
scenario: S08
description: Dépenses par cost center avec breakdown employé — les noms de cost centers sont retournés directement, mais certains employés apparaissent sous forme d'ID (utilisateurs archivés)
tags: [spend-analysis, cost-center, employee, breakdown, groupby]
when_to_use: Quand on veut analyser les dépenses d'un département avec le détail par employé, ou identifier qui dépense le plus dans chaque équipe
risk: P2 — groupBy=["costCenter","employee"] retourne les noms de cost centers directement, mais les employés archivés ou sans nom apparaissent avec leur ID comme clé (ex: "d2uvqq5sbi6oth") — le même gotcha que les utilisateurs archivés dans get_users.
---

# Instructions — Dépenses par cost center et employé

## ⚠️ Noms cost centers vs employés : comportement différent

Dans `spendesk_analyze_spend` :

| Dimension | `key` retourné | `id` retourné |
|-----------|---------------|--------------|
| `costCenter` | **Nom** du cost center (ex: "Marketing") | UUID du cost center |
| `supplier` | **ID** du fournisseur | ID (identique) |
| `employee` | **Nom** si disponible (ex: "Sabine Juin") | ID de l'employé |
| | **ID** si archivé ou sans nom (ex: "d2uvqq5sbi6oth") | ID (identique) |

→ **Résolution de noms nécessaire seulement pour `employee` quand `key === id`** (utilisateur archivé/sans nom).

## ⚠️ Cost centers "X -old-" : non archivés dans le système

`get_cost_centers` retourne des cost centers dont le nom commence par "X -old-" ou "X- old" mais avec `isArchived=false`. Ces cost centers "déprécié par convention" restent actifs dans le système et peuvent apparaître dans les données historiques.

→ Toujours utiliser `get_cost_centers` pour obtenir la liste des IDs actifs si l'utilisateur veut filtrer sur un sous-ensemble de départements.

## Étape 1 — Récupérer les cost centers actifs (si besoin de filtrer)

```json
{ "companyId": "...", "includeArchived": false }
```

→ Retourne id + name + isArchived pour tous les cost centers.
→ Utiliser les IDs dans `filters.costCenterIds` pour cibler un département.

## Étape 2 — Analyse avec double breakdown

```json
{
  "companyId": "...",
  "fromDate": "YYYY-MM-DD",
  "toDate": "YYYY-MM-DD",
  "groupBy": ["costCenter", "employee"],
  "limit": 10
}
```

→ Retourne : top-10 cost centers (par montant), chaque cost center avec ses top-10 employés.
→ La row "Others" apparaît si > 10 cost centers ou > 10 employés par cost center.

## Étape 3 — Filtrer sur un seul cost center

Pour voir TOUS les employés d'un département (pas seulement les top-10) :
```json
{
  "companyId": "...",
  "fromDate": "YYYY-MM-DD",
  "toDate": "YYYY-MM-DD",
  "groupBy": ["costCenter", "employee"],
  "filters": { "costCenterIds": ["<uuid-cost-center>"] },
  "limit": 50
}
```

→ Avec un seul cost center filtré, le `limit=50` au niveau employé donne les 50 plus gros dépensiers.

## Étape 4 — Interpréter les champs

Chaque row cost center :
- `key` : **nom** du cost center
- `id` : UUID du cost center
- `amount` / `count` / `share` : agrégats du cost center
- `breakdown[]` : top-N employés dans ce cost center

Chaque row employé (dans breakdown) :
- `key` : **nom** si disponible, **ID** si archivé ou sans nom
- `id` : ID de l'employé (toujours)
- `amount` / `count` / `share` : dépenses de l'employé dans CE cost center

## Étape 5 — Gérer les employés sans nom

```
breakdown.forEach(emp => {
  const displayName = (emp.key !== emp.id)
    ? emp.key                // nom résolu
    : `[Utilisateur archivé: ${emp.id.substring(0,8)}...]`  // ID fallback
})
```

## Exemple live (H1 2026, groupBy=["costCenter","employee"])

**Total : 8 174 523,65 EUR — 3 937 payables**

| Rang | Cost Center | Montant | Share | Top dépensier |
|------|-------------|---------|-------|--------------|
| 1 | **People** | 2 078 260,64 EUR | 25,4% | `d2uvqq5sbi6oth` (ID seul) — 691 423,46 EUR (33,3%) |
| 2 | **Marketing** | 1 867 209,46 EUR | 22,8% | Loretta Nguyen — 1 141 489,15 EUR (61,1%) |
| 3 | **Engineering Foundations** | 1 563 799,22 EUR | 19,1% | Hoang-Huy Jean-Pierre Huynh — 529 153,49 EUR (33,8%) |
| 4 | **Product Engineering** | 592 502,11 EUR | 7,2% | Guilhem Bellion — 142 850,34 EUR (24,1%) |
| 5 | **Revenue Operations** | 591 595,97 EUR | 7,2% | Sébastien van Hoof — 471 241,01 EUR (79,7%) |
| 6 | **Strat Ops** | 253 422,42 EUR | 3,1% | Vincent Mothes — 104 412,26 EUR (41,2%) |
| 7 | **Revenue** | 200 824,70 EUR | 2,5% | Maria Eugenia Montes Pita — 166 139,29 EUR (82,7%) |
| 8 | **Security Engineering** | 178 840,45 EUR | 2,2% | Jonathan Fedida — 118 558,80 EUR (66,3%) |
| 9 | **Product** | 164 276,49 EUR | 2,0% | Julien Chriqui — 26 246,65 EUR (16%) |
| 10 | **Finance** | 162 699,94 EUR | 2,0% | Eva Tourki — 53 461,60 EUR (32,9%) |
| — | Others | 521 092,25 EUR | 6,4% | — |

Observations :
- Le top dépensier de "People" est un ID (utilisateur archivé) — 691 K EUR sans nom affiché
- Marketing très concentré : Loretta Nguyen représente 61,1% des dépenses du département
- Revenue Operations : Sébastien van Hoof = 79,7% du cost center (dépendance forte sur un seul employé)
- Revenue Operations "Others" = -13 427,11 EUR (négatif) — credit notes d'employés hors top-10

## Exemple de prompts

- "Quelles équipes dépensent le plus ?" → groupBy=["costCenter"], pas de breakdown employee
- "Qui dépense le plus dans chaque département ?" → groupBy=["costCenter","employee"], limit=5
- "Dépenses de l'équipe Marketing par employé" → groupBy=["costCenter","employee"], costCenterIds=[id_marketing]
- "Quel département concentre ses dépenses sur peu d'employés ?" → lire share du top-1 dans chaque breakdown
