{
  "info": {
    "name": "Approbateurs (Dadycar Fleet)",
    "description": "Approval Circuits + Approver Pool + Digest configuration. Drives the /approbateurs page (3 tabs) and integrates with the Commande approval workflow.\n\n**Setup**: set the `token` variable to a Bearer token, then the `circuit_id`, `step_id`, `approver_id`, `commande_id` variables as you go. Most list endpoints will return ids you can paste back.\n\n**Base URL**: `https://api.fleet.dadycar.fr/api/v1/fleet`",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "variable": [
    { "key": "base_url",     "value": "https://api.fleet.dadycar.fr/api/v1/fleet", "type": "string" },
    { "key": "token",        "value": "PASTE_BEARER_TOKEN_HERE",                   "type": "string" },
    { "key": "circuit_id",   "value": "1",  "type": "string" },
    { "key": "step_id",      "value": "1",  "type": "string" },
    { "key": "approver_id",  "value": "1",  "type": "string" },
    { "key": "delegate_id",  "value": "2",  "type": "string" },
    { "key": "commande_id",  "value": "1",  "type": "string" },
    { "key": "pending_validator_user_id", "value": "78", "type": "string" }
  ],
  "auth": {
    "type": "bearer",
    "bearer": [{ "key": "token", "value": "{{token}}", "type": "string" }]
  },
  "item": [
    {
      "name": "1. Approval Circuits",
      "description": "Templates for approval workflows. Each circuit has ordered steps; each step has a role, a default approver from the pool, an SLA in hours, and an optional TCO threshold (step skipped if commande TCO doesn't exceed it AND step is non-mandatory).",
      "item": [
        {
          "name": "List circuits + KPIs (flat)",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{base_url}}/approval-circuits/list?sort_by=updated_at&sort_dir=desc",
              "host": ["{{base_url}}"],
              "path": ["approval-circuits", "list"],
              "query": [
                { "key": "sort_by",       "value": "updated_at", "description": "name | updated_at | steps_count | status" },
                { "key": "sort_dir",      "value": "desc" },
                { "key": "search",        "value": "",          "disabled": true, "description": "full-text on name + description" },
                { "key": "status_filter", "value": "active",    "disabled": true, "description": "active | inactive" }
              ]
            },
            "description": "Flat list — NOT paginated. Returns every circuit for the company in one shot (matches the FE single-screen card layout).\n\nResponse: { total, circuits[], kpis }. The `per_page`/`page` query params, if sent, are silently ignored."
          }
        },
        {
          "name": "KPIs only",
          "request": { "method": "GET", "url": "{{base_url}}/approval-circuits/kpis" }
        },
        {
          "name": "All (dropdown options)",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{base_url}}/approval-circuits/list/all?active_only=true",
              "host": ["{{base_url}}"],
              "path": ["approval-circuits", "list", "all"],
              "query": [{ "key": "active_only", "value": "true" }]
            }
          }
        },
        {
          "name": "Show circuit",
          "request": { "method": "GET", "url": "{{base_url}}/approval-circuits/show/{{circuit_id}}" }
        },
        {
          "name": "Options — statuses",
          "request": { "method": "GET", "url": "{{base_url}}/approval-circuits/options/statuses" }
        },
        {
          "name": "Options — sorts",
          "request": { "method": "GET", "url": "{{base_url}}/approval-circuits/options/sorts" }
        },
        {
          "name": "Options — approver roles",
          "request": { "method": "GET", "url": "{{base_url}}/approval-circuits/options/roles" }
        },
        {
          "name": "Create circuit (minimal)",
          "request": {
            "method": "POST",
            "url": "{{base_url}}/approval-circuits/store",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\": \"Circuit Standard\",\n  \"description\": \"Circuit par défaut pour toutes les commandes véhicule standard (TCO ≤ 800 €/mois)\",\n  \"is_active\": true\n}"
            }
          }
        },
        {
          "name": "Create circuit + steps (one-shot)",
          "request": {
            "method": "POST",
            "url": "{{base_url}}/approval-circuits/store",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\": \"Circuit Premium\",\n  \"description\": \"Circuit renforcé pour les commandes à fort TCO (> 800 €/mois) — validation DAF obligatoire\",\n  \"is_active\": true,\n  \"steps\": [\n    {\n      \"label\": \"Validation Manager N+1\",\n      \"role_code\": \"MN1\",\n      \"default_approver_id\": {{approver_id}},\n      \"sla_hours\": 48,\n      \"is_mandatory\": true\n    },\n    {\n      \"label\": \"Validation RH\",\n      \"role_code\": \"RH\",\n      \"default_approver_id\": {{approver_id}},\n      \"sla_hours\": 48,\n      \"is_mandatory\": true\n    },\n    {\n      \"label\": \"Validation DAF\",\n      \"role_code\": \"DAF\",\n      \"default_approver_id\": {{approver_id}},\n      \"sla_hours\": 72,\n      \"tco_threshold_min\": 800.00,\n      \"is_mandatory\": false\n    },\n    {\n      \"label\": \"Validation Fleet Manager\",\n      \"role_code\": \"FM\",\n      \"default_approver_id\": {{approver_id}},\n      \"sla_hours\": 24,\n      \"is_mandatory\": true\n    }\n  ]\n}"
            }
          }
        },
        {
          "name": "Update circuit",
          "request": {
            "method": "POST",
            "url": "{{base_url}}/approval-circuits/update/{{circuit_id}}",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\": \"Circuit Premium (révisé)\",\n  \"description\": \"Mise à jour de la description.\",\n  \"is_active\": true\n}"
            }
          }
        },
        {
          "name": "Activate circuit",
          "request": { "method": "POST", "url": "{{base_url}}/approval-circuits/{{circuit_id}}/activate" }
        },
        {
          "name": "Deactivate circuit",
          "request": { "method": "POST", "url": "{{base_url}}/approval-circuits/{{circuit_id}}/deactivate" }
        },
        {
          "name": "Add step",
          "request": {
            "method": "POST",
            "url": "{{base_url}}/approval-circuits/{{circuit_id}}/steps",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"label\": \"Validation Directeur Général\",\n  \"role_code\": \"DG\",\n  \"default_approver_id\": {{approver_id}},\n  \"sla_hours\": 96,\n  \"tco_threshold_min\": 1200.00,\n  \"is_mandatory\": false\n}"
            }
          }
        },
        {
          "name": "Update step",
          "request": {
            "method": "POST",
            "url": "{{base_url}}/approval-circuits/{{circuit_id}}/steps/{{step_id}}/update",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"label\": \"Validation Manager N+1 (révisé)\",\n  \"sla_hours\": 24,\n  \"is_mandatory\": true\n}"
            }
          }
        },
        {
          "name": "Move step up",
          "request": { "method": "POST", "url": "{{base_url}}/approval-circuits/{{circuit_id}}/steps/{{step_id}}/move-up" }
        },
        {
          "name": "Move step down",
          "request": { "method": "POST", "url": "{{base_url}}/approval-circuits/{{circuit_id}}/steps/{{step_id}}/move-down" }
        },
        {
          "name": "Delete step",
          "request": { "method": "DELETE", "url": "{{base_url}}/approval-circuits/{{circuit_id}}/steps/{{step_id}}" }
        },
        {
          "name": "Reorder steps (drag-drop)",
          "request": {
            "method": "POST",
            "url": "{{base_url}}/approval-circuits/{{circuit_id}}/steps/reorder",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"step_ids\": [3, 1, 2, 4]\n}"
            }
          }
        },
        {
          "name": "Delete circuit",
          "request": { "method": "DELETE", "url": "{{base_url}}/approval-circuits/delete/{{circuit_id}}" }
        }
      ]
    },
    {
      "name": "2. Approvers (pool)",
      "description": "Approver pool — entries can be used as `default_approver_id` on circuit steps. Each approver can be temporarily delegated to another approver until a given date; delegations are honored automatically at commande submit time AND at reassignment time.",
      "item": [
        {
          "name": "List approvers + KPIs (paginated)",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{base_url}}/approvers/list?per_page=20&page=1&sort_by=name&sort_dir=asc",
              "host": ["{{base_url}}"],
              "path": ["approvers", "list"],
              "query": [
                { "key": "per_page",              "value": "20" },
                { "key": "page",                  "value": "1" },
                { "key": "sort_by",               "value": "name",   "description": "name | role | department | status" },
                { "key": "sort_dir",              "value": "asc" },
                { "key": "search",                "value": "",       "disabled": true, "description": "full-text on prenom, nom, email, department" },
                { "key": "status_filter",         "value": "active", "disabled": true, "description": "active | inactive" },
                { "key": "role_code",             "value": "MN1",    "disabled": true, "description": "narrow by role (MN1/RH/FM/DAF/DG/...)" },
                { "key": "has_active_delegation", "value": "1",      "disabled": true, "description": "true → only approvers whose delegation hasn't expired" }
              ]
            },
            "description": "Paginated table view. Response: { total, count, per_page, currentPage, lastPage, totalPages, previousPageUrl, nextPageUrl, approvers[], kpis }.\n\nFilters: search / status_filter / role_code / has_active_delegation. Sort: name | role | department | status."
          }
        },
        {
          "name": "KPIs only",
          "request": { "method": "GET", "url": "{{base_url}}/approvers/kpis" }
        },
        {
          "name": "All (dropdown for step editor)",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{base_url}}/approvers/list/all?active_only=true",
              "host": ["{{base_url}}"],
              "path": ["approvers", "list", "all"],
              "query": [
                { "key": "active_only", "value": "true" },
                { "key": "role_code",   "value": "MN1", "disabled": true, "description": "narrow to one role" }
              ]
            }
          }
        },
        {
          "name": "Show approver",
          "request": { "method": "GET", "url": "{{base_url}}/approvers/show/{{approver_id}}" }
        },
        {
          "name": "Options — roles",
          "request": { "method": "GET", "url": "{{base_url}}/approvers/options/roles" }
        },
        {
          "name": "Options — statuses",
          "request": { "method": "GET", "url": "{{base_url}}/approvers/options/statuses" }
        },
        {
          "name": "Options — sorts",
          "request": { "method": "GET", "url": "{{base_url}}/approvers/options/sorts" }
        },
        {
          "name": "Create approver (no delegation)",
          "request": {
            "method": "POST",
            "url": "{{base_url}}/approvers/store",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"prenom\": \"Sophie\",\n  \"nom\": \"Martin\",\n  \"email\": \"sophie.martin@entreprise.fr\",\n  \"role_code\": \"MN1\",\n  \"department\": \"Commercial\",\n  \"is_active\": true,\n  \"user_id\": null\n}"
            },
            "description": "Minimal body. Optional fields the BE also accepts:\n- delegated_to_approver_id (int)  — another approver's id\n- delegated_until (date YYYY-MM-DD) — required when delegated_to_approver_id is set"
          }
        },
        {
          "name": "Create approver (with delegation)",
          "request": {
            "method": "POST",
            "url": "{{base_url}}/approvers/store",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"prenom\": \"Sophie\",\n  \"nom\": \"Martin\",\n  \"email\": \"sophie.martin@entreprise.fr\",\n  \"role_code\": \"MN1\",\n  \"department\": \"Commercial\",\n  \"is_active\": true,\n  \"delegated_to_approver_id\": {{delegate_id}},\n  \"delegated_until\": \"2026-08-15\"\n}"
            },
            "description": "Creates an approver who is already delegating to another approver until the given date. The delegate id must be a valid (non-soft-deleted) approver from the same company."
          }
        },
        {
          "name": "Update approver (fields + delegation)",
          "request": {
            "method": "POST",
            "url": "{{base_url}}/approvers/update/{{approver_id}}",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"department\": \"Direction Commerciale\",\n  \"role_code\": \"MN1\",\n  \"delegated_to_approver_id\": {{delegate_id}},\n  \"delegated_until\": \"2026-10-31\"\n}"
            },
            "description": "PATCH semantics — omit any field to leave it unchanged. To clear an existing delegation, send both delegated_to_approver_id=null and delegated_until=null (or use DELETE /{approver}/delegation)."
          }
        },
        {
          "name": "Activate approver",
          "request": { "method": "POST", "url": "{{base_url}}/approvers/{{approver_id}}/activate" }
        },
        {
          "name": "Deactivate approver",
          "request": { "method": "POST", "url": "{{base_url}}/approvers/{{approver_id}}/deactivate" }
        },
        {
          "name": "Set delegation",
          "request": {
            "method": "POST",
            "url": "{{base_url}}/approvers/{{approver_id}}/delegation",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"delegated_to_approver_id\": {{delegate_id}},\n  \"delegated_until\": \"2026-06-01\"\n}"
            }
          }
        },
        {
          "name": "Clear delegation",
          "request": { "method": "DELETE", "url": "{{base_url}}/approvers/{{approver_id}}/delegation" }
        },
        {
          "name": "Delete approver",
          "request": { "method": "DELETE", "url": "{{base_url}}/approvers/delete/{{approver_id}}" }
        }
      ]
    },
    {
      "name": "3. Digest & Relances",
      "description": "Per-company digest configuration + 7-day send history. Three rules in the UI: standard frequency, urgent (SLA about to expire), escalation (SLA breached).",
      "item": [
        {
          "name": "Get config (one-shot Digest tab)",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{base_url}}/approval-digest/config",
              "host": ["{{base_url}}"],
              "path": ["approval-digest", "config"],
              "query": [
                { "key": "history_days", "value": "7", "disabled": true, "description": "1..90, default 7 — tunes the embedded history window" }
              ]
            },
            "description": "One-shot payload for the Digest tab. Returns:\n  - rules (3 config rules with chip metadata)\n  - raw config fields (standard_frequency_key, urgent_sla_remaining_hours, urgent_frequency_key, escalation_mode, escalation_role_code)\n  - pending_validators[]  (one row per approver with pending steps, with tier/SLA badge/next digest)\n  - pending_validators_kpis  ({ validators_count, pending_commandes_count, urgent_count })\n  - history.logs[] + history.kpis  (last 7 days by default; tune with ?history_days=N)\n\nFor switching the history window only, hit GET /approval-digest/history?days=N instead — it avoids reloading the whole config payload."
          }
        },
        {
          "name": "Update config",
          "request": {
            "method": "PUT",
            "url": "{{base_url}}/approval-digest/config",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"standard_frequency_key\": \"daily_8h\",\n  \"urgent_sla_remaining_hours\": 12,\n  \"urgent_frequency_key\": \"every_4h\",\n  \"escalation_mode\": \"immediate_with_role_copy\",\n  \"escalation_role_code\": \"FM\"\n}"
            }
          }
        },
        {
          "name": "History (last 7 days)",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{base_url}}/approval-digest/history?days=7",
              "host": ["{{base_url}}"],
              "path": ["approval-digest", "history"],
              "query": [{ "key": "days", "value": "7", "description": "1..90" }]
            }
          }
        },
        {
          "name": "Preview digest for one validator",
          "request": {
            "method": "GET",
            "url": "{{base_url}}/approval-digest/pending-validators/{{pending_validator_user_id}}/preview",
            "description": "Powers the 'Aperçu' button. The path id is the user_id returned in `approver_id` from /pending-validators.\n\nResponse:\n  {\n    approver_id, approver_name, role_code, role_label, role_meta,\n    pending_count,\n    commandes: [\n      {\n        commande_id, reference, collaborator_name, target_vehicle_label,\n        step_order, role_label,\n        sla_due_at, sla_remaining_hours, sla_overdue,\n        submitted_at\n      }\n    ]\n  }\n\nReturns 404 if the user has no pending steps."
          }
        },
        {
          "name": "Relancer maintenant",
          "request": {
            "method": "POST",
            "url": "{{base_url}}/approval-digest/pending-validators/{{pending_validator_user_id}}/relance",
            "description": "Powers the 'Relancer maintenant' button. Records an immediate digest send into approval_digest_logs (the actual email worker is pending — this just logs intent, response is immediate).\n\nResponse:\n  { log_id, approver_id, recipient_name, type, commandes_count, commande_ids[], sent_at }\n\nThe log appears in /approval-digest/history immediately."
          }
        },
        {
          "name": "Options — frequencies",
          "request": { "method": "GET", "url": "{{base_url}}/approval-digest/options/frequencies" }
        },
        {
          "name": "Options — types",
          "request": { "method": "GET", "url": "{{base_url}}/approval-digest/options/types" }
        },
        {
          "name": "Options — statuses",
          "request": { "method": "GET", "url": "{{base_url}}/approval-digest/options/statuses" }
        }
      ]
    },
    {
      "name": "4. Commande integration",
      "description": "Two existing commande endpoints that now consume the new Approver pool. `reassignable-approvers` returns both the legacy auth-service users AND the pool (delegation-resolved). `reassign` accepts either `approver_id` (user) or `approver_pool_id` (pool entry).",
      "item": [
        {
          "name": "Reassignable approvers (now includes pool)",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{base_url}}/commandes/{{commande_id}}/reassignable-approvers",
              "host": ["{{base_url}}"],
              "path": ["commandes", "{{commande_id}}", "reassignable-approvers"],
              "query": [
                { "key": "all_roles", "value": "1", "disabled": true, "description": "set to widen beyond current step's role" }
              ]
            },
            "description": "Response shape:\n  {\n    current_approver_id: int|null,\n    current_role_code: string|null,    // role of the step the FE is reassigning\n    approvers: [...],                  // legacy auth-service users (unchanged contract)\n    pool_approvers: [                  // new: Approver-pool entries, delegation-resolved\n      {\n        approver_id, effective_approver_id, effective_user_id,\n        name, effective_name, email,\n        role_code, role_label, department,\n        has_active_delegation, delegated_until,\n        is_match_for_current_step\n      }\n    ]\n  }\n\nBy default `pool_approvers` is filtered to entries matching `current_role_code` (same-role swap). Pass `?all_roles=1` to disable that filter."
          }
        },
        {
          "name": "Reassign — via plain user (legacy)",
          "request": {
            "method": "POST",
            "url": "{{base_url}}/commandes/{{commande_id}}/reassign",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"approver_id\": 42,\n  \"raison\": \"Absence congés\"\n}"
            }
          }
        },
        {
          "name": "Reassign — via approver pool (delegation-aware)",
          "request": {
            "method": "POST",
            "url": "{{base_url}}/commandes/{{commande_id}}/reassign",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"approver_pool_id\": {{approver_id}},\n  \"raison\": \"Réassignation depuis le pool d'approbateurs\"\n}"
            }
          }
        }
      ]
    }
  ]
}
