fix: conformité stricte skill itinova-user-management
- Rôles : remplacement admin/approbateur/validateur/operateur → admin/standard/readonly - schema.ts, migrate.ts : ENUM MySQL mis à jour (3 rôles skill) - routes/auth.ts : rôle par défaut standard, validRoles, modèle CSV corrigé - routes/invoices.ts : permissions readonly/standard/admin - routes/dashboard.ts : compteurs dashboard selon standard/admin - frontend/types/index.ts : type User role mis à jour - frontend/utils/helpers.ts : roleLabels admin/standard/readonly - frontend/pages/InvoiceDetail.tsx : actions disponibles selon standard/readonly/admin - frontend/pages/UserList.tsx : rôle par défaut standard, labels import corrigés
This commit is contained in:
@@ -101,13 +101,17 @@ export default function InvoiceDetail() {
|
||||
const role = user.role;
|
||||
const s = invoice.status;
|
||||
|
||||
if (s === 'recue' && ['operateur', 'validateur', 'approbateur', 'admin'].includes(role)) {
|
||||
// Permissions selon le skill itinova-user-management (admin / standard / readonly)
|
||||
// readonly : aucune action disponible
|
||||
// standard : droits métiers complets (vérification, validation, approbation, rejet)
|
||||
// admin : tous les droits y compris paiement et archivage
|
||||
if (s === 'recue' && ['standard', 'admin'].includes(role)) {
|
||||
actions.push({ status: 'en_verification', label: 'Passer en vérification', color: 'btn-primary' });
|
||||
}
|
||||
if (s === 'en_verification' && ['validateur', 'approbateur', 'admin'].includes(role)) {
|
||||
if (s === 'en_verification' && ['standard', 'admin'].includes(role)) {
|
||||
actions.push({ status: 'validee', label: 'Valider', color: 'btn-success' });
|
||||
}
|
||||
if (s === 'validee' && ['approbateur', 'admin'].includes(role)) {
|
||||
if (s === 'validee' && ['standard', 'admin'].includes(role)) {
|
||||
actions.push({ status: 'approuvee', label: 'Approuver', color: 'btn-success' });
|
||||
}
|
||||
if (s === 'approuvee' && role === 'admin') {
|
||||
@@ -116,10 +120,10 @@ export default function InvoiceDetail() {
|
||||
if (s === 'payee' && role === 'admin') {
|
||||
actions.push({ status: 'archivee', label: 'Archiver', color: 'btn-secondary' });
|
||||
}
|
||||
if (!['payee', 'archivee', 'rejetee'].includes(s) && ['validateur', 'approbateur', 'admin'].includes(role)) {
|
||||
if (!['payee', 'archivee', 'rejetee'].includes(s) && ['standard', 'admin'].includes(role)) {
|
||||
actions.push({ status: 'rejetee', label: 'Rejeter', color: 'btn-danger' });
|
||||
}
|
||||
if (s === 'rejetee' && ['operateur', 'validateur', 'approbateur', 'admin'].includes(role)) {
|
||||
if (s === 'rejetee' && ['standard', 'admin'].includes(role)) {
|
||||
actions.push({ status: 'recue', label: 'Remettre en réception', color: 'btn-secondary' });
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ export default function UserList() {
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const [form, setForm] = useState({
|
||||
email: '', password: '', firstName: '', lastName: '', role: 'operateur',
|
||||
email: '', password: '', firstName: '', lastName: '', role: 'standard',
|
||||
});
|
||||
|
||||
useEffect(() => { loadUsers(); }, []);
|
||||
@@ -41,7 +41,7 @@ export default function UserList() {
|
||||
|
||||
const openCreate = () => {
|
||||
setEditingUser(null);
|
||||
setForm({ email: '', password: '', firstName: '', lastName: '', role: 'operateur' });
|
||||
setForm({ email: '', password: '', firstName: '', lastName: '', role: 'standard' });
|
||||
setShowModal(true);
|
||||
};
|
||||
|
||||
@@ -242,7 +242,7 @@ export default function UserList() {
|
||||
<p className="font-semibold mb-1">Format attendu (colonnes) :</p>
|
||||
<code className="text-xs bg-blue-100 px-2 py-1 rounded">email, prenom, nom, role</code>
|
||||
<p className="mt-2 text-xs">
|
||||
Roles : <strong>admin</strong>, <strong>approbateur</strong>, <strong>validateur</strong>, <strong>operateur</strong> (défaut si vide).
|
||||
Profils : <strong>admin</strong>, <strong>standard</strong>, <strong>readonly</strong> (défaut : <strong>standard</strong> si vide).
|
||||
</p>
|
||||
<p className="text-xs mt-1">
|
||||
Utilisateurs existants (même email) : mis à jour. Nouveaux : mot de passe temporaire généré.
|
||||
|
||||
Reference in New Issue
Block a user