Aller au contenu principal

Validation d'un Cycle

Endpoints pour gérer le workflow de validation multi-niveaux des cycles de paiement.

Niveaux de validation

NiveauRôleDescription
0Non soumisCycle en préparation (brouillon)
1AgentValidation initiale
2SuperviseurValidation intermédiaire
3DirecteurValidation avancée
4Direction GénéraleValidation finale

Le nombre de niveaux requis est configurable par programme (par défaut: 2).


POST /api/cycles/{id}/soumettre

Soumet le cycle pour validation.

Endpoint

POST /api/cycles/{id}/soumettre

Headers

HeaderValeurRequis
AuthorizationBearer {token}Oui

Prérequis

  • Le cycle doit être en statut brouillon
  • Le cycle doit avoir des bénéficiaires calculés

Réponse succès

Code: 200 OK

{
"success": true,
"statutValidation": "en_attente",
"niveauValidation": 0,
"prochainNiveau": "Agent",
"message": "Cycle soumis pour validation"
}

Exemple cURL

curl -X POST https://sig.ucp-pch.org/api/cycles/770e8400-e29b-41d4-a716-446655440003/soumettre \
-H "Authorization: Bearer TOKEN"

POST /api/cycles/{id}/valider

Valide le cycle au niveau actuel.

Endpoint

POST /api/cycles/{id}/valider

Corps de la requête

{
"commentaire": "Validé après vérification des bénéficiaires"
}

Champs

ChampTypeRequisDescription
commentairestringNonCommentaire de validation

Réponse succès

Code: 200 OK

{
"success": true,
"statutValidation": "valide",
"niveauValidation": 2,
"niveauxRequis": 2,
"estCompletementValide": true,
"message": "Cycle validé - Validation complète"
}

Réponse succès (validation partielle)

{
"success": true,
"statutValidation": "en_attente",
"niveauValidation": 1,
"niveauxRequis": 2,
"estCompletementValide": false,
"prochainNiveau": "Superviseur",
"message": "Cycle validé au niveau Agent - En attente validation Superviseur"
}

Exemple cURL

curl -X POST https://sig.ucp-pch.org/api/cycles/770e8400-e29b-41d4-a716-446655440003/valider \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json" \
-d '{"commentaire": "Validé"}'

POST /api/cycles/{id}/rejeter

Rejette le cycle.

Endpoint

POST /api/cycles/{id}/rejeter

Corps de la requête

{
"motif": "Incohérence dans le nombre de bénéficiaires"
}

Champs

ChampTypeRequisDescription
motifstringOuiMotif du rejet

Réponse succès

Code: 200 OK

{
"success": true,
"statutValidation": "rejete",
"niveauValidation": 1,
"message": "Cycle rejeté"
}

Exemple cURL

curl -X POST https://sig.ucp-pch.org/api/cycles/770e8400-e29b-41d4-a716-446655440003/rejeter \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json" \
-d '{"motif": "Incohérence dans le nombre de bénéficiaires"}'

GET /api/cycles/{id}/historique-validations

Récupère l'historique des validations du cycle.

Endpoint

GET /api/cycles/{id}/historique-validations

Réponse succès

Code: 200 OK

{
"cycle": {
"id": "770e8400-e29b-41d4-a716-446655440003",
"code": "CYC-2024-003",
"nom": "Cycle Mars 2024"
},
"statutValidation": "valide",
"niveauValidation": 2,
"niveauxRequis": 2,
"historique": [
{
"action": "soumission",
"niveau": 0,
"niveauLabel": "Non soumis",
"user": "agent@pch-sig.sn",
"userName": "Agent Terrain",
"date": "2024-02-20T10:00:00+00:00",
"commentaire": null
},
{
"action": "validation",
"niveau": 1,
"niveauLabel": "Agent",
"user": "superviseur@pch-sig.sn",
"userName": "Superviseur PCH",
"date": "2024-02-20T11:00:00+00:00",
"commentaire": "Conforme"
},
{
"action": "validation",
"niveau": 2,
"niveauLabel": "Superviseur",
"user": "directeur@pch-sig.sn",
"userName": "Directeur PCH",
"date": "2024-02-20T14:00:00+00:00",
"commentaire": "Approuvé pour exécution"
}
]
}

POST /api/cycles/{id}/reinitialiser-validation

Réinitialise la validation (retour au statut brouillon).

Endpoint

POST /api/cycles/{id}/reinitialiser-validation

Prérequis

  • Le cycle ne doit pas être en cours d'exécution
  • Permission spéciale requise

Réponse succès

Code: 200 OK

{
"success": true,
"statutValidation": "brouillon",
"niveauValidation": 0,
"message": "Validation réinitialisée"
}

Exemples complets

