Skip to main content

Cycle Validation

Endpoints for managing the multi-level validation workflow of payment cycles.

Validation Levels

LevelRoleDescription
0Not submittedCycle in preparation (draft)
1AgentInitial validation
2SupervisorIntermediate validation
3DirectorAdvanced validation
4General ManagementFinal validation

The number of required levels is configurable per program (default: 2).


POST /api/cycles/{id}/soumettre

Submits the cycle for validation.

Endpoint

POST /api/cycles/{id}/soumettre

Headers

HeaderValueRequired
AuthorizationBearer {token}Yes

Prerequisites

  • The cycle must be in brouillon status
  • The cycle must have calculated beneficiaries

Success Response

Code: 200 OK

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

cURL Example

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

Validates the cycle at the current level.

Endpoint

POST /api/cycles/{id}/valider

Request Body

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

Fields

FieldTypeRequiredDescription
commentairestringNoValidation comment

Success Response

Code: 200 OK

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

Success Response (partial validation)

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

cURL Example

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

Rejects the cycle.

Endpoint

POST /api/cycles/{id}/rejeter

Request Body

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

Fields

FieldTypeRequiredDescription
motifstringYesRejection reason

Success Response

Code: 200 OK

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

cURL Example

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

Retrieves the cycle's validation history.

Endpoint

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

Success Response

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

Resets validation (returns to draft status).

Endpoint

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

Prerequisites

  • The cycle must not be in execution
  • Special permission required

Success Response

Code: 200 OK

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

Complete Examples

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();
}
}

// Usage - Complete workflow
const api = new CycleValidationAPI(token);
const cycleId = '770e8400-e29b-41d4-a716-446655440003';

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

// 2. Level 1 validation
let result = await api.valider(cycleId, 'Validated by Agent');
console.log(`Level: ${result.niveauValidation}/${result.niveauxRequis}`);

// 3. Level 2 validation (if required)
if (!result.estCompletementValide) {
result = await api.valider(cycleId, 'Validated by Supervisor');
}

// Check history
const historique = await api.getHistorique(cycleId);
historique.historique.forEach(entry => {
console.log(`${entry.date}: ${entry.action} by ${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()

# Usage
api = CycleValidationAPI(token)

# Validation workflow
api.soumettre(cycle_id)

# Validate until complete
while True:
result = api.valider(cycle_id, 'Automatic validation')
print(f"Level {result['niveauValidation']}/{result['niveauxRequis']}")
if result['estCompletementValide']:
print("Cycle fully validated!")
break

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

Workflow Diagram

+--------------+     POST /soumettre     +--------------+
| brouillon | ----------------------> | en_attente |
+--------------+ +------+-------+
|
POST /valider | POST /rejeter
+-----------------+-----------------+
| | |
v | v
+--------------+ | +----------+
| Level N | | | rejete |
| validated | | +----------+
+------+-------+ |
| |
niveauValidation | |
< niveauxRequis | |
| |
+------+------+ |
| | |
v v |
+--------------+ +----------+ |
| en_attente | | valide | |
| level N+1 | | complete | |
+--------------+ +----------+ |
| |
+-------------------------+

Notes

  • Validation is multi-level and configurable
  • Each level requires a user with appropriate permissions
  • Complete validation history is maintained
  • A rejected cycle can be modified and re-submitted
  • The number of required levels is defined at cycle creation