{ "description": "Finance Workflow - Exemples de requêtes API pour tests", "baseUrl": "http://localhost:8085", "note": "Ces exemples peuvent être utilisés dans Swagger UI, Postman, ou curl", "authentication": { "note": "Si JWT requis, utilisez Keycloak pour obtenir un token", "keycloakUrl": "http://localhost:8180/realms/unionflow/protocol/openid-connect/token", "exampleToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." }, "tests": [ { "id": "TEST-01", "name": "Lister les approbations en attente", "method": "GET", "endpoint": "/api/finance/approvals/pending", "description": "Récupère toutes les approbations en attente pour une organisation", "queryParams": { "organizationId": "00000000-0000-0000-0000-000000000001" }, "expectedStatus": [200, 401, 403], "expectedResponse": { "success_empty": [], "success_with_data": [ { "id": "uuid", "transactionId": "uuid", "transactionType": "CONTRIBUTION", "amount": 50000.00, "currency": "XOF", "requesterId": "uuid", "requesterName": "Jean Dupont", "organizationId": "uuid", "requiredLevel": "LEVEL1", "status": "PENDING", "approvers": [], "createdAt": "2026-03-14T00:00:00", "expiresAt": "2026-03-21T00:00:00", "approvalCount": 0, "requiredApprovals": 1, "hasAllApprovals": false, "isExpired": false, "isPending": true, "isCompleted": false } ] } }, { "id": "TEST-02", "name": "Récupérer une approbation par ID", "method": "GET", "endpoint": "/api/finance/approvals/{approvalId}", "description": "Récupère les détails d'une approbation spécifique", "pathParams": { "approvalId": "00000000-0000-0000-0000-000000000001" }, "expectedStatus": [200, 404], "expectedResponse": { "success": { "id": "uuid", "transactionId": "uuid", "transactionType": "CONTRIBUTION", "amount": 50000.00, "status": "PENDING" }, "error_404": { "message": "Approbation non trouvée: {approvalId}" } } }, { "id": "TEST-03", "name": "Approuver une transaction", "method": "POST", "endpoint": "/api/finance/approvals/{approvalId}/approve", "description": "Approuve une transaction en attente", "authRequired": true, "pathParams": { "approvalId": "00000000-0000-0000-0000-000000000001" }, "requestBody": { "comment": "Approuvé après vérification des documents" }, "expectedStatus": [200, 400, 403, 404], "expectedResponse": { "success": { "id": "uuid", "status": "VALIDATED", "approvalCount": 1, "hasAllApprovals": true, "completedAt": "2026-03-14T10:30:00" }, "error_403_self_approval": { "message": "Un utilisateur ne peut pas approuver sa propre demande" }, "error_400_expired": { "message": "Cette approbation est expirée" } } }, { "id": "TEST-04", "name": "Rejeter une transaction", "method": "POST", "endpoint": "/api/finance/approvals/{approvalId}/reject", "description": "Rejette une transaction avec une raison obligatoire", "authRequired": true, "pathParams": { "approvalId": "00000000-0000-0000-0000-000000000001" }, "requestBody": { "reason": "Montant trop élevé, nécessite révision du budget avant approbation" }, "expectedStatus": [200, 400, 404], "expectedResponse": { "success": { "id": "uuid", "status": "REJECTED", "rejectionReason": "Montant trop élevé...", "completedAt": "2026-03-14T10:30:00" }, "error_400_short_reason": { "message": "La raison doit contenir entre 10 et 1000 caractères" } } }, { "id": "TEST-05", "name": "Historique des approbations", "method": "GET", "endpoint": "/api/finance/approvals/history", "description": "Récupère l'historique avec filtres optionnels", "queryParams": { "organizationId": "00000000-0000-0000-0000-000000000001", "startDate": "2026-03-01T00:00:00", "endDate": "2026-03-14T23:59:59", "status": "APPROVED" }, "expectedStatus": [200], "expectedResponse": { "success": [ { "id": "uuid", "status": "APPROVED", "completedAt": "2026-03-10T14:30:00" } ] } }, { "id": "TEST-06", "name": "Compter les approbations en attente", "method": "GET", "endpoint": "/api/finance/approvals/count/pending", "description": "Retourne le nombre d'approbations en attente", "queryParams": { "organizationId": "00000000-0000-0000-0000-000000000001" }, "expectedStatus": [200], "expectedResponse": { "success": 5 } }, { "id": "TEST-07", "name": "Lister les budgets", "method": "GET", "endpoint": "/api/finance/budgets", "description": "Liste tous les budgets avec filtres optionnels", "queryParams": { "organizationId": "00000000-0000-0000-0000-000000000001", "status": "ACTIVE", "year": 2026 }, "expectedStatus": [200], "expectedResponse": { "success": [ { "id": "uuid", "name": "Budget Q1 2026", "period": "QUARTERLY", "year": 2026, "status": "ACTIVE", "totalPlanned": 10000000.00, "totalRealized": 8500000.00, "currency": "XOF", "realizationRate": 85.0, "variance": -1500000.00, "isOverBudget": false } ] } }, { "id": "TEST-08", "name": "Créer un budget mensuel", "method": "POST", "endpoint": "/api/finance/budgets", "description": "Crée un nouveau budget avec lignes budgétaires", "authRequired": true, "requestBody": { "name": "Budget Mars 2026", "description": "Budget mensuel pour le mois de mars", "organizationId": "00000000-0000-0000-0000-000000000001", "period": "MONTHLY", "year": 2026, "month": 3, "currency": "XOF", "lines": [ { "category": "CONTRIBUTIONS", "name": "Cotisations mensuelles", "description": "Cotisations des membres actifs", "amountPlanned": 2000000.00, "notes": "Basé sur 40 membres à 50000 XOF" }, { "category": "SAVINGS", "name": "Épargne collective", "description": "Épargne pour projets futurs", "amountPlanned": 1000000.00 }, { "category": "OPERATIONAL", "name": "Frais opérationnels", "description": "Loyer, électricité, etc.", "amountPlanned": 500000.00 } ] }, "expectedStatus": [200, 400, 404], "expectedResponse": { "success": { "id": "uuid", "name": "Budget Mars 2026", "period": "MONTHLY", "year": 2026, "month": 3, "startDate": "2026-03-01", "endDate": "2026-03-31", "totalPlanned": 3500000.00, "totalRealized": 0.00, "lines": [ { "category": "CONTRIBUTIONS", "amountPlanned": 2000000.00 } ] }, "error_400_monthly_without_month": { "message": "Le mois est requis pour un budget MONTHLY" } } }, { "id": "TEST-09", "name": "Créer un budget trimestriel", "method": "POST", "endpoint": "/api/finance/budgets", "description": "Budget pour un trimestre (Q1, Q2, Q3, Q4)", "authRequired": true, "requestBody": { "name": "Budget Q2 2026", "description": "Budget deuxième trimestre 2026", "organizationId": "00000000-0000-0000-0000-000000000001", "period": "QUARTERLY", "year": 2026, "month": 4, "currency": "XOF", "lines": [ { "category": "CONTRIBUTIONS", "name": "Cotisations trimestrielles", "amountPlanned": 6000000.00 }, { "category": "EVENTS", "name": "Événements du trimestre", "amountPlanned": 2000000.00 } ] }, "expectedStatus": [200], "expectedResponse": { "success": { "period": "QUARTERLY", "startDate": "2026-04-01", "endDate": "2026-06-30" } } }, { "id": "TEST-10", "name": "Suivi budgétaire (tracking)", "method": "GET", "endpoint": "/api/finance/budgets/{budgetId}/tracking", "description": "Retourne les métriques de suivi d'un budget", "pathParams": { "budgetId": "00000000-0000-0000-0000-000000000001" }, "expectedStatus": [200, 404], "expectedResponse": { "success": { "budgetId": "uuid", "budgetName": "Budget Q1 2026", "trackingByCategory": [ { "category": "CONTRIBUTIONS", "planned": 5000000.00, "realized": 4500000.00, "realizationRate": 90.0, "variance": -500000.00, "isOverBudget": false }, { "category": "EVENTS", "planned": 3000000.00, "realized": 3200000.00, "realizationRate": 106.67, "variance": 200000.00, "isOverBudget": true } ], "topVariances": [ { "category": "CONTRIBUTIONS", "variance": -500000.00 }, { "category": "EVENTS", "variance": 200000.00 } ], "overallRealizationRate": 95.0 } } } ], "validationTests": [ { "id": "VAL-01", "name": "Validation - Raison de rejet trop courte", "method": "POST", "endpoint": "/api/finance/approvals/{approvalId}/reject", "requestBody": { "reason": "Court" }, "expectedStatus": [400], "expectedError": { "field": "reason", "message": "La raison doit contenir entre 10 et 1000 caractères" } }, { "id": "VAL-02", "name": "Validation - Budget sans lignes", "method": "POST", "endpoint": "/api/finance/budgets", "requestBody": { "name": "Budget vide", "organizationId": "uuid", "period": "MONTHLY", "year": 2026, "month": 3, "currency": "XOF", "lines": [] }, "expectedStatus": [400], "expectedError": { "field": "lines", "message": "ne doit pas être vide" } } ] }