JavaScript

class CycleValidationAPI {
constructor(token) {
this.token = token;
this.baseUrl = 'https://sig.ucp-pch.org/api';
}

async getCycle(cycleId) {
const response = await fetch(
`${this.baseUrl}/cycles/${cycleId}`,
{
headers: { 'Authorization': `Bearer ${this.token}` }
}
);
return response.json();
}

async soumettre(cycleId) {
const response = await fetch(
`${this.baseUrl}/cycles/${cycleId}/soumettre`,
{
method: 'POST',
headers: { 'Authorization': `Bearer ${this.token}` }
}
);
return response.json();
}

async valider(cycleId, commentaire = null) {
const response = await fetch(
`${this.baseUrl}/cycles/${cycleId}/valider`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${this.token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ commentaire })
}
);
return response.json();
}

async rejeter(cycleId, motif) {
const response = await fetch(
`${this.baseUrl}/cycles/${cycleId}/rejeter`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${this.token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ motif })
}
);
return response.json();
}

async getHistorique(cycleId) {
const response = await fetch(
`${this.baseUrl}/cycles/${cycleId}/historique-validations`,
{
headers: { 'Authorization': `Bearer ${this.token}` }
}
);
return response.json();
}
}

// Utilisation - Workflow complet
const api = new CycleValidationAPI(token);
const cycleId = '770e8400-e29b-41d4-a716-446655440003';

// 1. Soumettre
await api.soumettre(cycleId);

// 2. Validation niveau 1
let result = await api.valider(cycleId, 'Validé par Agent');
console.log(`Niveau: ${result.niveauValidation}/${result.niveauxRequis}`);

// 3. Validation niveau 2 (si requis)
if (!result.estCompletementValide) {
result = await api.valider(cycleId, 'Validé par Superviseur');
}

// Vérifier l'historique
const historique = await api.getHistorique(cycleId);
historique.historique.forEach(entry => {
console.log(`${entry.date}: ${entry.action} par ${entry.userName}`);
});

Python

import requests

class CycleValidationAPI:
def __init__(self, token):
self.token = token
self.base_url = 'https://sig.ucp-pch.org/api'
self.headers = {'Authorization': f'Bearer {token}'}

def soumettre(self, cycle_id):
response = requests.post(
f'{self.base_url}/cycles/{cycle_id}/soumettre',
headers=self.headers
)
return response.json()

def valider(self, cycle_id, commentaire=None):
response = requests.post(
f'{self.base_url}/cycles/{cycle_id}/valider',
headers={**self.headers, 'Content-Type': 'application/json'},
json={'commentaire': commentaire}
)
return response.json()

def rejeter(self, cycle_id, motif):
response = requests.post(
f'{self.base_url}/cycles/{cycle_id}/rejeter',
headers={**self.headers, 'Content-Type': 'application/json'},
json={'motif': motif}
)
return response.json()

def get_historique(self, cycle_id):
response = requests.get(
f'{self.base_url}/cycles/{cycle_id}/historique-validations',
headers=self.headers
)
return response.json()

# Utilisation
api = CycleValidationAPI(token)

# Workflow de validation
api.soumettre(cycle_id)

# Valider jusqu'à complétion
while True:
result = api.valider(cycle_id, 'Validation automatique')
print(f"Niveau {result['niveauValidation']}/{result['niveauxRequis']}")
if result['estCompletementValide']:
print("Cycle complètement validé!")
break

# Afficher l'historique
historique = api.get_historique(cycle_id)
for entry in historique['historique']:
print(f"- {entry['niveauLabel']}: {entry['action']} par {entry['userName']}")

Diagramme de workflow

┌─────────────┐     POST /soumettre     ┌─────────────┐
│ brouillon │ ──────────────────────▶ │ en_attente │
└─────────────┘ └──────┬──────┘

POST /valider │ POST /rejeter
┌────────────────┼────────────────┐
│ │ │
▼ │ ▼
┌─────────────┐ │ ┌───────────┐
│ Niveau N │ │ │ rejete │
│ validé │ │ └───────────┘
└──────┬──────┘ │
│ │
niveauValidation │ │
< niveauxRequis │ │
│ │
┌──────┴──────┐ │
│ │ │
▼ ▼ │
┌─────────────┐ ┌─────────┐ │
│ en_attente │ │ valide │ │
│ niveau N+1 │ │ complet │ │
└─────────────┘ └─────────┘ │
│ │
└────────────────────────┘

Notes

  • La validation est multi-niveaux et configurable
  • Chaque niveau nécessite un utilisateur avec les permissions appropriées
  • L'historique complet des validations est conservé
  • Un cycle rejeté peut être modifié et re-soumis
  • Le nombre de niveaux requis est défini à la création du cycle