feat: add DCB User Service API - Authentication system with KEYCLOAK - Modular architecture with services for each feature
This commit is contained in:
parent
8d7fdb27ea
commit
822d349ffc
@ -18,7 +18,7 @@ export class HasRoleDirective implements OnDestroy {
|
|||||||
const userRoles = this.authService.getCurrentUserRoles();
|
const userRoles = this.authService.getCurrentUserRoles();
|
||||||
|
|
||||||
const hasAccess = requiredRoles.some(role => userRoles.includes(
|
const hasAccess = requiredRoles.some(role => userRoles.includes(
|
||||||
UserRole.DCB_ADMIN || UserRole.DCB_PARTNER || UserRole.DCB_SUPPORT
|
UserRole.DCB_ADMIN || UserRole.DCB_SUPPORT
|
||||||
|| UserRole.DCB_PARTNER_ADMIN || UserRole.DCB_PARTNER_MANAGER || UserRole.DCB_PARTNER_SUPPORT
|
|| UserRole.DCB_PARTNER_ADMIN || UserRole.DCB_PARTNER_MANAGER || UserRole.DCB_PARTNER_SUPPORT
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|||||||
@ -5,12 +5,11 @@ export enum UserType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export enum UserRole {
|
export enum UserRole {
|
||||||
// Rôles Hub (sans merchantPartnerId)
|
// Rôles Hub
|
||||||
DCB_ADMIN = 'dcb-admin',
|
DCB_ADMIN = 'dcb-admin',
|
||||||
DCB_SUPPORT = 'dcb-support',
|
DCB_SUPPORT = 'dcb-support',
|
||||||
DCB_PARTNER = 'dcb-partner', // Propriétaire de merchants
|
|
||||||
|
|
||||||
// Rôles Merchant Partner (avec merchantPartnerId obligatoire = ID du DCB_PARTNER)
|
// Rôles Merchant User
|
||||||
DCB_PARTNER_ADMIN = 'dcb-partner-admin',
|
DCB_PARTNER_ADMIN = 'dcb-partner-admin',
|
||||||
DCB_PARTNER_MANAGER = 'dcb-partner-manager',
|
DCB_PARTNER_MANAGER = 'dcb-partner-manager',
|
||||||
DCB_PARTNER_SUPPORT = 'dcb-partner-support',
|
DCB_PARTNER_SUPPORT = 'dcb-partner-support',
|
||||||
@ -58,12 +57,8 @@ export interface User {
|
|||||||
emailVerified: boolean;
|
emailVerified: boolean;
|
||||||
userType: UserType; // HUB ou MERCHANT_PARTNER
|
userType: UserType; // HUB ou MERCHANT_PARTNER
|
||||||
|
|
||||||
// C'est l'ID du "merchant" (DCB_PARTNER) qui est propriétaire
|
|
||||||
merchantPartnerId?: string; // Référence à l'ID Keycloak du DCB_PARTNER
|
|
||||||
|
|
||||||
role: UserRole;
|
role: UserRole;
|
||||||
// Merchant Config - Stocker l'ID du merchant dans l'autre système
|
|
||||||
merchantConfigId?: string; // ID INT dans Merchant Config pour CE merchant
|
|
||||||
createdBy?: string;
|
createdBy?: string;
|
||||||
createdByUsername?: string;
|
createdByUsername?: string;
|
||||||
createdTimestamp: number;
|
createdTimestamp: number;
|
||||||
@ -89,8 +84,6 @@ export interface CreateUserDto {
|
|||||||
role: UserRole;
|
role: UserRole;
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
emailVerified?: boolean;
|
emailVerified?: boolean;
|
||||||
merchantPartnerId?: string;
|
|
||||||
merchantConfigId?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UpdateUserDto {
|
export interface UpdateUserDto {
|
||||||
@ -149,8 +142,6 @@ export interface SearchUsersParams {
|
|||||||
role?: UserRole;
|
role?: UserRole;
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
userType?: UserType;
|
userType?: UserType;
|
||||||
merchantPartnerId?: string;
|
|
||||||
merchantConfigId?: string;
|
|
||||||
page?: number;
|
page?: number;
|
||||||
limit?: number;
|
limit?: number;
|
||||||
}
|
}
|
||||||
@ -161,7 +152,7 @@ export class UserUtils {
|
|||||||
return user.userType === UserType.HUB;
|
return user.userType === UserType.HUB;
|
||||||
}
|
}
|
||||||
|
|
||||||
static isMerchantPartnerUser(user: User): boolean {
|
static isMerchantUser(user: User): boolean {
|
||||||
return user.userType === UserType.MERCHANT_PARTNER;
|
return user.userType === UserType.MERCHANT_PARTNER;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,7 +165,7 @@ export class UserUtils {
|
|||||||
const roleNames = {
|
const roleNames = {
|
||||||
[UserRole.DCB_ADMIN]: 'DCB Admin',
|
[UserRole.DCB_ADMIN]: 'DCB Admin',
|
||||||
[UserRole.DCB_SUPPORT]: 'DCB Support',
|
[UserRole.DCB_SUPPORT]: 'DCB Support',
|
||||||
[UserRole.DCB_PARTNER]: 'DCB Partner',
|
|
||||||
[UserRole.DCB_PARTNER_ADMIN]: 'Partner Admin',
|
[UserRole.DCB_PARTNER_ADMIN]: 'Partner Admin',
|
||||||
[UserRole.DCB_PARTNER_MANAGER]: 'Partner Manager',
|
[UserRole.DCB_PARTNER_MANAGER]: 'Partner Manager',
|
||||||
[UserRole.DCB_PARTNER_SUPPORT]: 'Partner Support',
|
[UserRole.DCB_PARTNER_SUPPORT]: 'Partner Support',
|
||||||
@ -209,21 +200,12 @@ export class UserUtils {
|
|||||||
static validateUserCreation(user: CreateUserDto): string[] {
|
static validateUserCreation(user: CreateUserDto): string[] {
|
||||||
const errors: string[] = [];
|
const errors: string[] = [];
|
||||||
|
|
||||||
// Validation merchantPartnerId
|
|
||||||
if (user.userType === UserType.MERCHANT_PARTNER && !user.merchantPartnerId) {
|
|
||||||
errors.push('merchantPartnerId est obligatoire pour les utilisateurs Merchant Partner');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (user.userType === UserType.HUB && user.merchantPartnerId) {
|
|
||||||
errors.push('merchantPartnerId ne doit pas être défini pour les utilisateurs Hub');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!user.role) {
|
if (!user.role) {
|
||||||
errors.push('Un rôle doit être assigné');
|
errors.push('Un rôle doit être assigné');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validation cohérence rôle/type
|
// Validation cohérence rôle/type
|
||||||
const hubRoles = [UserRole.DCB_ADMIN, UserRole.DCB_SUPPORT, UserRole.DCB_PARTNER];
|
const hubRoles = [UserRole.DCB_ADMIN, UserRole.DCB_SUPPORT]
|
||||||
const merchantRoles = [UserRole.DCB_PARTNER_ADMIN, UserRole.DCB_PARTNER_MANAGER, UserRole.DCB_PARTNER_SUPPORT];
|
const merchantRoles = [UserRole.DCB_PARTNER_ADMIN, UserRole.DCB_PARTNER_MANAGER, UserRole.DCB_PARTNER_SUPPORT];
|
||||||
|
|
||||||
if (user.userType === UserType.HUB && user.role) {
|
if (user.userType === UserType.HUB && user.role) {
|
||||||
|
|||||||
@ -5,16 +5,16 @@ export enum UserType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export enum UserRole {
|
export enum UserRole {
|
||||||
// Rôles Hub (sans merchantPartnerId)
|
// Rôles Hub
|
||||||
DCB_ADMIN = 'dcb-admin',
|
DCB_ADMIN = 'dcb-admin',
|
||||||
DCB_SUPPORT = 'dcb-support',
|
DCB_SUPPORT = 'dcb-support',
|
||||||
DCB_PARTNER = 'dcb-partner',
|
|
||||||
|
|
||||||
// Rôles Merchant Partner (avec merchantPartnerId obligatoire)
|
// Rôles Merchant User
|
||||||
DCB_PARTNER_ADMIN = 'dcb-partner-admin',
|
DCB_PARTNER_ADMIN = 'dcb-partner-admin',
|
||||||
DCB_PARTNER_MANAGER = 'dcb-partner-manager',
|
DCB_PARTNER_MANAGER = 'dcb-partner-manager',
|
||||||
DCB_PARTNER_SUPPORT = 'dcb-partner-support',
|
DCB_PARTNER_SUPPORT = 'dcb-partner-support',
|
||||||
|
|
||||||
|
// Rôles de configuration Marchand (MerchantConfig)
|
||||||
MERCHANT_CONFIG_ADMIN = 'ADMIN',
|
MERCHANT_CONFIG_ADMIN = 'ADMIN',
|
||||||
MERCHANT_CONFIG_MANAGER = 'MANAGER',
|
MERCHANT_CONFIG_MANAGER = 'MANAGER',
|
||||||
MERCHANT_CONFIG_TECHNICAL = 'TECHNICAL',
|
MERCHANT_CONFIG_TECHNICAL = 'TECHNICAL',
|
||||||
@ -65,6 +65,9 @@ export interface MerchantUser {
|
|||||||
firstName?: string;
|
firstName?: string;
|
||||||
lastName?: string;
|
lastName?: string;
|
||||||
merchantPartnerId?: number
|
merchantPartnerId?: number
|
||||||
|
merchantConfigId?: string; // Référence au merchant dans MerchantConfig
|
||||||
|
createdAt?: string;
|
||||||
|
updatedAt?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Merchant {
|
export interface Merchant {
|
||||||
@ -111,6 +114,9 @@ export interface ApiMerchantUser {
|
|||||||
firstName?: string;
|
firstName?: string;
|
||||||
lastName?: string;
|
lastName?: string;
|
||||||
merchantPartnerId?: number;
|
merchantPartnerId?: number;
|
||||||
|
merchantConfigId?: string;
|
||||||
|
createdAt?: string;
|
||||||
|
updatedAt?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ApiMerchant {
|
export interface ApiMerchant {
|
||||||
@ -147,6 +153,14 @@ export interface UpdateMerchantConfigDto {
|
|||||||
operatorId?: Operator | 1;
|
operatorId?: Operator | 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DTO mise à jour d'un contact technique
|
||||||
|
export interface UpdateTechnicalContactDto {
|
||||||
|
firstName?: string;
|
||||||
|
lastName?: string;
|
||||||
|
phone?: string;
|
||||||
|
email?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface AddUserToMerchantDto {
|
export interface AddUserToMerchantDto {
|
||||||
userId: string;
|
userId: string;
|
||||||
role: UserRole;
|
role: UserRole;
|
||||||
@ -157,6 +171,17 @@ export interface UpdateUserRoleDto {
|
|||||||
role: UserRole;
|
role: UserRole;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DTO pour associer/dissocier un utilisateur
|
||||||
|
export interface AssociateUserToMerchantDto {
|
||||||
|
userId: string;
|
||||||
|
merchantConfigId: string;
|
||||||
|
role: UserRole;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DissociateUserFromMerchantDto {
|
||||||
|
userId: string;
|
||||||
|
merchantConfigId: string;
|
||||||
|
}
|
||||||
|
|
||||||
// === RÉPONSES API ===
|
// === RÉPONSES API ===
|
||||||
export interface ApiResponse<T> {
|
export interface ApiResponse<T> {
|
||||||
@ -190,6 +215,15 @@ export interface SearchMerchantsParams {
|
|||||||
limit?: number;
|
limit?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === TYPES POUR GESTION DES RÔLES ===
|
||||||
|
|
||||||
|
export interface UserRoleInfo {
|
||||||
|
value: UserRole;
|
||||||
|
label: string;
|
||||||
|
description: string;
|
||||||
|
type: 'hub' | 'merchant' | 'config';
|
||||||
|
}
|
||||||
|
|
||||||
// === UTILITAIRES ===
|
// === UTILITAIRES ===
|
||||||
export class MerchantUtils {
|
export class MerchantUtils {
|
||||||
static getOperatorName(operatorId: Operator): string {
|
static getOperatorName(operatorId: Operator): string {
|
||||||
@ -229,23 +263,4 @@ export class MerchantUtils {
|
|||||||
|
|
||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Méthode pour obtenir les rôles disponibles pour les merchants
|
|
||||||
static getAvailableMerchantRoles(): UserRole[] {
|
|
||||||
return [
|
|
||||||
UserRole.DCB_PARTNER_ADMIN,
|
|
||||||
UserRole.DCB_PARTNER_MANAGER,
|
|
||||||
UserRole.DCB_PARTNER_SUPPORT
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vérifier si un rôle est valide pour un merchant
|
|
||||||
static isValidMerchantRole(role: UserRole): boolean {
|
|
||||||
const merchantRoles = [
|
|
||||||
UserRole.DCB_PARTNER_ADMIN,
|
|
||||||
UserRole.DCB_PARTNER_MANAGER,
|
|
||||||
UserRole.DCB_PARTNER_SUPPORT
|
|
||||||
];
|
|
||||||
return merchantRoles.includes(role);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -209,7 +209,7 @@ export class AuthService {
|
|||||||
private determineUserType(apiUser: any): UserType {
|
private determineUserType(apiUser: any): UserType {
|
||||||
|
|
||||||
const hubRoles = [UserRole.DCB_ADMIN || UserRole.DCB_SUPPORT];
|
const hubRoles = [UserRole.DCB_ADMIN || UserRole.DCB_SUPPORT];
|
||||||
const merchantRoles = [UserRole.DCB_PARTNER || UserRole.DCB_PARTNER_ADMIN || UserRole.DCB_PARTNER_MANAGER || UserRole.DCB_PARTNER_SUPPORT];
|
const merchantRoles = [UserRole.DCB_PARTNER_ADMIN || UserRole.DCB_PARTNER_MANAGER || UserRole.DCB_PARTNER_SUPPORT];
|
||||||
|
|
||||||
// Logique pour déterminer le type d'utilisateur
|
// Logique pour déterminer le type d'utilisateur
|
||||||
if (apiUser.clientRoles?.[0].includes(merchantRoles)) {
|
if (apiUser.clientRoles?.[0].includes(merchantRoles)) {
|
||||||
@ -232,8 +232,6 @@ export class AuthService {
|
|||||||
enabled: apiUser.enabled ?? apiUser.active ?? true,
|
enabled: apiUser.enabled ?? apiUser.active ?? true,
|
||||||
emailVerified: apiUser.emailVerified ?? apiUser.email_verified ?? false,
|
emailVerified: apiUser.emailVerified ?? apiUser.email_verified ?? false,
|
||||||
userType: userType,
|
userType: userType,
|
||||||
merchantPartnerId: apiUser.merchantPartnerId || apiUser.partnerId || apiUser.merchantId || null,
|
|
||||||
merchantConfigId: apiUser.merchantConfigId || apiUser.configId || apiUser.merchantId || null,
|
|
||||||
role: apiUser.clientRoles || apiUser.clientRoles?.[0] || '', // Gérer rôle unique ou tableau
|
role: apiUser.clientRoles || apiUser.clientRoles?.[0] || '', // Gérer rôle unique ou tableau
|
||||||
createdBy: apiUser.createdBy || apiUser.creatorId || null,
|
createdBy: apiUser.createdBy || apiUser.creatorId || null,
|
||||||
createdByUsername: apiUser.createdByUsername || apiUser.creatorUsername || null,
|
createdByUsername: apiUser.createdByUsername || apiUser.creatorUsername || null,
|
||||||
@ -303,10 +301,6 @@ export class AuthService {
|
|||||||
'support': UserRole.DCB_SUPPORT,
|
'support': UserRole.DCB_SUPPORT,
|
||||||
'dcb-support': UserRole.DCB_SUPPORT,
|
'dcb-support': UserRole.DCB_SUPPORT,
|
||||||
|
|
||||||
// Rôles partenaire
|
|
||||||
'partner': UserRole.DCB_PARTNER,
|
|
||||||
'dcb-partner': UserRole.DCB_PARTNER,
|
|
||||||
|
|
||||||
// Rôles admin partenaire
|
// Rôles admin partenaire
|
||||||
'partner-admin': UserRole.DCB_PARTNER_ADMIN,
|
'partner-admin': UserRole.DCB_PARTNER_ADMIN,
|
||||||
'dcb-partner-admin': UserRole.DCB_PARTNER_ADMIN,
|
'dcb-partner-admin': UserRole.DCB_PARTNER_ADMIN,
|
||||||
@ -363,7 +357,7 @@ export class AuthService {
|
|||||||
if (!role) return null;
|
if (!role) return null;
|
||||||
|
|
||||||
// Déterminer le type d'utilisateur basé sur le rôle
|
// Déterminer le type d'utilisateur basé sur le rôle
|
||||||
const hubRoles = [UserRole.DCB_ADMIN, UserRole.DCB_SUPPORT, UserRole.DCB_PARTNER];
|
const hubRoles = [UserRole.DCB_ADMIN, UserRole.DCB_SUPPORT];
|
||||||
const merchantRoles = [UserRole.DCB_PARTNER_ADMIN, UserRole.DCB_PARTNER_MANAGER, UserRole.DCB_PARTNER_SUPPORT];
|
const merchantRoles = [UserRole.DCB_PARTNER_ADMIN, UserRole.DCB_PARTNER_MANAGER, UserRole.DCB_PARTNER_SUPPORT];
|
||||||
|
|
||||||
if (hubRoles.includes(role)) {
|
if (hubRoles.includes(role)) {
|
||||||
@ -434,7 +428,7 @@ export class AuthService {
|
|||||||
* Vérifie si l'utilisateur courant peut gérer les utilisateurs Marchands
|
* Vérifie si l'utilisateur courant peut gérer les utilisateurs Marchands
|
||||||
*/
|
*/
|
||||||
canManageMerchantUsers(): boolean {
|
canManageMerchantUsers(): boolean {
|
||||||
return this.hasAnyRole(UserRole.DCB_ADMIN) || this.hasAnyRole(UserRole.DCB_PARTNER);
|
return this.hasAnyRole(UserRole.DCB_ADMIN) || this.hasAnyRole(UserRole.DCB_PARTNER_ADMIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
// === MÉTHODES UTILITAIRES ===
|
// === MÉTHODES UTILITAIRES ===
|
||||||
@ -455,14 +449,6 @@ export class AuthService {
|
|||||||
return profile?.id || null;
|
return profile?.id || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Récupère le merchantPartnerId de l'utilisateur courant (si marchand)
|
|
||||||
*/
|
|
||||||
getCurrentMerchantPartnerId(): string | null {
|
|
||||||
const profile = this.userProfile$.value;
|
|
||||||
return profile?.merchantPartnerId || null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Vérifie si le profil fourni est celui de l'utilisateur courant
|
* Vérifie si le profil fourni est celui de l'utilisateur courant
|
||||||
*/
|
*/
|
||||||
@ -475,7 +461,7 @@ export class AuthService {
|
|||||||
* Vérifie si l'utilisateur peut visualiser tous les marchands
|
* Vérifie si l'utilisateur peut visualiser tous les marchands
|
||||||
*/
|
*/
|
||||||
canViewAllMerchants(): boolean {
|
canViewAllMerchants(): boolean {
|
||||||
return this.hasAnyRole(UserRole.DCB_ADMIN) || this.hasAnyRole(UserRole.DCB_PARTNER);
|
return this.hasAnyRole(UserRole.DCB_ADMIN) || this.hasAnyRole(UserRole.DCB_PARTNER_ADMIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
// === TOKENS ===
|
// === TOKENS ===
|
||||||
|
|||||||
@ -81,29 +81,6 @@ const ROLE_CONFIG: Record<UserRole, RoleConfig> = {
|
|||||||
canAccessPartner: true,
|
canAccessPartner: true,
|
||||||
assignableRoles: [
|
assignableRoles: [
|
||||||
UserRole.DCB_SUPPORT,
|
UserRole.DCB_SUPPORT,
|
||||||
UserRole.DCB_PARTNER,
|
|
||||||
UserRole.DCB_PARTNER_ADMIN,
|
|
||||||
UserRole.DCB_PARTNER_MANAGER,
|
|
||||||
UserRole.DCB_PARTNER_SUPPORT
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[UserRole.DCB_PARTNER]: {
|
|
||||||
label: 'Partenaire DCB',
|
|
||||||
description: 'Partenaire commercial principal',
|
|
||||||
badgeClass: 'bg-primary',
|
|
||||||
icon: 'lucideBuilding',
|
|
||||||
permissions: {
|
|
||||||
canCreateUsers: true,
|
|
||||||
canEditUsers: true,
|
|
||||||
canDeleteUsers: true,
|
|
||||||
canManageRoles: true,
|
|
||||||
canViewStats: true,
|
|
||||||
canManageMerchants: false,
|
|
||||||
canAccessAdmin: false,
|
|
||||||
canAccessSupport: false,
|
|
||||||
canAccessPartner: false,
|
|
||||||
assignableRoles: [
|
|
||||||
UserRole.DCB_PARTNER_ADMIN,
|
UserRole.DCB_PARTNER_ADMIN,
|
||||||
UserRole.DCB_PARTNER_MANAGER,
|
UserRole.DCB_PARTNER_MANAGER,
|
||||||
UserRole.DCB_PARTNER_SUPPORT
|
UserRole.DCB_PARTNER_SUPPORT
|
||||||
@ -198,7 +175,6 @@ const ROLE_CONFIG: Record<UserRole, RoleConfig> = {
|
|||||||
const HUB_ROLES = [
|
const HUB_ROLES = [
|
||||||
UserRole.DCB_ADMIN,
|
UserRole.DCB_ADMIN,
|
||||||
UserRole.DCB_SUPPORT,
|
UserRole.DCB_SUPPORT,
|
||||||
UserRole.DCB_PARTNER
|
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
// Rôles Marchands (pour les filtres)
|
// Rôles Marchands (pour les filtres)
|
||||||
@ -303,8 +279,7 @@ export class RoleManagementService {
|
|||||||
|
|
||||||
const fullPermissionRoles = [
|
const fullPermissionRoles = [
|
||||||
UserRole.DCB_ADMIN,
|
UserRole.DCB_ADMIN,
|
||||||
UserRole.DCB_SUPPORT,
|
UserRole.DCB_SUPPORT
|
||||||
UserRole.DCB_PARTNER
|
|
||||||
];
|
];
|
||||||
|
|
||||||
if (fullPermissionRoles.includes(currentUserRole)) {
|
if (fullPermissionRoles.includes(currentUserRole)) {
|
||||||
@ -398,10 +373,6 @@ export class RoleManagementService {
|
|||||||
return role === UserRole.DCB_SUPPORT;
|
return role === UserRole.DCB_SUPPORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
isPartnerRole(role: UserRole): boolean {
|
|
||||||
return role === UserRole.DCB_PARTNER;
|
|
||||||
}
|
|
||||||
|
|
||||||
isMerchantUserRole(role: UserRole): boolean {
|
isMerchantUserRole(role: UserRole): boolean {
|
||||||
return role === UserRole.DCB_PARTNER_ADMIN
|
return role === UserRole.DCB_PARTNER_ADMIN
|
||||||
|| role === UserRole.DCB_PARTNER_MANAGER
|
|| role === UserRole.DCB_PARTNER_MANAGER
|
||||||
|
|||||||
@ -45,10 +45,10 @@ export class PermissionsService {
|
|||||||
// Webhooks - Admin et Partner
|
// Webhooks - Admin et Partner
|
||||||
{
|
{
|
||||||
module: 'webhooks',
|
module: 'webhooks',
|
||||||
roles: [UserRole.DCB_ADMIN, UserRole.DCB_PARTNER],
|
roles: [UserRole.DCB_ADMIN, UserRole.DCB_PARTNER_ADMIN],
|
||||||
children: {
|
children: {
|
||||||
'history': [UserRole.DCB_ADMIN, UserRole.DCB_PARTNER],
|
'history': [UserRole.DCB_ADMIN, UserRole.DCB_PARTNER_ADMIN],
|
||||||
'status': [UserRole.DCB_ADMIN, UserRole.DCB_PARTNER],
|
'status': [UserRole.DCB_ADMIN, UserRole.DCB_PARTNER_ADMIN],
|
||||||
'retry': [UserRole.DCB_ADMIN]
|
'retry': [UserRole.DCB_ADMIN]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -85,7 +85,6 @@ export class UserProfileComponent implements OnInit, OnDestroy {
|
|||||||
const roleDisplayNames: { [key in UserRole]: string } = {
|
const roleDisplayNames: { [key in UserRole]: string } = {
|
||||||
[UserRole.DCB_ADMIN]: 'Administrateur système avec tous les accès',
|
[UserRole.DCB_ADMIN]: 'Administrateur système avec tous les accès',
|
||||||
[UserRole.DCB_SUPPORT]: 'Support technique avec accès étendus',
|
[UserRole.DCB_SUPPORT]: 'Support technique avec accès étendus',
|
||||||
[UserRole.DCB_PARTNER]: 'Partenaire commercial principal',
|
|
||||||
[UserRole.DCB_PARTNER_ADMIN]: 'Administrateur de partenaire marchand',
|
[UserRole.DCB_PARTNER_ADMIN]: 'Administrateur de partenaire marchand',
|
||||||
[UserRole.DCB_PARTNER_MANAGER]: 'Manager opérationnel partenaire',
|
[UserRole.DCB_PARTNER_MANAGER]: 'Manager opérationnel partenaire',
|
||||||
[UserRole.DCB_PARTNER_SUPPORT]: 'Support technique partenaire',
|
[UserRole.DCB_PARTNER_SUPPORT]: 'Support technique partenaire',
|
||||||
|
|||||||
@ -66,14 +66,6 @@
|
|||||||
>
|
>
|
||||||
DCB Support ({{ getUsersCountByRole(UserRole.DCB_SUPPORT) }})
|
DCB Support ({{ getUsersCountByRole(UserRole.DCB_SUPPORT) }})
|
||||||
</button>
|
</button>
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-outline-success"
|
|
||||||
[class.active]="roleFilter === UserRole.DCB_PARTNER"
|
|
||||||
(click)="filterByRole(UserRole.DCB_PARTNER)"
|
|
||||||
>
|
|
||||||
DCB Partners ({{ getUsersCountByRole(UserRole.DCB_PARTNER) }})
|
|
||||||
</button>
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-outline-warning text-dark"
|
class="btn btn-outline-warning text-dark"
|
||||||
@ -116,14 +108,6 @@
|
|||||||
>
|
>
|
||||||
Support ({{ getUsersCountByRole(UserRole.DCB_SUPPORT) }})
|
Support ({{ getUsersCountByRole(UserRole.DCB_SUPPORT) }})
|
||||||
</button>
|
</button>
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-outline-success"
|
|
||||||
[class.active]="roleFilter === UserRole.DCB_PARTNER"
|
|
||||||
(click)="filterByRole(UserRole.DCB_PARTNER)"
|
|
||||||
>
|
|
||||||
Partenaires ({{ getUsersCountByRole(UserRole.DCB_PARTNER) }})
|
|
||||||
</button>
|
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -460,11 +444,6 @@
|
|||||||
<strong>Support :</strong> {{ getUsersCountByRole(UserRole.DCB_SUPPORT) }}
|
<strong>Support :</strong> {{ getUsersCountByRole(UserRole.DCB_SUPPORT) }}
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
|
||||||
<small class="text-muted">
|
|
||||||
<strong>Partenaires :</strong> {{ getUsersCountByRole(UserRole.DCB_PARTNER) }}
|
|
||||||
</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -161,7 +161,7 @@ export class HubUsersList implements OnInit, OnDestroy {
|
|||||||
{ value: 'all', label: 'Tous les rôles', description: 'Tous les Roles' },
|
{ value: 'all', label: 'Tous les rôles', description: 'Tous les Roles' },
|
||||||
{ value: UserRole.DCB_ADMIN, label: 'DCB Admin', description: 'Administrateur système' },
|
{ value: UserRole.DCB_ADMIN, label: 'DCB Admin', description: 'Administrateur système' },
|
||||||
{ value: UserRole.DCB_SUPPORT, label: 'DCB Support', description: 'Support technique' },
|
{ value: UserRole.DCB_SUPPORT, label: 'DCB Support', description: 'Support technique' },
|
||||||
{ value: UserRole.DCB_PARTNER, label: 'DCB Partner', description: 'Partenaire commercial' },
|
//{ value: UserRole.DCB_PARTNER, label: 'DCB Partner', description: 'Partenaire commercial' },
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -124,7 +124,7 @@ export class HubUserProfile implements OnInit, OnDestroy {
|
|||||||
this.availableRoles = [
|
this.availableRoles = [
|
||||||
{ value: UserRole.DCB_ADMIN, label: 'DCB Admin', description: 'Administrateur système' },
|
{ value: UserRole.DCB_ADMIN, label: 'DCB Admin', description: 'Administrateur système' },
|
||||||
{ value: UserRole.DCB_SUPPORT, label: 'DCB Support', description: 'Support technique' },
|
{ value: UserRole.DCB_SUPPORT, label: 'DCB Support', description: 'Support technique' },
|
||||||
{ value: UserRole.DCB_PARTNER, label: 'DCB Partner', description: 'Partenaire commercial' }
|
//{ value: UserRole.DCB_PARTNER, label: 'DCB Partner', description: 'Partenaire commercial' }
|
||||||
];
|
];
|
||||||
this.cdRef.detectChanges();
|
this.cdRef.detectChanges();
|
||||||
}
|
}
|
||||||
@ -480,7 +480,7 @@ export class HubUserProfile implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private isValidHubRole(role: UserRole): boolean {
|
private isValidHubRole(role: UserRole): boolean {
|
||||||
const hubRoles = [UserRole.DCB_ADMIN, UserRole.DCB_SUPPORT, UserRole.DCB_PARTNER];
|
const hubRoles = [UserRole.DCB_ADMIN, UserRole.DCB_SUPPORT];
|
||||||
return hubRoles.includes(role);
|
return hubRoles.includes(role);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -526,7 +526,7 @@ export class HubUserProfile implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getAssignableRoles(): UserRole[] {
|
getAssignableRoles(): UserRole[] {
|
||||||
const hubRoles = [UserRole.DCB_ADMIN, UserRole.DCB_SUPPORT, UserRole.DCB_PARTNER];
|
const hubRoles = [UserRole.DCB_ADMIN, UserRole.DCB_SUPPORT];
|
||||||
return hubRoles.filter(role => this.roleService.canAssignRole(this.currentUserRole, role));
|
return hubRoles.filter(role => this.roleService.canAssignRole(this.currentUserRole, role));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -39,7 +39,6 @@ export interface UserProfileResponse {
|
|||||||
emailVerified: boolean;
|
emailVerified: boolean;
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
role: string[];
|
role: string[];
|
||||||
merchantPartnerId?: string;
|
|
||||||
createdBy?: string;
|
createdBy?: string;
|
||||||
createdByUsername?: string;
|
createdByUsername?: string;
|
||||||
}
|
}
|
||||||
@ -48,19 +47,10 @@ export interface MessageResponse {
|
|||||||
message: string;
|
message: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MerchantPartnerIdResponse {
|
|
||||||
merchantPartnerId: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MerchantConfigIdResponse {
|
|
||||||
merchantPartnerId: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class HubUsersService {
|
export class HubUsersService {
|
||||||
private http = inject(HttpClient);
|
private http = inject(HttpClient);
|
||||||
private baseIamApiUrl = `${environment.iamApiUrl}/hub-users`;
|
private baseIamApiUrl = `${environment.iamApiUrl}/hub-users`;
|
||||||
private baseConfigApiUrl = `${environment.configApiUrl}/merchants`;
|
|
||||||
|
|
||||||
// === MÉTHODES SPÉCIFIQUES HUB ===
|
// === MÉTHODES SPÉCIFIQUES HUB ===
|
||||||
|
|
||||||
@ -123,19 +113,6 @@ export class HubUsersService {
|
|||||||
return throwError(() => 'Password must be at least 8 characters');
|
return throwError(() => 'Password must be at least 8 characters');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (createUserDto.role === UserRole.DCB_PARTNER && !createUserDto.merchantConfigId) {
|
|
||||||
return throwError(() => 'Merchant Config is required and cannot be empty');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (createUserDto.userType === UserType.MERCHANT_PARTNER && !createUserDto.merchantConfigId) {
|
|
||||||
return throwError(() => 'Merchant Config is required and cannot be empty');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Avant de créer le payload, valider les données
|
|
||||||
if (createUserDto.userType === UserType.MERCHANT_PARTNER && !createUserDto.merchantPartnerId) {
|
|
||||||
return throwError(() => 'merchantPartnerId is required for merchant users');
|
|
||||||
}
|
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
username: createUserDto.username.trim(),
|
username: createUserDto.username.trim(),
|
||||||
email: createUserDto.email.trim().toLowerCase(), // Normaliser l'email
|
email: createUserDto.email.trim().toLowerCase(), // Normaliser l'email
|
||||||
@ -145,16 +122,9 @@ export class HubUsersService {
|
|||||||
role: createUserDto.role,
|
role: createUserDto.role,
|
||||||
enabled: createUserDto.enabled ?? true,
|
enabled: createUserDto.enabled ?? true,
|
||||||
emailVerified: createUserDto.emailVerified ?? true,
|
emailVerified: createUserDto.emailVerified ?? true,
|
||||||
merchantPartnerId: createUserDto.merchantPartnerId,
|
|
||||||
merchantConfigId: createUserDto.merchantConfigId,
|
|
||||||
userType: createUserDto.userType.trim()
|
userType: createUserDto.userType.trim()
|
||||||
};
|
};
|
||||||
|
|
||||||
// Validation supplémentaire
|
|
||||||
if (payload.userType === UserType.HUB && payload.merchantPartnerId) {
|
|
||||||
return throwError(() => 'merchantPartnerId should not be provided for hub users');
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(payload)
|
console.log(payload)
|
||||||
|
|
||||||
return this.http.post<User>(`${this.baseIamApiUrl}`, payload).pipe(
|
return this.http.post<User>(`${this.baseIamApiUrl}`, payload).pipe(
|
||||||
@ -179,19 +149,6 @@ export class HubUsersService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getAllDcbPartners(page: number = 1, limit: number = 10, filters?: SearchUsersParams): Observable<PaginatedUserResponse> {
|
|
||||||
return this.http.get<User[]>(`${this.baseIamApiUrl}/partners/dcb-partners`).pipe(
|
|
||||||
map(users => {
|
|
||||||
const mappedUsers = users.map(user => this.mapToUserModel(user, UserType.HUB));
|
|
||||||
return this.filterAndPaginateUsers(mappedUsers, page, limit, filters);
|
|
||||||
}),
|
|
||||||
catchError(error => {
|
|
||||||
console.error('Error loading merchant hub users:', error);
|
|
||||||
return throwError(() => error);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
getHubUserById(id: string): Observable<User> {
|
getHubUserById(id: string): Observable<User> {
|
||||||
return this.http.get<User>(`${this.baseIamApiUrl}/${id}`).pipe(
|
return this.http.get<User>(`${this.baseIamApiUrl}/${id}`).pipe(
|
||||||
map(user => this.mapToUserModel(user, UserType.HUB)),
|
map(user => this.mapToUserModel(user, UserType.HUB)),
|
||||||
@ -220,7 +177,7 @@ export class HubUsersService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateHubUserRole(id: string, role: UserRole): Observable<User> {
|
updateHubUserRole(id: string, role: UserRole): Observable<User> {
|
||||||
const hubRoles = [UserRole.DCB_ADMIN, UserRole.DCB_SUPPORT, UserRole.DCB_PARTNER];
|
const hubRoles = [UserRole.DCB_ADMIN, UserRole.DCB_SUPPORT];
|
||||||
if (!hubRoles.includes(role)) {
|
if (!hubRoles.includes(role)) {
|
||||||
return throwError(() => 'Invalid role for Hub user');
|
return throwError(() => 'Invalid role for Hub user');
|
||||||
}
|
}
|
||||||
@ -285,13 +242,6 @@ export class HubUsersService {
|
|||||||
allowedForCreation: true,
|
allowedForCreation: true,
|
||||||
userType: UserType.HUB
|
userType: UserType.HUB
|
||||||
},
|
},
|
||||||
{
|
|
||||||
value: UserRole.DCB_PARTNER,
|
|
||||||
label: 'DCB Partner',
|
|
||||||
description: 'Partner access to merchant management',
|
|
||||||
allowedForCreation: true,
|
|
||||||
userType: UserType.HUB
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
} as AvailableRolesResponse);
|
} as AvailableRolesResponse);
|
||||||
}
|
}
|
||||||
@ -327,7 +277,7 @@ export class HubUsersService {
|
|||||||
// === MÉTHODES UTILITAIRES ===
|
// === MÉTHODES UTILITAIRES ===
|
||||||
|
|
||||||
isValidRoleForHub(role: UserRole): boolean {
|
isValidRoleForHub(role: UserRole): boolean {
|
||||||
const hubRoles = [UserRole.DCB_ADMIN, UserRole.DCB_PARTNER, UserRole.DCB_SUPPORT];
|
const hubRoles = [UserRole.DCB_ADMIN, UserRole.DCB_SUPPORT];
|
||||||
return hubRoles.includes(role);
|
return hubRoles.includes(role);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,8 +293,6 @@ export class HubUsersService {
|
|||||||
enabled: apiUser.enabled,
|
enabled: apiUser.enabled,
|
||||||
emailVerified: apiUser.emailVerified,
|
emailVerified: apiUser.emailVerified,
|
||||||
userType: userType,
|
userType: userType,
|
||||||
merchantPartnerId: apiUser.merchantPartnerId,
|
|
||||||
merchantConfigId: apiUser.merchantConfigId,
|
|
||||||
role: apiUser.role,
|
role: apiUser.role,
|
||||||
createdBy: apiUser.createdBy,
|
createdBy: apiUser.createdBy,
|
||||||
createdByUsername: apiUser.createdByUsername,
|
createdByUsername: apiUser.createdByUsername,
|
||||||
@ -384,9 +332,6 @@ export class HubUsersService {
|
|||||||
filteredUsers = filteredUsers.filter(user => user.userType === filters.userType);
|
filteredUsers = filteredUsers.filter(user => user.userType === filters.userType);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.merchantPartnerId) {
|
|
||||||
filteredUsers = filteredUsers.filter(user => user.merchantPartnerId === filters.merchantPartnerId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pagination côté client
|
// Pagination côté client
|
||||||
|
|||||||
@ -76,7 +76,7 @@ export class HubUsersManagement implements OnInit, OnDestroy {
|
|||||||
userType: UserType;
|
userType: UserType;
|
||||||
} = this.getDefaultUserForm();
|
} = this.getDefaultUserForm();
|
||||||
|
|
||||||
// Formulaire de création marchand (pour DCB_PARTNER)
|
// Formulaire de création marchand (pour les utilisateurs avec rôle permettant de créer des marchands)
|
||||||
newMerchant: CreateMerchantDto = this.getDefaultMerchantForm();
|
newMerchant: CreateMerchantDto = this.getDefaultMerchantForm();
|
||||||
|
|
||||||
// États des opérations
|
// États des opérations
|
||||||
@ -101,8 +101,15 @@ export class HubUsersManagement implements OnInit, OnDestroy {
|
|||||||
showPassword = false;
|
showPassword = false;
|
||||||
showNewPassword = false;
|
showNewPassword = false;
|
||||||
|
|
||||||
|
// Mode de création (nouveau)
|
||||||
|
creationMode: 'userOnly' | 'userAndMerchant' = 'userOnly';
|
||||||
|
|
||||||
|
// Liste des marchands disponibles pour association
|
||||||
|
availableMerchants: any[] = [];
|
||||||
|
|
||||||
// Références aux templates de modals
|
// Références aux templates de modals
|
||||||
@ViewChild('createUserModal') createUserModal!: TemplateRef<any>;
|
@ViewChild('createUserModal') createUserModal!: TemplateRef<any>;
|
||||||
|
@ViewChild('createMerchantModal') createMerchantModal!: TemplateRef<any>;
|
||||||
@ViewChild('resetPasswordModal') resetPasswordModal!: TemplateRef<any>;
|
@ViewChild('resetPasswordModal') resetPasswordModal!: TemplateRef<any>;
|
||||||
@ViewChild('deleteUserModal') deleteUserModal!: TemplateRef<any>;
|
@ViewChild('deleteUserModal') deleteUserModal!: TemplateRef<any>;
|
||||||
|
|
||||||
@ -208,7 +215,9 @@ export class HubUsersManagement implements OnInit, OnDestroy {
|
|||||||
return [
|
return [
|
||||||
{ value: UserRole.DCB_ADMIN, label: 'DCB Admin', description: 'Administrateur système' },
|
{ value: UserRole.DCB_ADMIN, label: 'DCB Admin', description: 'Administrateur système' },
|
||||||
{ value: UserRole.DCB_SUPPORT, label: 'DCB Support', description: 'Support technique' },
|
{ value: UserRole.DCB_SUPPORT, label: 'DCB Support', description: 'Support technique' },
|
||||||
{ value: UserRole.DCB_PARTNER, label: 'DCB Partner', description: 'Partenaire commercial' }
|
{ value: UserRole.DCB_PARTNER_ADMIN, label: 'DCB Partner Admin', description: 'Administrateur partenaire' },
|
||||||
|
{ value: UserRole.DCB_PARTNER_MANAGER, label: 'DCB Partner Manager', description: 'Manager partenaire' },
|
||||||
|
{ value: UserRole.DCB_PARTNER_SUPPORT, label: 'DCB Partner Support', description: 'Support partenaire' }
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,7 +242,7 @@ export class HubUsersManagement implements OnInit, OnDestroy {
|
|||||||
description: '',
|
description: '',
|
||||||
adresse: '',
|
adresse: '',
|
||||||
phone: '',
|
phone: '',
|
||||||
configs:[],
|
configs: [],
|
||||||
technicalContacts: []
|
technicalContacts: []
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -332,10 +341,22 @@ export class HubUsersManagement implements OnInit, OnDestroy {
|
|||||||
this.openModal(this.createUserModal);
|
this.openModal(this.createUserModal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Méthode pour ouvrir le modal de création de marchand
|
||||||
|
openCreateMerchantModal() {
|
||||||
|
this.resetMerchantForm();
|
||||||
|
this.openModal(this.createMerchantModal);
|
||||||
|
}
|
||||||
|
|
||||||
private resetUserForm() {
|
private resetUserForm() {
|
||||||
this.newUser = this.getDefaultUserForm();
|
this.newUser = this.getDefaultUserForm();
|
||||||
|
this.creationMode = 'userOnly';
|
||||||
|
console.log('🔄 User form reset');
|
||||||
|
}
|
||||||
|
|
||||||
|
private resetMerchantForm() {
|
||||||
this.newMerchant = this.getDefaultMerchantForm();
|
this.newMerchant = this.getDefaultMerchantForm();
|
||||||
console.log('🔄 Hub user form reset');
|
this.creatingMerchant = false;
|
||||||
|
console.log('🔄 Merchant form reset');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Méthode pour ouvrir le modal de réinitialisation de mot de passe
|
// Méthode pour ouvrir le modal de réinitialisation de mot de passe
|
||||||
@ -387,6 +408,7 @@ export class HubUsersManagement implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
onRoleSelectionChange(selectedRole: UserRole) {
|
onRoleSelectionChange(selectedRole: UserRole) {
|
||||||
this.newUser.role = selectedRole;
|
this.newUser.role = selectedRole;
|
||||||
|
// Le mode reste 'userOnly' par défaut, l'association au marchand se fera plus tard
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== OPÉRATIONS CRUD ====================
|
// ==================== OPÉRATIONS CRUD ====================
|
||||||
@ -416,106 +438,48 @@ export class HubUsersManagement implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
console.log('📤 Creating hub user:', {
|
console.log('📤 Creating hub user:', {
|
||||||
username: this.newUser.username,
|
username: this.newUser.username,
|
||||||
role: this.newUser.role,
|
role: this.newUser.role
|
||||||
type: this.newUser.role === UserRole.DCB_PARTNER ? 'DCB Partner (avec marchand)' : 'Utilisateur Hub standard'
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Pour DCB_PARTNER: créer d'abord le marchand
|
// Déterminer le userType en fonction du rôle
|
||||||
if (this.newUser.role === UserRole.DCB_PARTNER) {
|
let userType = UserType.HUB;
|
||||||
// Validation du formulaire marchand pour DCB_PARTNER
|
if (this.isPartnerRole(this.newUser.role)) {
|
||||||
const merchantValidation = this.validateMerchantForm();
|
userType = UserType.MERCHANT_PARTNER;
|
||||||
if (!merchantValidation.isValid) {
|
|
||||||
this.createUserError = merchantValidation.error!;
|
|
||||||
console.error('❌ Merchant form validation failed:', merchantValidation.error);
|
|
||||||
this.creatingUser = false;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.createMerchantForDcbPartner();
|
const userData = {
|
||||||
} else {
|
...this.newUser,
|
||||||
// Pour les autres rôles: créer uniquement l'utilisateur Hub
|
userType: userType
|
||||||
this.createHubUserOnly();
|
};
|
||||||
}
|
|
||||||
|
// Créer uniquement l'utilisateur dans Keycloak
|
||||||
|
this.createKeycloakUserOnly(userData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Crée un marchand avec un DCB Partner (ordre: merchantConfig -> Keycloak)
|
* Crée uniquement l'utilisateur dans Keycloak
|
||||||
*/
|
*/
|
||||||
private createMerchantForDcbPartner() {
|
private createKeycloakUserOnly(userData: any) {
|
||||||
this.creatingMerchant = true;
|
console.log('👤 Creating user in Keycloak only...');
|
||||||
console.log('📤 Creating merchant for DCB_PARTNER:', this.newMerchant);
|
|
||||||
|
|
||||||
// Données du DCB Partner
|
this.hubUsersService.createHubUser(userData)
|
||||||
const dcbPartnerData = {
|
|
||||||
username: this.newUser.username,
|
|
||||||
email: this.newUser.email,
|
|
||||||
password: this.newUser.password,
|
|
||||||
firstName: this.newUser.firstName,
|
|
||||||
lastName: this.newUser.lastName,
|
|
||||||
enabled: this.newUser.enabled,
|
|
||||||
emailVerified: this.newUser.emailVerified
|
|
||||||
};
|
|
||||||
|
|
||||||
// Données du marchand
|
|
||||||
const merchantData: CreateMerchantDto = {
|
|
||||||
...this.newMerchant
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log('🔧 Données envoyées:');
|
|
||||||
console.log(' Merchant:', merchantData);
|
|
||||||
console.log(' DCB Partner:', { ...dcbPartnerData, password: '***' });
|
|
||||||
|
|
||||||
// Utiliser le MerchantSyncService pour créer d'abord dans merchantConfig puis dans Keycloak
|
|
||||||
this.merchantSyncService.createMerchant(merchantData, dcbPartnerData)
|
|
||||||
.pipe(takeUntil(this.destroy$))
|
|
||||||
.subscribe({
|
|
||||||
next: (createResult) => {
|
|
||||||
console.log('✅ Merchant and DCB Partner created successfully:', createResult);
|
|
||||||
this.creatingUser = false;
|
|
||||||
this.creatingMerchant = false;
|
|
||||||
|
|
||||||
console.log('📊 Résultat création:');
|
|
||||||
console.log(' Merchant Config ID:', createResult.merchantConfig?.id);
|
|
||||||
console.log(' Keycloak Merchant ID:', createResult.keycloakMerchant?.id);
|
|
||||||
console.log(' Merchant name:', createResult.merchantConfig?.name);
|
|
||||||
console.log(' DCB Partner email:', createResult.keycloakMerchant?.email);
|
|
||||||
|
|
||||||
this.modalService.dismissAll();
|
|
||||||
this.refreshUsersList();
|
|
||||||
this.cdRef.detectChanges();
|
|
||||||
},
|
|
||||||
error: (error) => {
|
|
||||||
console.error('❌ Error creating merchant and DCB Partner:', error);
|
|
||||||
this.creatingUser = false;
|
|
||||||
this.creatingMerchant = false;
|
|
||||||
|
|
||||||
this.createUserError = this.getMerchantErrorMessage(error);
|
|
||||||
console.error('❌ Détails de l\'erreur:', error);
|
|
||||||
|
|
||||||
this.cdRef.detectChanges();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Crée uniquement un utilisateur Hub (pas de marchand)
|
|
||||||
*/
|
|
||||||
private createHubUserOnly() {
|
|
||||||
console.log('📤 Creating hub user only (no merchant)');
|
|
||||||
|
|
||||||
this.hubUsersService.createHubUser(this.newUser)
|
|
||||||
.pipe(takeUntil(this.destroy$))
|
.pipe(takeUntil(this.destroy$))
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: (createdUser) => {
|
next: (createdUser) => {
|
||||||
console.log('✅ Hub user created successfully:', createdUser);
|
console.log('✅ User created successfully in Keycloak:', createdUser);
|
||||||
this.creatingUser = false;
|
this.creatingUser = false;
|
||||||
|
|
||||||
|
// Si l'utilisateur a un rôle de partenaire, proposer de créer un marchand
|
||||||
|
if (this.isPartnerRole(this.newUser.role)) {
|
||||||
|
console.log('ℹ️ User with partner role created. Merchant creation can be done separately.');
|
||||||
|
}
|
||||||
|
|
||||||
this.modalService.dismissAll();
|
this.modalService.dismissAll();
|
||||||
this.refreshUsersList();
|
this.refreshUsersList();
|
||||||
this.cdRef.detectChanges();
|
this.cdRef.detectChanges();
|
||||||
},
|
},
|
||||||
error: (error) => {
|
error: (error) => {
|
||||||
console.error('❌ Error creating hub user:', error);
|
console.error('❌ Error creating user in Keycloak:', error);
|
||||||
this.creatingUser = false;
|
this.creatingUser = false;
|
||||||
this.createUserError = this.getErrorMessage(error);
|
this.createUserError = this.getErrorMessage(error);
|
||||||
this.cdRef.detectChanges();
|
this.cdRef.detectChanges();
|
||||||
@ -523,6 +487,56 @@ export class HubUsersManagement implements OnInit, OnDestroy {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée un marchand dans MerchantConfig (séparément de l'utilisateur)
|
||||||
|
*/
|
||||||
|
createMerchant() {
|
||||||
|
// Validation du formulaire marchand
|
||||||
|
const merchantValidation = this.validateMerchantForm();
|
||||||
|
if (!merchantValidation.isValid) {
|
||||||
|
this.createUserError = merchantValidation.error!;
|
||||||
|
console.error('❌ Merchant form validation failed:', merchantValidation.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.creatingMerchant = true;
|
||||||
|
|
||||||
|
console.log('📤 Creating merchant in MerchantConfig...');
|
||||||
|
|
||||||
|
this.merchantSyncService.createMerchantInConfigOnly(this.newMerchant)
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe({
|
||||||
|
next: (merchantConfig) => {
|
||||||
|
console.log('✅ Merchant created in MerchantConfig:', merchantConfig);
|
||||||
|
this.creatingMerchant = false;
|
||||||
|
|
||||||
|
// Optionnel: proposer d'associer un utilisateur au marchand créé
|
||||||
|
console.log(`✅ Merchant ID: ${merchantConfig.id} - Name: ${merchantConfig.name}`);
|
||||||
|
|
||||||
|
this.modalService.dismissAll();
|
||||||
|
this.resetMerchantForm();
|
||||||
|
this.cdRef.detectChanges();
|
||||||
|
},
|
||||||
|
error: (error) => {
|
||||||
|
console.error('❌ Error creating merchant in MerchantConfig:', error);
|
||||||
|
this.creatingMerchant = false;
|
||||||
|
this.createUserError = this.getMerchantErrorMessage(error);
|
||||||
|
this.cdRef.detectChanges();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si le rôle est un rôle partenaire
|
||||||
|
*/
|
||||||
|
private isPartnerRole(role: UserRole): boolean {
|
||||||
|
return [
|
||||||
|
UserRole.DCB_PARTNER_ADMIN,
|
||||||
|
UserRole.DCB_PARTNER_MANAGER,
|
||||||
|
UserRole.DCB_PARTNER_SUPPORT
|
||||||
|
].includes(role);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Vérifie si l'utilisateur peut attribuer un rôle spécifique
|
* Vérifie si l'utilisateur peut attribuer un rôle spécifique
|
||||||
*/
|
*/
|
||||||
@ -585,11 +599,19 @@ export class HubUsersManagement implements OnInit, OnDestroy {
|
|||||||
this.deletingUser = true;
|
this.deletingUser = true;
|
||||||
this.deleteUserError = '';
|
this.deleteUserError = '';
|
||||||
|
|
||||||
|
// Supprimer uniquement l'utilisateur de Keycloak
|
||||||
|
this.deleteKeycloakUserOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supprime uniquement l'utilisateur de Keycloak
|
||||||
|
*/
|
||||||
|
private deleteKeycloakUserOnly() {
|
||||||
this.hubUsersService.deleteHubUser(this.selectedUserForDelete.id)
|
this.hubUsersService.deleteHubUser(this.selectedUserForDelete.id)
|
||||||
.pipe(takeUntil(this.destroy$))
|
.pipe(takeUntil(this.destroy$))
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: () => {
|
next: () => {
|
||||||
console.log('✅ Hub user deleted successfully');
|
console.log('✅ User deleted successfully from Keycloak');
|
||||||
this.deletingUser = false;
|
this.deletingUser = false;
|
||||||
this.modalService.dismissAll();
|
this.modalService.dismissAll();
|
||||||
this.refreshUsersList();
|
this.refreshUsersList();
|
||||||
@ -661,18 +683,18 @@ export class HubUsersManagement implements OnInit, OnDestroy {
|
|||||||
return error.error.message;
|
return error.error.message;
|
||||||
}
|
}
|
||||||
if (error.status === 400) {
|
if (error.status === 400) {
|
||||||
return 'Données du marchand ou du DCB Partner invalides.';
|
return 'Données du marchand invalides.';
|
||||||
}
|
}
|
||||||
if (error.status === 409) {
|
if (error.status === 409) {
|
||||||
return 'Un marchand avec ce nom ou un utilisateur avec ces identifiants existe déjà.';
|
return 'Un marchand avec ce nom existe déjà.';
|
||||||
}
|
}
|
||||||
if (error.status === 403) {
|
if (error.status === 403) {
|
||||||
return 'Vous n\'avez pas les permissions pour créer un marchand ou un DCB Partner.';
|
return 'Vous n\'avez pas les permissions pour créer un marchand.';
|
||||||
}
|
}
|
||||||
if (error.status === 404) {
|
if (error.status === 404) {
|
||||||
return 'Service de création de marchand non disponible.';
|
return 'Service de création de marchand non disponible.';
|
||||||
}
|
}
|
||||||
return 'Erreur lors de la création du marchand et du DCB Partner.';
|
return 'Erreur lors de la création du marchand.';
|
||||||
}
|
}
|
||||||
|
|
||||||
private getResetPasswordErrorMessage(error: any): string {
|
private getResetPasswordErrorMessage(error: any): string {
|
||||||
@ -754,7 +776,7 @@ export class HubUsersManagement implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
for (const { field, name } of requiredFields) {
|
for (const { field, name } of requiredFields) {
|
||||||
if (!field) {
|
if (!field) {
|
||||||
return { isValid: false, error: `${name} est requis pour un DCB Partner` };
|
return { isValid: false, error: `${name} est requis` };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -153,10 +153,6 @@
|
|||||||
<table class="table table-hover table-striped">
|
<table class="table table-hover table-striped">
|
||||||
<thead class="table-light">
|
<thead class="table-light">
|
||||||
<tr>
|
<tr>
|
||||||
<!-- Colonne Merchant Partner pour les admins -->
|
|
||||||
@if (showMerchantPartnerColumn) {
|
|
||||||
<th>Merchant Partner</th>
|
|
||||||
}
|
|
||||||
<th (click)="sort('username')" class="cursor-pointer">
|
<th (click)="sort('username')" class="cursor-pointer">
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
<span>Utilisateur</span>
|
<span>Utilisateur</span>
|
||||||
@ -188,21 +184,6 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
@for (user of displayedUsers; track user.id) {
|
@for (user of displayedUsers; track user.id) {
|
||||||
<tr>
|
<tr>
|
||||||
<!-- Colonne Merchant Partner pour les admins -->
|
|
||||||
@if (showMerchantPartnerColumn) {
|
|
||||||
<td>
|
|
||||||
<div class="d-flex align-items-center">
|
|
||||||
<div class="avatar-sm bg-secondary bg-opacity-10 rounded-circle d-flex align-items-center justify-content-center me-2">
|
|
||||||
<ng-icon name="lucideBuilding" class="text-secondary fs-12"></ng-icon>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<small class="text-muted font-monospace" [title]="user.merchantPartnerId || 'N/A'">
|
|
||||||
{{ (user.merchantPartnerId || 'N/A').substring(0, 8) }}...
|
|
||||||
</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
}
|
|
||||||
<td>
|
<td>
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
<div class="avatar-sm bg-primary bg-opacity-10 rounded-circle d-flex align-items-center justify-content-center me-2">
|
<div class="avatar-sm bg-primary bg-opacity-10 rounded-circle d-flex align-items-center justify-content-center me-2">
|
||||||
|
|||||||
@ -116,7 +116,6 @@ export class MerchantUsersList implements OnInit, OnDestroy {
|
|||||||
.subscribe({
|
.subscribe({
|
||||||
next: (user) => {
|
next: (user) => {
|
||||||
this.currentUserRole = this.extractUserRole(user);
|
this.currentUserRole = this.extractUserRole(user);
|
||||||
this.currentMerchantPartnerId = this.extractMerchantPartnerId(user);
|
|
||||||
this.canViewAllMerchants = this.canViewAllMerchantsCheck(this.currentUserRole);
|
this.canViewAllMerchants = this.canViewAllMerchantsCheck(this.currentUserRole);
|
||||||
|
|
||||||
console.log('Merchant User Context Loaded:', {
|
console.log('Merchant User Context Loaded:', {
|
||||||
@ -143,13 +142,6 @@ export class MerchantUsersList implements OnInit, OnDestroy {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private extractMerchantPartnerId(user: any): string {
|
|
||||||
if (user?.merchantPartnerId) {
|
|
||||||
return user.merchantPartnerId;
|
|
||||||
}
|
|
||||||
return this.authService.getCurrentMerchantPartnerId() || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
private canViewAllMerchantsCheck(role: UserRole | null): boolean {
|
private canViewAllMerchantsCheck(role: UserRole | null): boolean {
|
||||||
if (!role) return false;
|
if (!role) return false;
|
||||||
|
|
||||||
@ -164,7 +156,6 @@ export class MerchantUsersList implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
private fallbackPermissions(): void {
|
private fallbackPermissions(): void {
|
||||||
this.currentUserRole = this.authService.getCurrentUserRole();
|
this.currentUserRole = this.authService.getCurrentUserRole();
|
||||||
this.currentMerchantPartnerId = this.authService.getCurrentMerchantPartnerId() || '';
|
|
||||||
this.canViewAllMerchants = this.canViewAllMerchantsCheck(this.currentUserRole);
|
this.canViewAllMerchants = this.canViewAllMerchantsCheck(this.currentUserRole);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,20 +172,12 @@ export class MerchantUsersList implements OnInit, OnDestroy {
|
|||||||
this.loading = true;
|
this.loading = true;
|
||||||
this.error = '';
|
this.error = '';
|
||||||
|
|
||||||
let usersObservable: Observable<User[]>;
|
const usersObservable: Observable<User[]> = this.canViewAllMerchants
|
||||||
|
? this.merchantUsersService
|
||||||
|
.getMerchantUsers(this.currentPage, this.itemsPerPage)
|
||||||
|
.pipe(map((response: PaginatedUserResponse) => response.users))
|
||||||
|
: of([]); // fallback propre
|
||||||
|
|
||||||
if (this.canViewAllMerchants) {
|
|
||||||
// Admin/Support accédant au contexte Merchant
|
|
||||||
usersObservable = this.merchantUsersService.getMerchantUsers(this.currentPage, this.itemsPerPage).pipe(
|
|
||||||
map((response: PaginatedUserResponse) => response.users)
|
|
||||||
);
|
|
||||||
} else if (this.currentMerchantPartnerId) {
|
|
||||||
// Merchant régulier voyant son équipe
|
|
||||||
usersObservable = this.merchantUsersService.getMerchantUsersByPartner(this.currentMerchantPartnerId);
|
|
||||||
} else {
|
|
||||||
// Fallback
|
|
||||||
usersObservable = this.merchantUsersService.getMyMerchantUsers();
|
|
||||||
}
|
|
||||||
|
|
||||||
usersObservable
|
usersObservable
|
||||||
.pipe(
|
.pipe(
|
||||||
|
|||||||
@ -66,7 +66,7 @@ export class MerchantUserProfile implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
// Getters pour la logique conditionnelle
|
// Getters pour la logique conditionnelle
|
||||||
get isMerchantPartnerUser(): boolean {
|
get isMerchantPartnerUser(): boolean {
|
||||||
return UserUtils.isMerchantPartnerUser(this.user!);
|
return UserUtils.isMerchantUser(this.user!);
|
||||||
}
|
}
|
||||||
|
|
||||||
userHasRole(user: User, role: UserRole): boolean {
|
userHasRole(user: User, role: UserRole): boolean {
|
||||||
|
|||||||
@ -136,80 +136,6 @@
|
|||||||
|
|
||||||
<form (ngSubmit)="createUser()" #userForm="ngForm">
|
<form (ngSubmit)="createUser()" #userForm="ngForm">
|
||||||
<div class="row g-3">
|
<div class="row g-3">
|
||||||
<!-- Merchant Partner ID - Uniquement pour DCB_PARTNER et DCB_PARTNER_ADMIN -->
|
|
||||||
@if (showMerchantPartnerIdField) {
|
|
||||||
<div class="col-12">
|
|
||||||
<div class="card border-primary">
|
|
||||||
<div class="card-header bg-primary text-white py-2">
|
|
||||||
<div class="d-flex align-items-center">
|
|
||||||
<ng-icon name="lucideBuilding" class="me-2"></ng-icon>
|
|
||||||
<span class="small">Votre Organisation Marchande</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<!-- Information du partenaire -->
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="form-control-plaintext">
|
|
||||||
VOUS
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-6">
|
|
||||||
<label class="form-label small fw-bold">Merchant Partner ID</label>
|
|
||||||
<div class="form-control-plaintext font-monospace small">
|
|
||||||
@if (currentMerchantPartnerId) {
|
|
||||||
<span class="text-success">{{ currentMerchantPartnerId }}</span>
|
|
||||||
<ng-icon name="lucideCheckCircle" class="text-success ms-1"></ng-icon>
|
|
||||||
} @else {
|
|
||||||
<span class="text-warning">Chargement...</span>
|
|
||||||
<ng-icon name="lucideLoader" class="text-warning ms-1"></ng-icon>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Champ caché pour le formulaire -->
|
|
||||||
<input
|
|
||||||
type="hidden"
|
|
||||||
[(ngModel)]="newUser.merchantPartnerId"
|
|
||||||
name="merchantPartnerId"
|
|
||||||
[value]="currentMerchantPartnerId"
|
|
||||||
required
|
|
||||||
>
|
|
||||||
|
|
||||||
<!-- Messages d'information -->
|
|
||||||
@if (!currentMerchantPartnerId) {
|
|
||||||
<div class="alert alert-warning mt-2 mb-0">
|
|
||||||
<div class="d-flex align-items-center">
|
|
||||||
<ng-icon name="lucideAlertTriangle" class="me-2"></ng-icon>
|
|
||||||
<div>
|
|
||||||
<small>
|
|
||||||
<strong>Merchant Partner ID non disponible</strong><br>
|
|
||||||
Impossible de récupérer votre identifiant de partenaire.
|
|
||||||
Veuillez contacter l'administrateur.
|
|
||||||
</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
} @else {
|
|
||||||
<div class="alert alert-info mt-2 mb-0">
|
|
||||||
<div class="d-flex align-items-center">
|
|
||||||
<ng-icon name="lucideInfo" class="me-2"></ng-icon>
|
|
||||||
<div>
|
|
||||||
<small>
|
|
||||||
<strong>Information :</strong>
|
|
||||||
Cet utilisateur sera automatiquement associé à votre organisation marchande.
|
|
||||||
Vous ne pouvez pas modifier cette association.
|
|
||||||
</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
<!-- Informations de base -->
|
<!-- Informations de base -->
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
@ -409,108 +335,6 @@
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
<!-- Sélection du partenaire marchand -->
|
|
||||||
@if (showMerchantPartnerField) {
|
|
||||||
<div class="col-12">
|
|
||||||
<label class="form-label">
|
|
||||||
Partenaire Marchand
|
|
||||||
@if (requireMerchantPartnerSelection) {
|
|
||||||
<span class="text-danger">*</span>
|
|
||||||
}
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<!-- État de chargement -->
|
|
||||||
@if (loadingMerchantPartners) {
|
|
||||||
<div class="form-control">
|
|
||||||
<div class="d-flex align-items-center">
|
|
||||||
<div class="spinner-border spinner-border-sm me-2" role="status">
|
|
||||||
<span class="visually-hidden">Chargement...</span>
|
|
||||||
</div>
|
|
||||||
<span class="text-muted">Chargement des partenaires marchands...</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
<!-- État d'erreur -->
|
|
||||||
@else if (merchantPartnersError) {
|
|
||||||
<div class="alert alert-warning">
|
|
||||||
<div class="d-flex align-items-center justify-content-between">
|
|
||||||
<div>
|
|
||||||
<ng-icon name="lucideAlertTriangle" class="me-2"></ng-icon>
|
|
||||||
{{ merchantPartnersError }}
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
class="btn btn-sm btn-outline-warning"
|
|
||||||
(click)="reloadMerchantPartners()"
|
|
||||||
>
|
|
||||||
<ng-icon name="lucideRefreshCw" class="me-1"></ng-icon>
|
|
||||||
Réessayer
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
<!-- Sélecteur normal -->
|
|
||||||
@else if (merchantPartners.length > 0) {
|
|
||||||
<select
|
|
||||||
class="form-select"
|
|
||||||
[(ngModel)]="selectedMerchantPartnerId"
|
|
||||||
(change)="onPartnerSelectionChange($any($event.target).value)"
|
|
||||||
name="merchantPartnerId"
|
|
||||||
[required]="requireMerchantPartnerSelection"
|
|
||||||
[disabled]="creatingUser"
|
|
||||||
>
|
|
||||||
<option value="" disabled>
|
|
||||||
@if (merchantPartners.length > 1) {
|
|
||||||
Sélectionnez un partenaire marchand
|
|
||||||
} @else {
|
|
||||||
Partenaire unique disponible
|
|
||||||
}
|
|
||||||
</option>
|
|
||||||
|
|
||||||
<!-- Liste des partenaires pour les admins Hub -->
|
|
||||||
@for (partner of merchantPartners; track partner.id) {
|
|
||||||
<option [value]="partner.id">
|
|
||||||
{{ partner.username }}
|
|
||||||
@if (!partner.enabled) {
|
|
||||||
<span class="badge bg-warning ms-1">Inactif</span>
|
|
||||||
}
|
|
||||||
</option>
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<div class="form-text">
|
|
||||||
{{ merchantSelectionHelpText }}
|
|
||||||
|
|
||||||
@if (merchantPartners.length === 1) {
|
|
||||||
<span class="text-info">
|
|
||||||
<ng-icon name="lucideInfo" class="me-1"></ng-icon>
|
|
||||||
Un seul partenaire disponible - sélectionné automatiquement
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
<!-- Aucun partenaire disponible -->
|
|
||||||
@else {
|
|
||||||
<div class="alert alert-danger">
|
|
||||||
<ng-icon name="lucideXCircle" class="me-2"></ng-icon>
|
|
||||||
Aucun partenaire marchand disponible.
|
|
||||||
Veuillez contacter l'administrateur système.
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
<!-- Message d'erreur de validation -->
|
|
||||||
@if (requireMerchantPartnerSelection && !selectedMerchantPartnerId && !loadingMerchantPartners) {
|
|
||||||
<div class="text-danger small mt-1">
|
|
||||||
<ng-icon name="lucideAlertCircle" class="me-1"></ng-icon>
|
|
||||||
La sélection d'un partenaire marchand est obligatoire
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@if (newUser.role) {
|
@if (newUser.role) {
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="alert alert-info">
|
<div class="alert alert-info">
|
||||||
@ -575,7 +399,6 @@
|
|||||||
<div class="alert alert-light">
|
<div class="alert alert-light">
|
||||||
<small class="text-muted">
|
<small class="text-muted">
|
||||||
<strong>Informations système :</strong><br>
|
<strong>Informations système :</strong><br>
|
||||||
• Merchant Partner ID : {{ currentMerchantPartnerId || 'Chargement...' }}<br>
|
|
||||||
• Type d'utilisateur : MERCHANT<br>
|
• Type d'utilisateur : MERCHANT<br>
|
||||||
• Créé par : Utilisateur courant<br>
|
• Créé par : Utilisateur courant<br>
|
||||||
• Votre rôle : {{ currentUserRole || 'Non défini' }}
|
• Votre rôle : {{ currentUserRole || 'Non défini' }}
|
||||||
@ -597,7 +420,7 @@
|
|||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
class="btn btn-primary"
|
class="btn btn-primary"
|
||||||
[disabled]="!userForm.form.valid || creatingUser || !selectedMerchantPartnerId"
|
[disabled]="!userForm.form.valid || creatingUser"
|
||||||
>
|
>
|
||||||
@if (creatingUser) {
|
@if (creatingUser) {
|
||||||
<div class="spinner-border spinner-border-sm me-2" role="status">
|
<div class="spinner-border spinner-border-sm me-2" role="status">
|
||||||
|
|||||||
@ -57,17 +57,7 @@ export class MerchantUsersService {
|
|||||||
private http = inject(HttpClient);
|
private http = inject(HttpClient);
|
||||||
private baseApiUrl = `${environment.iamApiUrl}/merchant-users`;
|
private baseApiUrl = `${environment.iamApiUrl}/merchant-users`;
|
||||||
|
|
||||||
getUserMerchantPartnerId(userId: string): Observable<string | null> {
|
// === MÉTHODES SPÉCIFIQUES MERCHANT ===
|
||||||
return this.http.get<MerchantPartnerIdResponse>(`${this.baseApiUrl}/merchant-partner/${userId}`).pipe(
|
|
||||||
map(response => response.merchantPartnerId),
|
|
||||||
catchError(error => {
|
|
||||||
console.error(`Error loading merchant partner ID for user ${userId}:`, error);
|
|
||||||
return throwError(() => error);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// === MÉTHODES SPÉCIFIQUES MERCHANT ===
|
|
||||||
|
|
||||||
createMerchantUser(createUserDto: CreateUserDto): Observable<User> {
|
createMerchantUser(createUserDto: CreateUserDto): Observable<User> {
|
||||||
// Utiliser la validation centralisée
|
// Utiliser la validation centralisée
|
||||||
@ -97,8 +87,6 @@ export class MerchantUsersService {
|
|||||||
role: createUserDto.role,
|
role: createUserDto.role,
|
||||||
enabled: createUserDto.enabled !== undefined ? createUserDto.enabled : true,
|
enabled: createUserDto.enabled !== undefined ? createUserDto.enabled : true,
|
||||||
emailVerified: createUserDto.emailVerified !== undefined ? createUserDto.emailVerified : true,
|
emailVerified: createUserDto.emailVerified !== undefined ? createUserDto.emailVerified : true,
|
||||||
merchantPartnerId: createUserDto.merchantPartnerId?.trim() || null,
|
|
||||||
//merchantConfigId: createUserDto.merchantConfigId?.trim() || null,
|
|
||||||
userType: createUserDto.userType.trim()
|
userType: createUserDto.userType.trim()
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -121,12 +109,6 @@ export class MerchantUsersService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getMerchantUsersByPartner(partnerId: string): Observable<User[]> {
|
|
||||||
return this.getMyMerchantUsers().pipe(
|
|
||||||
map(users => users.filter(user => user.merchantPartnerId === partnerId))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
getMerchantUserById(id: string | undefined): Observable<User> {
|
getMerchantUserById(id: string | undefined): Observable<User> {
|
||||||
return this.http.get<User>(`${this.baseApiUrl}/${id}`).pipe(
|
return this.http.get<User>(`${this.baseApiUrl}/${id}`).pipe(
|
||||||
map(user => this.mapToUserModel(user, UserType.MERCHANT_PARTNER)),
|
map(user => this.mapToUserModel(user, UserType.MERCHANT_PARTNER)),
|
||||||
@ -290,8 +272,6 @@ export class MerchantUsersService {
|
|||||||
enabled: apiUser.enabled,
|
enabled: apiUser.enabled,
|
||||||
emailVerified: apiUser.emailVerified,
|
emailVerified: apiUser.emailVerified,
|
||||||
userType: userType,
|
userType: userType,
|
||||||
merchantPartnerId: apiUser.merchantPartnerId,
|
|
||||||
merchantConfigId: apiUser.merchantConfigId,
|
|
||||||
role: apiUser.role,
|
role: apiUser.role,
|
||||||
createdBy: apiUser.createdBy,
|
createdBy: apiUser.createdBy,
|
||||||
createdByUsername: apiUser.createdByUsername,
|
createdByUsername: apiUser.createdByUsername,
|
||||||
@ -330,10 +310,6 @@ export class MerchantUsersService {
|
|||||||
if (filters.userType) {
|
if (filters.userType) {
|
||||||
filteredUsers = filteredUsers.filter(user => user.userType === filters.userType);
|
filteredUsers = filteredUsers.filter(user => user.userType === filters.userType);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.merchantPartnerId) {
|
|
||||||
filteredUsers = filteredUsers.filter(user => user.merchantPartnerId === filters.merchantPartnerId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pagination côté client
|
// Pagination côté client
|
||||||
|
|||||||
@ -60,7 +60,6 @@ export class MerchantUsersManagement implements OnInit, OnDestroy {
|
|||||||
// Gestion des permissions
|
// Gestion des permissions
|
||||||
currentUserRole: UserRole | null = null;
|
currentUserRole: UserRole | null = null;
|
||||||
currentUserType: UserType | null = null;
|
currentUserType: UserType | null = null;
|
||||||
currentMerchantPartnerId: string = '';
|
|
||||||
userPermissions: any = null;
|
userPermissions: any = null;
|
||||||
canCreateUsers = false;
|
canCreateUsers = false;
|
||||||
canDeleteUsers = false;
|
canDeleteUsers = false;
|
||||||
@ -76,7 +75,6 @@ export class MerchantUsersManagement implements OnInit, OnDestroy {
|
|||||||
role: UserRole;
|
role: UserRole;
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
emailVerified: boolean;
|
emailVerified: boolean;
|
||||||
merchantPartnerId: string;
|
|
||||||
userType: UserType;
|
userType: UserType;
|
||||||
} = this.getDefaultUserForm();
|
} = this.getDefaultUserForm();
|
||||||
|
|
||||||
@ -123,130 +121,23 @@ export class MerchantUsersManagement implements OnInit, OnDestroy {
|
|||||||
this.loadAvailableRoles();
|
this.loadAvailableRoles();
|
||||||
this.newUser.role = UserRole.DCB_PARTNER_SUPPORT;
|
this.newUser.role = UserRole.DCB_PARTNER_SUPPORT;
|
||||||
|
|
||||||
// Charger la liste des partenaires marchands (pour les admins Hub)
|
|
||||||
if (this.currentUserRole === UserRole.DCB_ADMIN ||
|
|
||||||
this.currentUserRole === UserRole.DCB_SUPPORT) {
|
|
||||||
|
|
||||||
this.loadMerchantPartners();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialiser le formulaire selon le contexte
|
|
||||||
this.initializeMerchantPartner();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
constructor() {}
|
constructor() {}
|
||||||
|
|
||||||
// Initialiser le merchant partner selon le contexte
|
|
||||||
initializeMerchantPartner() {
|
|
||||||
if (this.currentUserRole === UserRole.DCB_PARTNER && this.currentMerchantPartnerId) {
|
|
||||||
// Auto-sélection pour DCB_PARTNER
|
|
||||||
this.selectedMerchantPartnerId = this.currentMerchantPartnerId;
|
|
||||||
}else if (this.currentUserRole === UserRole.DCB_PARTNER_ADMIN && this.currentMerchantPartnerId) {
|
|
||||||
// Auto-sélection pour DCB_PARTNER_ADMIN
|
|
||||||
this.selectedMerchantPartnerId = this.currentMerchantPartnerId;
|
|
||||||
} else if ((this.currentUserRole === UserRole.DCB_ADMIN ||
|
|
||||||
this.currentUserRole === UserRole.DCB_SUPPORT) &&
|
|
||||||
this.isMerchantRole(this.newUser.role)) {
|
|
||||||
// Forcer la sélection pour les admins Hub créant des users marchands
|
|
||||||
this.selectedMerchantPartnerId = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onRoleSelectionChange(selectedRole: UserRole) {
|
onRoleSelectionChange(selectedRole: UserRole) {
|
||||||
this.newUser.role = selectedRole;
|
this.newUser.role = selectedRole;
|
||||||
}
|
}
|
||||||
|
|
||||||
onPartnerSelectionChange(selectedPartner: User) {
|
|
||||||
this.newUser.merchantPartnerId = this.selectedMerchantPartnerId || '';
|
|
||||||
|
|
||||||
this.currentMerchantPartnerId = this.selectedMerchantPartnerId || ''
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Recharge les partenaires marchands (pour retry)
|
|
||||||
*/
|
|
||||||
reloadMerchantPartners(): void {
|
|
||||||
console.log('🔄 Rechargement des partenaires marchands...');
|
|
||||||
this.loadMerchantPartners();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Charge la liste des partenaires marchands
|
|
||||||
*/
|
|
||||||
loadMerchantPartners(): void {
|
|
||||||
this.loadingMerchantPartners = true;
|
|
||||||
this.merchantPartnersError = '';
|
|
||||||
|
|
||||||
console.log('🔄 Chargement des partenaires marchands...');
|
|
||||||
|
|
||||||
this.hubUsersService.getAllDcbPartners()
|
|
||||||
.pipe(
|
|
||||||
map((response: PaginatedUserResponse) => response.users),
|
|
||||||
takeUntil(this.destroy$),
|
|
||||||
catchError(error => {
|
|
||||||
console.error('Error loading hub users:', error);
|
|
||||||
this.loadingMerchantPartners = false;
|
|
||||||
this.merchantPartnersError = 'Impossible de charger la liste des partenaires marchands';
|
|
||||||
return of([] as User[]);
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.subscribe(
|
|
||||||
{next: (partners) => {
|
|
||||||
this.merchantPartners = partners;
|
|
||||||
this.loadingMerchantPartners = false;
|
|
||||||
|
|
||||||
console.log(`✅ ${partners.length} partenaires marchands chargés`, partners);
|
|
||||||
|
|
||||||
},
|
|
||||||
error: (error) => {
|
|
||||||
console.error('❌ Erreur lors du chargement des partenaires marchands:', error);
|
|
||||||
this.loadingMerchantPartners = false;
|
|
||||||
this.merchantPartnersError = 'Impossible de charger la liste des partenaires marchands';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Vérifie si l'utilisateur connecté est un DCB_PARTNER ou DCB_PARTNER_ADMIN
|
* Vérifie si l'utilisateur connecté est un DCB_PARTNER ou DCB_PARTNER_ADMIN
|
||||||
*/
|
*/
|
||||||
get isPartnerUser(): boolean {
|
get isMerchantUser(): boolean {
|
||||||
return this.currentUserRole === UserRole.DCB_PARTNER ||
|
return this.currentUserRole === UserRole.DCB_PARTNER_ADMIN ||
|
||||||
this.currentUserRole === UserRole.DCB_PARTNER_ADMIN;
|
this.currentUserRole === UserRole.DCB_PARTNER_MANAGER||
|
||||||
}
|
this.currentUserRole === UserRole.DCB_PARTNER_SUPPORT;
|
||||||
|
|
||||||
/**
|
|
||||||
* Vérifie si on doit afficher le champ Merchant Partner ID
|
|
||||||
*/
|
|
||||||
get showMerchantPartnerIdField(): boolean {
|
|
||||||
return this.isPartnerUser && this.isMerchantRole(this.newUser.role);
|
|
||||||
}
|
|
||||||
|
|
||||||
get showMerchantPartnerField(): boolean {
|
|
||||||
if (this.isMerchantRole(this.newUser.role) && !this.isPartnerUser) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
get requireMerchantPartnerSelection(): boolean {
|
|
||||||
// Si l'utilisateur connecté est un admin/support Hub ET qu'il crée un utilisateur marchand
|
|
||||||
const isHubAdminCreatingMerchant =
|
|
||||||
(this.currentUserRole === UserRole.DCB_ADMIN ||
|
|
||||||
this.currentUserRole === UserRole.DCB_SUPPORT) &&
|
|
||||||
this.isMerchantRole(this.newUser.role);
|
|
||||||
return isHubAdminCreatingMerchant;
|
|
||||||
}
|
|
||||||
|
|
||||||
get merchantSelectionHelpText(): string {
|
|
||||||
if (this.currentUserRole === UserRole.DCB_ADMIN ||
|
|
||||||
this.currentUserRole === UserRole.DCB_SUPPORT) {
|
|
||||||
return 'En tant qu\'administrateur Hub, vous devez sélectionner un partenaire marchand pour cet utilisateur';
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'Sélectionnez le partenaire marchand auquel cet utilisateur sera associé';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
@ -264,16 +155,9 @@ export class MerchantUsersManagement implements OnInit, OnDestroy {
|
|||||||
next: (user) => {
|
next: (user) => {
|
||||||
this.currentUserRole = this.extractUserRole(user);
|
this.currentUserRole = this.extractUserRole(user);
|
||||||
|
|
||||||
if(user?.role.includes(UserRole.DCB_PARTNER)){
|
|
||||||
this.currentMerchantPartnerId = user.id;
|
|
||||||
} else {
|
|
||||||
this.currentMerchantPartnerId = this.extractMerchantPartnerId(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.currentUserType = this.extractUserType(user);
|
this.currentUserType = this.extractUserType(user);
|
||||||
|
|
||||||
console.log(`MERCHANT User ROLE: ${this.currentUserRole}`);
|
console.log(`MERCHANT User ROLE: ${this.currentUserRole}`);
|
||||||
console.log(`Merchant Partner ID: ${this.currentMerchantPartnerId}`);
|
|
||||||
|
|
||||||
if (this.currentUserRole) {
|
if (this.currentUserRole) {
|
||||||
this.roleService.setCurrentUserRole(this.currentUserRole);
|
this.roleService.setCurrentUserRole(this.currentUserRole);
|
||||||
@ -286,12 +170,9 @@ export class MerchantUsersManagement implements OnInit, OnDestroy {
|
|||||||
console.log('Assignable roles:', this.assignableRoles);
|
console.log('Assignable roles:', this.assignableRoles);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialiser le merchantPartnerId
|
|
||||||
this.newUser.merchantPartnerId = this.currentMerchantPartnerId;
|
|
||||||
},
|
},
|
||||||
error: (error) => {
|
error: (error) => {
|
||||||
console.error('Error loading user profile:', error);
|
console.error('Error loading user profile:', error);
|
||||||
this.fallbackPermissions();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -315,30 +196,6 @@ export class MerchantUsersManagement implements OnInit, OnDestroy {
|
|||||||
return userType || null;
|
return userType || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Extraire le merchantPartnerId
|
|
||||||
*/
|
|
||||||
private extractMerchantPartnerId(user: any): string {
|
|
||||||
if (user?.merchantPartnerId) {
|
|
||||||
return user.merchantPartnerId;
|
|
||||||
}
|
|
||||||
return this.authService.getCurrentMerchantPartnerId() || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fallback en cas d'erreur de chargement du profil
|
|
||||||
*/
|
|
||||||
private fallbackPermissions(): void {
|
|
||||||
this.currentUserRole = this.authService.getCurrentUserRole();
|
|
||||||
this.currentMerchantPartnerId = this.authService.getCurrentMerchantPartnerId() || '';
|
|
||||||
|
|
||||||
if (this.currentUserRole) {
|
|
||||||
this.canCreateUsers = this.roleService.canCreateUsers(this.currentUserRole);
|
|
||||||
this.canDeleteUsers = this.roleService.canDeleteUsers(this.currentUserRole);
|
|
||||||
this.canManageRoles = this.roleService.canManageRoles(this.currentUserRole);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Charge les rôles disponibles
|
* Charge les rôles disponibles
|
||||||
*/
|
*/
|
||||||
@ -356,22 +213,10 @@ export class MerchantUsersManagement implements OnInit, OnDestroy {
|
|||||||
},
|
},
|
||||||
error: (error) => {
|
error: (error) => {
|
||||||
console.error('Error loading available roles:', error);
|
console.error('Error loading available roles:', error);
|
||||||
this.availableRoles = this.getFallbackRoles();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Rôles par défaut en cas d'erreur
|
|
||||||
*/
|
|
||||||
private getFallbackRoles(): any[] {
|
|
||||||
return [
|
|
||||||
{ value: UserRole.DCB_PARTNER_ADMIN, label: 'Partner Admin', description: 'Administrateur partenaire' },
|
|
||||||
{ value: UserRole.DCB_PARTNER_MANAGER, label: 'Partner Manager', description: 'Manager partenaire' },
|
|
||||||
{ value: UserRole.DCB_PARTNER_SUPPORT, label: 'Partner Support', description: 'Support partenaire' }
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
private getDefaultUserForm() {
|
private getDefaultUserForm() {
|
||||||
return {
|
return {
|
||||||
username: '',
|
username: '',
|
||||||
@ -382,7 +227,6 @@ export class MerchantUsersManagement implements OnInit, OnDestroy {
|
|||||||
role: UserRole.DCB_PARTNER_SUPPORT,
|
role: UserRole.DCB_PARTNER_SUPPORT,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
emailVerified: false,
|
emailVerified: false,
|
||||||
merchantPartnerId: '',
|
|
||||||
userType: UserType.MERCHANT_PARTNER
|
userType: UserType.MERCHANT_PARTNER
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -492,7 +336,6 @@ export class MerchantUsersManagement implements OnInit, OnDestroy {
|
|||||||
role: UserRole.DCB_PARTNER_SUPPORT,
|
role: UserRole.DCB_PARTNER_SUPPORT,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
emailVerified: false,
|
emailVerified: false,
|
||||||
merchantPartnerId: this.selectedMerchantPartnerId,
|
|
||||||
userType: UserType.MERCHANT_PARTNER,
|
userType: UserType.MERCHANT_PARTNER,
|
||||||
};
|
};
|
||||||
console.log('🔄 Merchant user form reset');
|
console.log('🔄 Merchant user form reset');
|
||||||
@ -567,12 +410,6 @@ export class MerchantUsersManagement implements OnInit, OnDestroy {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validation spécifique au contexte marchand
|
|
||||||
if (!this.newUser.merchantPartnerId) {
|
|
||||||
this.createUserError = 'Merchant Partner ID est requis pour les utilisateurs marchands';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.creatingUser = true;
|
this.creatingUser = true;
|
||||||
this.createUserError = '';
|
this.createUserError = '';
|
||||||
|
|
||||||
@ -782,8 +619,7 @@ export class MerchantUsersManagement implements OnInit, OnDestroy {
|
|||||||
{ field: this.newUser.username?.trim(), name: 'Nom d\'utilisateur' },
|
{ field: this.newUser.username?.trim(), name: 'Nom d\'utilisateur' },
|
||||||
{ field: this.newUser.email?.trim(), name: 'Email' },
|
{ field: this.newUser.email?.trim(), name: 'Email' },
|
||||||
{ field: this.newUser.firstName?.trim(), name: 'Prénom' },
|
{ field: this.newUser.firstName?.trim(), name: 'Prénom' },
|
||||||
{ field: this.newUser.lastName?.trim(), name: 'Nom' },
|
{ field: this.newUser.lastName?.trim(), name: 'Nom' }
|
||||||
{ field: this.selectedMerchantPartnerId?.trim(), name: 'Merchant Partner ID' }
|
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const { field, name } of requiredFields) {
|
for (const { field, name } of requiredFields) {
|
||||||
|
|||||||
@ -156,12 +156,6 @@ export class MerchantConfigsList implements OnInit, OnDestroy {
|
|||||||
next: (user) => {
|
next: (user) => {
|
||||||
this.currentUserRole = this.extractUserRole(user);
|
this.currentUserRole = this.extractUserRole(user);
|
||||||
|
|
||||||
if(user?.role.includes(UserRole.DCB_PARTNER)){
|
|
||||||
this.currentMerchantConfigId = user.merchantConfigId;
|
|
||||||
} else {
|
|
||||||
this.currentMerchantConfigId = this.extractMerchantConfigId(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.canViewAllMerchants = this.canViewAllMerchantsCheck(this.currentUserRole);
|
this.canViewAllMerchants = this.canViewAllMerchantsCheck(this.currentUserRole);
|
||||||
|
|
||||||
console.log(`MERCHANT User ROLE: ${this.currentUserRole}`);
|
console.log(`MERCHANT User ROLE: ${this.currentUserRole}`);
|
||||||
|
|||||||
@ -679,127 +679,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li [ngbNavItem]="'users'">
|
|
||||||
<a ngbNavLink>
|
|
||||||
<ng-icon name="lucideUser" class="me-2"></ng-icon>
|
|
||||||
Utilisateurs
|
|
||||||
@if (merchant.users.length > 0) {
|
|
||||||
<span class="badge bg-primary ms-1">{{ merchant.users.length }}</span>
|
|
||||||
}
|
|
||||||
</a>
|
|
||||||
<ng-template ngbNavContent>
|
|
||||||
<!-- Onglet Utilisateurs -->
|
|
||||||
<div class="p-3">
|
|
||||||
<h5 class="mb-4">
|
|
||||||
<ng-icon name="lucideUser" class="me-2"></ng-icon>
|
|
||||||
Utilisateurs associés
|
|
||||||
</h5>
|
|
||||||
|
|
||||||
@if (merchant.users.length > 0) {
|
|
||||||
<div class="row g-3">
|
|
||||||
@for (user of paginatedUsers; track trackByUserId($index, user)) {
|
|
||||||
<div class="col-12">
|
|
||||||
<div class="section-card">
|
|
||||||
<div class="section-content">
|
|
||||||
<div class="row align-items-center">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="d-flex align-items-center">
|
|
||||||
<div class="user-badge me-3">
|
|
||||||
<ng-icon name="lucideUser" class="text-muted"></ng-icon>
|
|
||||||
<span>{{ user.username }}</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="fw-semibold">{{ user.email }}</div>
|
|
||||||
@if (isEditingUserRole(user.userId)) {
|
|
||||||
<select
|
|
||||||
class="form-select form-select-sm"
|
|
||||||
[(ngModel)]="newUserRole"
|
|
||||||
style="width: auto; display: inline-block;"
|
|
||||||
>
|
|
||||||
@for (role of getAvailableUserRoles(); track role.value) {
|
|
||||||
<option [value]="role.value">{{ role.label }}</option>
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
} @else {
|
|
||||||
<span [ngClass]="getUserRoleBadgeClass(user.role)" class="badge">
|
|
||||||
{{ getUserRoleLabel(user.role) }}
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6 text-md-end">
|
|
||||||
<small class="text-muted me-3">
|
|
||||||
Partner ID: {{ user.merchantPartnerId }}
|
|
||||||
</small>
|
|
||||||
|
|
||||||
@if (canEditUserRole()) {
|
|
||||||
@if (isEditingUserRole(user.userId)) {
|
|
||||||
<div class="d-flex gap-2 justify-content-end">
|
|
||||||
<button
|
|
||||||
class="btn btn-outline-secondary btn-sm"
|
|
||||||
(click)="cancelEditingUserRole()"
|
|
||||||
[disabled]="saving"
|
|
||||||
>
|
|
||||||
Annuler
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="btn btn-success btn-sm"
|
|
||||||
(click)="updateUserRole(user)"
|
|
||||||
[disabled]="saving || !newUserRole"
|
|
||||||
>
|
|
||||||
@if (saving) {
|
|
||||||
<div class="spinner-border spinner-border-sm me-1" role="status">
|
|
||||||
<span class="visually-hidden">Chargement...</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
Valider
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
} @else {
|
|
||||||
<button
|
|
||||||
class="btn btn-outline-primary btn-sm"
|
|
||||||
(click)="startEditingUserRole(user)"
|
|
||||||
>
|
|
||||||
<ng-icon name="lucideEdit" class="me-1"></ng-icon>
|
|
||||||
Modifier le rôle
|
|
||||||
</button>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Pagination -->
|
|
||||||
@if (totalPages > 1) {
|
|
||||||
<div class="d-flex justify-content-center mt-4">
|
|
||||||
<ngb-pagination
|
|
||||||
[collectionSize]="merchant.users.length"
|
|
||||||
[page]="page"
|
|
||||||
[pageSize]="pageSize"
|
|
||||||
(pageChange)="page = $event"
|
|
||||||
[maxSize]="5"
|
|
||||||
[boundaryLinks]="true"
|
|
||||||
></ngb-pagination>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
} @else {
|
|
||||||
<div class="text-center py-5">
|
|
||||||
<div class="text-muted">
|
|
||||||
<ng-icon name="lucideUser" class="fs-1 mb-3 opacity-50"></ng-icon>
|
|
||||||
<h5 class="mb-2">Aucun utilisateur</h5>
|
|
||||||
<p class="mb-0">Aucun utilisateur n'est associé à ce marchand.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</ng-template>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div [ngbNavOutlet]="nav" class="mt-3"></div>
|
<div [ngbNavOutlet]="nav" class="mt-3"></div>
|
||||||
|
|||||||
@ -290,7 +290,6 @@ export class MerchantConfigView implements OnInit, OnDestroy {
|
|||||||
.subscribe({
|
.subscribe({
|
||||||
next: (profile) => {
|
next: (profile) => {
|
||||||
this.currentUserRole = this.authService.getCurrentUserRole();
|
this.currentUserRole = this.authService.getCurrentUserRole();
|
||||||
this.currentMerchantPartnerId = this.authService.getCurrentMerchantPartnerId() || '';
|
|
||||||
this.cdRef.detectChanges();
|
this.cdRef.detectChanges();
|
||||||
},
|
},
|
||||||
error: (error) => {
|
error: (error) => {
|
||||||
@ -693,7 +692,7 @@ export class MerchantConfigView implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
getAvailableUserRoles(): { value: UserRole, label: string }[] {
|
getAvailableUserRoles(): { value: UserRole, label: string }[] {
|
||||||
return [
|
return [
|
||||||
{ value: UserRole.DCB_PARTNER, label: 'Partenaire' },
|
//{ value: UserRole.DCB_PARTNER, label: 'Partenaire' },
|
||||||
{ value: UserRole.DCB_PARTNER_ADMIN, label: 'Admin Partenaire' },
|
{ value: UserRole.DCB_PARTNER_ADMIN, label: 'Admin Partenaire' },
|
||||||
{ value: UserRole.DCB_ADMIN, label: 'Administrateur' },
|
{ value: UserRole.DCB_ADMIN, label: 'Administrateur' },
|
||||||
{ value: UserRole.DCB_SUPPORT, label: 'Support' }
|
{ value: UserRole.DCB_SUPPORT, label: 'Support' }
|
||||||
@ -711,7 +710,7 @@ export class MerchantConfigView implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
// Un admin partenaire peut assigner des rôles partenaire
|
// Un admin partenaire peut assigner des rôles partenaire
|
||||||
if (this.currentUserRole === UserRole.DCB_PARTNER_ADMIN) {
|
if (this.currentUserRole === UserRole.DCB_PARTNER_ADMIN) {
|
||||||
return [UserRole.DCB_PARTNER, UserRole.DCB_PARTNER_ADMIN].includes(role);
|
return [UserRole.DCB_PARTNER_ADMIN].includes(role);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -162,7 +162,7 @@ export class MerchantConfigManagement implements OnInit, OnDestroy {
|
|||||||
this.currentUserRole = this.authService.getCurrentUserRole();
|
this.currentUserRole = this.authService.getCurrentUserRole();
|
||||||
|
|
||||||
// Déterminer si c'est un utilisateur marchand
|
// Déterminer si c'est un utilisateur marchand
|
||||||
if (this.currentUserRole === UserRole.DCB_PARTNER ||
|
if (//this.currentUserRole === UserRole.DCB_PARTNER ||
|
||||||
this.currentUserRole === UserRole.DCB_PARTNER_ADMIN ||
|
this.currentUserRole === UserRole.DCB_PARTNER_ADMIN ||
|
||||||
this.currentUserRole === UserRole.DCB_PARTNER_MANAGER ||
|
this.currentUserRole === UserRole.DCB_PARTNER_MANAGER ||
|
||||||
this.currentUserRole === UserRole.DCB_PARTNER_SUPPORT ||
|
this.currentUserRole === UserRole.DCB_PARTNER_SUPPORT ||
|
||||||
@ -251,9 +251,8 @@ export class MerchantConfigManagement implements OnInit, OnDestroy {
|
|||||||
this.loadingMerchantUsers = true;
|
this.loadingMerchantUsers = true;
|
||||||
this.merchantUsersError = '';
|
this.merchantUsersError = '';
|
||||||
|
|
||||||
this.merchantSyncService.getMerchantUsers(
|
this.merchantSyncService.getUsersByMerchant(
|
||||||
this.currentMerchantConfigId,
|
this.currentMerchantConfigId
|
||||||
this.currentMerchantPartnerId
|
|
||||||
)
|
)
|
||||||
.pipe(
|
.pipe(
|
||||||
takeUntil(this.destroy$),
|
takeUntil(this.destroy$),
|
||||||
@ -419,14 +418,7 @@ export class MerchantConfigManagement implements OnInit, OnDestroy {
|
|||||||
next: (user) => {
|
next: (user) => {
|
||||||
this.currentUserRole = this.extractUserRole(user);
|
this.currentUserRole = this.extractUserRole(user);
|
||||||
|
|
||||||
if (user?.role.includes(UserRole.DCB_PARTNER)) {
|
|
||||||
this.currentMerchantPartnerId = user.id;
|
|
||||||
this.currentMerchantConfigId = user.merchantConfigId;
|
|
||||||
} else {
|
|
||||||
|
|
||||||
this.currentMerchantPartnerId = user?.merchantPartnerId || '';
|
|
||||||
this.currentMerchantConfigId = this.extractMerchantConfigId(user);
|
this.currentMerchantConfigId = this.extractMerchantConfigId(user);
|
||||||
}
|
|
||||||
|
|
||||||
if (this.currentUserRole) {
|
if (this.currentUserRole) {
|
||||||
this.userPermissions = this.roleService.getPermissionsForRole(this.currentUserRole);
|
this.userPermissions = this.roleService.getPermissionsForRole(this.currentUserRole);
|
||||||
@ -496,7 +488,7 @@ export class MerchantConfigManagement implements OnInit, OnDestroy {
|
|||||||
// ==================== GESTION DES MARCHANDS ====================
|
// ==================== GESTION DES MARCHANDS ====================
|
||||||
|
|
||||||
private initializeMerchantPartnerContext(): void {
|
private initializeMerchantPartnerContext(): void {
|
||||||
if ((this.currentUserRole === UserRole.DCB_PARTNER ||
|
if ((//this.currentUserRole === UserRole.DCB_PARTNER ||
|
||||||
this.currentUserRole === UserRole.DCB_PARTNER_ADMIN) &&
|
this.currentUserRole === UserRole.DCB_PARTNER_ADMIN) &&
|
||||||
this.currentMerchantConfigId) {
|
this.currentMerchantConfigId) {
|
||||||
this.selectedMerchantConfigId = this.currentMerchantConfigId;
|
this.selectedMerchantConfigId = this.currentMerchantConfigId;
|
||||||
@ -551,8 +543,7 @@ export class MerchantConfigManagement implements OnInit, OnDestroy {
|
|||||||
if (!this.isMerchantUser) return false;
|
if (!this.isMerchantUser) return false;
|
||||||
|
|
||||||
// Seuls certains rôles marchands peuvent créer des utilisateurs
|
// Seuls certains rôles marchands peuvent créer des utilisateurs
|
||||||
return this.currentUserRole === UserRole.DCB_PARTNER ||
|
return this.currentUserRole === UserRole.DCB_PARTNER_ADMIN; //this.currentUserRole === UserRole.DCB_PARTNER ||
|
||||||
this.currentUserRole === UserRole.DCB_PARTNER_ADMIN;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -125,12 +125,6 @@
|
|||||||
<ng-icon name="lucideCalendar" class="me-2 text-muted"></ng-icon>
|
<ng-icon name="lucideCalendar" class="me-2 text-muted"></ng-icon>
|
||||||
<small>Membre depuis {{ getCreationDate() }}</small>
|
<small>Membre depuis {{ getCreationDate() }}</small>
|
||||||
</div>
|
</div>
|
||||||
@if (isMerchantUser()) {
|
|
||||||
<div class="d-flex align-items-center mt-2">
|
|
||||||
<ng-icon name="lucideBuilding" class="me-2 text-muted"></ng-icon>
|
|
||||||
<small>Partner ID: {{ getMerchantPartnerId() }}</small>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -193,14 +187,6 @@
|
|||||||
<span class="badge bg-secondary">{{ getUserTypeDisplay() }}</span>
|
<span class="badge bg-secondary">{{ getUserTypeDisplay() }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@if (isMerchantUser()) {
|
|
||||||
<div class="col-12">
|
|
||||||
<strong>Merchant Partner ID :</strong>
|
|
||||||
<div class="text-muted font-monospace small">
|
|
||||||
{{ getMerchantPartnerId() }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -394,14 +380,6 @@
|
|||||||
<span class="badge bg-secondary">{{ getUserTypeDisplay() }}</span>
|
<span class="badge bg-secondary">{{ getUserTypeDisplay() }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@if (isMerchantUser()) {
|
|
||||||
<div class="col-md-6">
|
|
||||||
<label class="form-label">Merchant Partner ID</label>
|
|
||||||
<div class="form-control-plaintext font-monospace small">
|
|
||||||
{{ getMerchantPartnerId() }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -319,7 +319,7 @@ export class MyProfile implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isMerchantUser(): boolean {
|
isMerchantUser(): boolean {
|
||||||
return UserUtils.isMerchantPartnerUser(this.user!);
|
return UserUtils.isMerchantUser(this.user!);
|
||||||
}
|
}
|
||||||
|
|
||||||
getUserTypeDisplay(): string {
|
getUserTypeDisplay(): string {
|
||||||
@ -332,10 +332,6 @@ export class MyProfile implements OnInit, OnDestroy {
|
|||||||
return this.formatTimestamp(this.user.createdTimestamp);
|
return this.formatTimestamp(this.user.createdTimestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
getMerchantPartnerId(): string {
|
|
||||||
return this.user?.merchantPartnerId || 'Non applicable';
|
|
||||||
}
|
|
||||||
|
|
||||||
refresh() {
|
refresh() {
|
||||||
this.loadUserProfile();
|
this.loadUserProfile();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -118,7 +118,6 @@ export class SubscriptionPaymentsList implements OnInit, OnDestroy {
|
|||||||
.subscribe({
|
.subscribe({
|
||||||
next: (user) => {
|
next: (user) => {
|
||||||
this.currentUserRole = this.extractUserRole(user);
|
this.currentUserRole = this.extractUserRole(user);
|
||||||
this.currentMerchantPartnerId = this.extractMerchantPartnerId(user);
|
|
||||||
|
|
||||||
console.log('Payments Context Loaded:', {
|
console.log('Payments Context Loaded:', {
|
||||||
role: this.currentUserRole,
|
role: this.currentUserRole,
|
||||||
@ -127,7 +126,6 @@ export class SubscriptionPaymentsList implements OnInit, OnDestroy {
|
|||||||
},
|
},
|
||||||
error: (error) => {
|
error: (error) => {
|
||||||
console.error('Error loading current user permissions:', error);
|
console.error('Error loading current user permissions:', error);
|
||||||
this.fallbackPermissions();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -140,17 +138,6 @@ export class SubscriptionPaymentsList implements OnInit, OnDestroy {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private extractMerchantPartnerId(user: any): string {
|
|
||||||
if (user?.merchantPartnerId) {
|
|
||||||
return user.merchantPartnerId;
|
|
||||||
}
|
|
||||||
return this.authService.getCurrentMerchantPartnerId() || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
private fallbackPermissions(): void {
|
|
||||||
this.currentUserRole = this.authService.getCurrentUserRole();
|
|
||||||
this.currentMerchantPartnerId = this.authService.getCurrentMerchantPartnerId() || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
private loadSubscriptionDetails() {
|
private loadSubscriptionDetails() {
|
||||||
if (this.subscriptionId) {
|
if (this.subscriptionId) {
|
||||||
|
|||||||
@ -111,7 +111,6 @@ export class SubscriptionsList implements OnInit, OnDestroy {
|
|||||||
.subscribe({
|
.subscribe({
|
||||||
next: (user) => {
|
next: (user) => {
|
||||||
this.currentUserRole = this.extractUserRole(user);
|
this.currentUserRole = this.extractUserRole(user);
|
||||||
this.currentMerchantPartnerId = this.extractMerchantPartnerId(user);
|
|
||||||
this.canViewAllMerchants = this.canViewAllMerchantsCheck(this.currentUserRole);
|
this.canViewAllMerchants = this.canViewAllMerchantsCheck(this.currentUserRole);
|
||||||
|
|
||||||
console.log('Subscriptions Context Loaded:', {
|
console.log('Subscriptions Context Loaded:', {
|
||||||
@ -138,13 +137,6 @@ export class SubscriptionsList implements OnInit, OnDestroy {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private extractMerchantPartnerId(user: any): string {
|
|
||||||
if (user?.merchantPartnerId) {
|
|
||||||
return user.merchantPartnerId;
|
|
||||||
}
|
|
||||||
return this.authService.getCurrentMerchantPartnerId() || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
private canViewAllMerchantsCheck(role: string | null): boolean {
|
private canViewAllMerchantsCheck(role: string | null): boolean {
|
||||||
if (!role) return false;
|
if (!role) return false;
|
||||||
|
|
||||||
@ -159,7 +151,6 @@ export class SubscriptionsList implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
private fallbackPermissions(): void {
|
private fallbackPermissions(): void {
|
||||||
this.currentUserRole = this.authService.getCurrentUserRole();
|
this.currentUserRole = this.authService.getCurrentUserRole();
|
||||||
this.currentMerchantPartnerId = this.authService.getCurrentMerchantPartnerId() || '';
|
|
||||||
this.canViewAllMerchants = this.canViewAllMerchantsCheck(this.currentUserRole);
|
this.canViewAllMerchants = this.canViewAllMerchantsCheck(this.currentUserRole);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -92,14 +92,11 @@ export class SubscriptionsManagement implements OnInit, OnDestroy {
|
|||||||
.subscribe({
|
.subscribe({
|
||||||
next: (user) => {
|
next: (user) => {
|
||||||
this.currentUserRole = this.extractUserRole(user);
|
this.currentUserRole = this.extractUserRole(user);
|
||||||
this.currentMerchantPartnerId = this.extractMerchantPartnerId(user);
|
|
||||||
|
|
||||||
console.log(`User ROLE: ${this.currentUserRole}`);
|
console.log(`User ROLE: ${this.currentUserRole}`);
|
||||||
console.log(`Merchant Partner ID: ${this.currentMerchantPartnerId}`);
|
|
||||||
},
|
},
|
||||||
error: (error) => {
|
error: (error) => {
|
||||||
console.error('Error loading user profile:', error);
|
console.error('Error loading user profile:', error);
|
||||||
this.fallbackPermissions();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -115,24 +112,6 @@ export class SubscriptionsManagement implements OnInit, OnDestroy {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Extraire le merchantPartnerId
|
|
||||||
*/
|
|
||||||
private extractMerchantPartnerId(user: any): string {
|
|
||||||
if (user?.merchantPartnerId) {
|
|
||||||
return user.merchantPartnerId;
|
|
||||||
}
|
|
||||||
return this.authService.getCurrentMerchantPartnerId() || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fallback en cas d'erreur de chargement du profil
|
|
||||||
*/
|
|
||||||
private fallbackPermissions(): void {
|
|
||||||
this.currentUserRole = this.authService.getCurrentUserRole();
|
|
||||||
this.currentMerchantPartnerId = this.authService.getCurrentMerchantPartnerId() || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==================== MÉTHODES D'INTERFACE ====================
|
// ==================== MÉTHODES D'INTERFACE ====================
|
||||||
|
|
||||||
// Méthode pour changer d'onglet
|
// Méthode pour changer d'onglet
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core';
|
|||||||
import { MerchantSyncService } from '../hub-users-management/merchant-sync-orchestrator.service';
|
import { MerchantSyncService } from '../hub-users-management/merchant-sync-orchestrator.service';
|
||||||
import { UserRole } from '@core/models/dcb-bo-hub-user.model';
|
import { UserRole } from '@core/models/dcb-bo-hub-user.model';
|
||||||
import { firstValueFrom } from 'rxjs';
|
import { firstValueFrom } from 'rxjs';
|
||||||
|
import { MerchantUsersService } from '@modules/hub-users-management/merchant-users.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-support',
|
selector: 'app-support',
|
||||||
@ -11,16 +12,22 @@ export class Support implements OnInit {
|
|||||||
|
|
||||||
private testData = {
|
private testData = {
|
||||||
merchantConfigId: '',
|
merchantConfigId: '',
|
||||||
keycloakMerchantId: '',
|
keycloakUserId: '',
|
||||||
testUserId: '',
|
testUserId: '',
|
||||||
testMerchantConfigUserId:''
|
testMerchantConfigUserId: '',
|
||||||
|
associatedUserId: '' // ID d'un utilisateur associé au marchand
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(private merchantCrudService: MerchantSyncService) {}
|
constructor(
|
||||||
|
private merchantCrudService: MerchantSyncService,
|
||||||
|
private merchantUsersService: MerchantUsersService
|
||||||
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
console.log('🚀 Support Component - Tests CRUD Merchants');
|
console.log('🚀 Support Component - Tests CRUD Merchants');
|
||||||
console.log('='.repeat(60));
|
console.log('='.repeat(60));
|
||||||
|
console.log('📌 NOUVELLE LOGIQUE: Merchant et User indépendants, association séparée');
|
||||||
|
console.log('='.repeat(60));
|
||||||
|
|
||||||
// Démarrer les tests automatiquement
|
// Démarrer les tests automatiquement
|
||||||
this.runAllTests();
|
this.runAllTests();
|
||||||
@ -32,21 +39,25 @@ export class Support implements OnInit {
|
|||||||
async runAllTests(): Promise<void> {
|
async runAllTests(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
console.log('\n🧪 DÉMARRAGE DES TESTS COMPLETS');
|
console.log('\n🧪 DÉMARRAGE DES TESTS COMPLETS');
|
||||||
|
console.log('📌 NOUVELLE LOGIQUE: Association séparée');
|
||||||
console.log('='.repeat(50));
|
console.log('='.repeat(50));
|
||||||
|
|
||||||
// Test 1: Création
|
// Test 1: Création indépendante
|
||||||
await this.testCreateOperations();
|
await this.testCreateOperations();
|
||||||
|
|
||||||
// Test 2: Lecture
|
// Test 2: Association
|
||||||
|
await this.testAssociationOperations();
|
||||||
|
|
||||||
|
// Test 3: Lecture
|
||||||
await this.testReadOperations();
|
await this.testReadOperations();
|
||||||
|
|
||||||
// Test 3: Mise à jour
|
// Test 4: Mise à jour
|
||||||
await this.testUpdateOperations();
|
await this.testUpdateOperations();
|
||||||
|
|
||||||
// Test 4: Gestion utilisateurs
|
// Test 5: Gestion utilisateurs
|
||||||
await this.testUserOperations();
|
await this.testUserOperations();
|
||||||
|
|
||||||
// Test 5: Suppression
|
// Test 6: Suppression
|
||||||
await this.testDeleteOperations();
|
await this.testDeleteOperations();
|
||||||
|
|
||||||
console.log('\n✅ TOUS LES TESTS TERMINÉS AVEC SUCCÈS!');
|
console.log('\n✅ TOUS LES TESTS TERMINÉS AVEC SUCCÈS!');
|
||||||
@ -58,15 +69,15 @@ export class Support implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TEST 1: Opérations de création
|
* TEST 1: Opérations de création indépendante
|
||||||
*/
|
*/
|
||||||
private async testCreateOperations(): Promise<void> {
|
private async testCreateOperations(): Promise<void> {
|
||||||
console.log('\n📝 TEST 1: Opérations CREATE');
|
console.log('\n📝 TEST 1: Opérations CREATE INDÉPENDANTES');
|
||||||
console.log('-'.repeat(40));
|
console.log('-'.repeat(40));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 1.1 Créer un merchant de test
|
// 1.1 Créer un merchant uniquement dans MerchantConfig
|
||||||
console.log('1.1 Création d\'un merchant test...');
|
console.log('1.1 Création d\'un merchant dans MerchantConfig seulement...');
|
||||||
|
|
||||||
const merchantData = {
|
const merchantData = {
|
||||||
name: 'Test Merchant ' + Date.now(),
|
name: 'Test Merchant ' + Date.now(),
|
||||||
@ -89,59 +100,67 @@ export class Support implements OnInit {
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
const ownerData = {
|
console.log('📤 Données merchant pour MerchantConfig:', merchantData);
|
||||||
username: `testowner.${Date.now()}`,
|
|
||||||
email: `owner.${Date.now()}@test-merchant.com`,
|
|
||||||
password: 'TestPassword123!',
|
|
||||||
firstName: 'Test',
|
|
||||||
lastName: 'Owner'
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log('📤 Données merchant:', merchantData);
|
const merchantConfigResult = await firstValueFrom(
|
||||||
console.log('👤 Données owner:', { ...ownerData, password: '***' });
|
this.merchantCrudService.createMerchantInConfigOnly(merchantData)
|
||||||
|
|
||||||
const createResult = await firstValueFrom(
|
|
||||||
this.merchantCrudService.createMerchant(merchantData, ownerData)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
this.testData.merchantConfigId = String(createResult.merchantConfig.id!);
|
this.testData.merchantConfigId = String(merchantConfigResult.id!);
|
||||||
this.testData.keycloakMerchantId = createResult.keycloakMerchant.id;
|
|
||||||
|
|
||||||
console.log('✅ Merchant créé avec succès!');
|
console.log('✅ Merchant créé dans MerchantConfig uniquement!');
|
||||||
console.log(' Merchant Config ID:', this.testData.merchantConfigId);
|
console.log(' Merchant Config ID:', this.testData.merchantConfigId);
|
||||||
console.log(' Keycloak Merchant ID:', this.testData.keycloakMerchantId);
|
console.log(' Merchant name:', merchantConfigResult.name);
|
||||||
console.log(' Merchant name:', createResult.merchantConfig.name);
|
|
||||||
console.log(' DCB Partner email:', createResult.keycloakMerchant.email);
|
|
||||||
|
|
||||||
// 1.2 Créer un utilisateur pour le merchant
|
// 1.2 Créer un utilisateur Hub dans Keycloak
|
||||||
console.log('\n1.2 Création d\'un utilisateur test...');
|
console.log('\n1.2 Création d\'un utilisateur Hub dans Keycloak...');
|
||||||
|
|
||||||
const userData = {
|
const hubUserData = {
|
||||||
username: `testuser.${Date.now()}`,
|
username: `testhubuser.${Date.now()}`,
|
||||||
email: `user.${Date.now()}@test-merchant.com`,
|
email: `hubuser.${Date.now()}@example.com`,
|
||||||
password: 'UserPassword123!',
|
password: 'HubPassword123!',
|
||||||
firstName: 'Test',
|
firstName: 'Test',
|
||||||
lastName: 'User',
|
lastName: 'HubUser',
|
||||||
|
role: UserRole.DCB_SUPPORT
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log('👤 Données Hub User pour Keycloak:', { ...hubUserData, password: '***' });
|
||||||
|
|
||||||
|
const hubUserResult = await firstValueFrom(
|
||||||
|
this.merchantCrudService.createKeycloakUser(hubUserData)
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log('✅ Utilisateur Hub créé dans Keycloak:');
|
||||||
|
console.log(' Keycloak User ID:', hubUserResult.id);
|
||||||
|
console.log(' Email:', hubUserResult.email);
|
||||||
|
console.log(' Rôle:', hubUserResult.role);
|
||||||
|
console.log(' User Type:', hubUserResult.userType);
|
||||||
|
|
||||||
|
// 1.3 Créer un utilisateur Partenaire dans Keycloak
|
||||||
|
console.log('\n1.3 Création d\'un utilisateur Partenaire dans Keycloak...');
|
||||||
|
|
||||||
|
const partnerUserData = {
|
||||||
|
username: `testpartner.${Date.now()}`,
|
||||||
|
email: `partner.${Date.now()}@example.com`,
|
||||||
|
password: 'PartnerPassword123!',
|
||||||
|
firstName: 'Test',
|
||||||
|
lastName: 'Partner',
|
||||||
role: UserRole.DCB_PARTNER_ADMIN
|
role: UserRole.DCB_PARTNER_ADMIN
|
||||||
};
|
};
|
||||||
|
|
||||||
const userResult = await firstValueFrom(
|
console.log('👤 Données Partner User pour Keycloak:', { ...partnerUserData, password: '***' });
|
||||||
this.merchantCrudService.createMerchantUser(
|
|
||||||
this.testData.merchantConfigId,
|
const partnerUserResult = await firstValueFrom(
|
||||||
this.testData.keycloakMerchantId,
|
this.merchantCrudService.createKeycloakUser(partnerUserData)
|
||||||
userData
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
this.testData.testUserId = userResult.keycloakUser.id;
|
this.testData.testUserId = partnerUserResult.id;
|
||||||
this.testData.testMerchantConfigUserId = String(userResult.merchantConfigUser.userId);
|
|
||||||
|
|
||||||
console.log('✅ Utilisateur créé avec succès!');
|
console.log('✅ Utilisateur Partenaire créé dans Keycloak:');
|
||||||
console.log(' Keycloak User ID:', this.testData.testUserId);
|
console.log(' Keycloak User ID:', this.testData.testUserId);
|
||||||
console.log(' Merchant Config User ID:', this.testData.testMerchantConfigUserId);
|
console.log(' Email:', partnerUserResult.email);
|
||||||
console.log(' Email:', userResult.keycloakUser.email);
|
console.log(' Rôle:', partnerUserResult.role);
|
||||||
console.log(' Rôle Keycloak:', userResult.keycloakUser.role);
|
console.log(' User Type:', partnerUserResult.userType);
|
||||||
console.log(' Rôle Merchant Config:', userResult.merchantConfigUser.role);
|
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('❌ ERREUR lors de la création:', error);
|
console.error('❌ ERREUR lors de la création:', error);
|
||||||
@ -150,10 +169,67 @@ export class Support implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TEST 2: Opérations de lecture
|
* TEST 2: Opérations d'association
|
||||||
|
*/
|
||||||
|
private async testAssociationOperations(): Promise<void> {
|
||||||
|
console.log('\n🔗 TEST 2: Opérations d\'ASSOCIATION');
|
||||||
|
console.log('-'.repeat(40));
|
||||||
|
|
||||||
|
if (!this.testData.merchantConfigId || !this.testData.testUserId) {
|
||||||
|
console.log('⚠️ Merchant ou utilisateur non créé, passage au test suivant');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 2.1 Associer l'utilisateur au marchand
|
||||||
|
console.log('2.1 Association de l\'utilisateur au marchand...');
|
||||||
|
|
||||||
|
const associationData = {
|
||||||
|
userId: this.testData.testUserId,
|
||||||
|
merchantConfigId: this.testData.merchantConfigId,
|
||||||
|
role: UserRole.MERCHANT_CONFIG_ADMIN
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log('🔗 Données d\'association:', associationData);
|
||||||
|
|
||||||
|
const associationResult = await firstValueFrom(
|
||||||
|
this.merchantCrudService.associateUserToMerchant(associationData)
|
||||||
|
);
|
||||||
|
|
||||||
|
this.testData.associatedUserId = associationResult.keycloakUser.id;
|
||||||
|
this.testData.testMerchantConfigUserId = String(associationResult.merchantConfigUser?.userId || '');
|
||||||
|
|
||||||
|
console.log('✅ Utilisateur associé au marchand:');
|
||||||
|
console.log(' Keycloak User ID:', associationResult.keycloakUser.id);
|
||||||
|
console.log(' Merchant Config User ID:', this.testData.testMerchantConfigUserId);
|
||||||
|
console.log(' Rôle dans MerchantConfig:', associationResult.merchantConfigUser?.role);
|
||||||
|
console.log(' Associé au merchant:', this.testData.merchantConfigId);
|
||||||
|
|
||||||
|
// 2.2 Récupérer les utilisateurs associés au marchand
|
||||||
|
console.log('\n2.2 Lecture des utilisateurs associés au marchand...');
|
||||||
|
|
||||||
|
const merchantUsers = await firstValueFrom(
|
||||||
|
this.merchantCrudService.getUsersByMerchant(this.testData.merchantConfigId)
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(`✅ ${merchantUsers.length} utilisateurs associés à ce merchant`);
|
||||||
|
|
||||||
|
merchantUsers.forEach((user: any, index: number) => {
|
||||||
|
console.log(` ${index + 1}. ${user.email || 'Inconnu'}`);
|
||||||
|
console.log(` ID: ${user.id}`);
|
||||||
|
console.log(` Rôle: ${user.role}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ ERREUR lors de l\'association:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TEST 3: Opérations de lecture
|
||||||
*/
|
*/
|
||||||
private async testReadOperations(): Promise<void> {
|
private async testReadOperations(): Promise<void> {
|
||||||
console.log('\n🔍 TEST 2: Opérations READ');
|
console.log('\n🔍 TEST 3: Opérations READ');
|
||||||
console.log('-'.repeat(40));
|
console.log('-'.repeat(40));
|
||||||
|
|
||||||
if (!this.testData.merchantConfigId) {
|
if (!this.testData.merchantConfigId) {
|
||||||
@ -162,68 +238,60 @@ export class Support implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 2.1 Lire le merchant par ID
|
// 3.1 Lire le merchant depuis MerchantConfig
|
||||||
console.log('2.1 Lecture du merchant par ID...');
|
console.log('3.1 Lecture du merchant depuis MerchantConfig...');
|
||||||
|
|
||||||
const merchant = await firstValueFrom(
|
const merchant = await firstValueFrom(
|
||||||
this.merchantCrudService.getMerchant(
|
this.merchantCrudService.getMerchantFromConfigOnly(
|
||||||
this.testData.merchantConfigId,
|
this.testData.merchantConfigId
|
||||||
this.testData.keycloakMerchantId
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log('✅ Merchant récupéré:');
|
console.log('✅ Merchant récupéré depuis MerchantConfig:');
|
||||||
console.log(' ID:', merchant.merchantConfig.id);
|
console.log(' ID:', merchant.id);
|
||||||
console.log(' Nom:', merchant.merchantConfig.name);
|
console.log(' Nom:', merchant.name);
|
||||||
console.log(' Adresse:', merchant.merchantConfig.adresse);
|
console.log(' Adresse:', merchant.adresse);
|
||||||
console.log(' Configurations:', merchant.merchantConfig.configs?.length || 0);
|
console.log(' Configurations:', merchant.configs?.length || 0);
|
||||||
console.log(' Contacts techniques:', merchant.merchantConfig.technicalContacts?.length || 0);
|
|
||||||
|
|
||||||
// 2.2 Lire tous les merchants
|
// 3.2 Lire tous les merchants depuis MerchantConfig
|
||||||
console.log('\n2.2 Lecture de tous les merchants...');
|
console.log('\n3.2 Lecture de tous les merchants depuis MerchantConfig...');
|
||||||
|
|
||||||
const allMerchants = await firstValueFrom(
|
const allMerchants = await firstValueFrom(
|
||||||
this.merchantCrudService.getAllMerchants()
|
this.merchantCrudService.getAllMerchantsFromConfig()
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log(`✅ ${allMerchants.length} merchants trouvés au total`);
|
console.log(`✅ ${allMerchants.length} merchants trouvés au total`);
|
||||||
|
|
||||||
if (allMerchants.length > 0) {
|
if (allMerchants.length > 0) {
|
||||||
console.log(' Dernier merchant:', allMerchants[allMerchants.length - 1].merchantConfig.name);
|
const lastMerchant = allMerchants[allMerchants.length - 1];
|
||||||
|
console.log(' Dernier merchant:', lastMerchant.name, '(ID:', lastMerchant.id, ')');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2.3 Lire les utilisateurs du merchant
|
// 3.3 Rechercher des merchants
|
||||||
console.log('\n2.3 Lecture des utilisateurs du merchant...');
|
console.log('\n3.3 Recherche de merchants dans MerchantConfig...');
|
||||||
|
|
||||||
const merchantUsers = await firstValueFrom(
|
const searchResults = await firstValueFrom(
|
||||||
this.merchantCrudService.getMerchantUsers(
|
this.merchantCrudService.searchMerchantsInConfig('Test')
|
||||||
this.testData.merchantConfigId,
|
|
||||||
this.testData.keycloakMerchantId
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log(`✅ ${merchantUsers.users.length} utilisateurs dans ce merchant`);
|
console.log(`✅ ${searchResults.length} merchants trouvés avec "Test"`);
|
||||||
|
|
||||||
merchantUsers.users.forEach((user: any, index: number) => {
|
if (searchResults.length > 0) {
|
||||||
console.log(` ${index + 1}. ${user.keycloakUser?.email || 'Inconnu'}`);
|
console.log(' Premier résultat:', searchResults[0].name);
|
||||||
console.log(` Synchronisé: ${user.synced ? '✅' : '❌'}`);
|
}
|
||||||
});
|
|
||||||
|
|
||||||
// 2.4 Vérifier le statut de synchronisation
|
// 3.4 Rechercher des utilisateurs
|
||||||
console.log('\n2.4 Vérification statut synchronisation...');
|
console.log('\n3.4 Recherche d\'utilisateurs dans Keycloak...');
|
||||||
|
|
||||||
const syncStatus = await firstValueFrom(
|
const userSearchResults = await firstValueFrom(
|
||||||
this.merchantCrudService.checkSyncStatus(
|
this.merchantCrudService.searchKeycloakUsers('test')
|
||||||
String(this.testData.merchantConfigId),
|
|
||||||
this.testData.keycloakMerchantId
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log('✅ Statut de synchronisation:');
|
console.log(`✅ ${userSearchResults.length} utilisateurs trouvés avec "test"`);
|
||||||
console.log(' Existe dans Keycloak:', syncStatus.existsInKeycloak ? '✅' : '❌');
|
|
||||||
console.log(' Existe dans Merchant Config:', syncStatus.existsInMerchantConfig ? '✅' : '❌');
|
if (userSearchResults.length > 0) {
|
||||||
console.log(' Utilisateurs synchronisés:', syncStatus.usersSynced ? '✅' : '❌');
|
console.log(' Premier résultat:', userSearchResults[0].email);
|
||||||
console.log(` ${syncStatus.syncedUserCount}/${syncStatus.totalUserCount} utilisateurs synchronisés`);
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('❌ ERREUR lors de la lecture:', error);
|
console.error('❌ ERREUR lors de la lecture:', error);
|
||||||
@ -231,10 +299,10 @@ export class Support implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TEST 3: Opérations de mise à jour
|
* TEST 4: Opérations de mise à jour
|
||||||
*/
|
*/
|
||||||
private async testUpdateOperations(): Promise<void> {
|
private async testUpdateOperations(): Promise<void> {
|
||||||
console.log('\n✏️ TEST 3: Opérations UPDATE');
|
console.log('\n✏️ TEST 4: Opérations UPDATE');
|
||||||
console.log('-'.repeat(40));
|
console.log('-'.repeat(40));
|
||||||
|
|
||||||
if (!this.testData.merchantConfigId) {
|
if (!this.testData.merchantConfigId) {
|
||||||
@ -243,83 +311,40 @@ export class Support implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 3.1 Mettre à jour le merchant
|
// 4.1 Mettre à jour le merchant dans MerchantConfig
|
||||||
console.log('3.1 Mise à jour du merchant...');
|
console.log('4.1 Mise à jour du merchant dans MerchantConfig...');
|
||||||
|
|
||||||
const newName = `Updated Merchant ${Date.now()}`;
|
const newName = `Updated Merchant ${Date.now()}`;
|
||||||
const newEmail = `updated.${Date.now()}@test-merchant.com`;
|
|
||||||
|
|
||||||
const updateResult = await firstValueFrom(
|
const updateResult = await firstValueFrom(
|
||||||
this.merchantCrudService.updateMerchant(
|
this.merchantCrudService.updateMerchantInConfigOnly(
|
||||||
this.testData.merchantConfigId,
|
this.testData.merchantConfigId,
|
||||||
this.testData.keycloakMerchantId,
|
|
||||||
{
|
{
|
||||||
merchantConfig: {
|
|
||||||
name: newName,
|
name: newName,
|
||||||
description: 'Mis à jour par les tests'
|
description: 'Mis à jour par les tests',
|
||||||
},
|
adresse: '456 Updated Street'
|
||||||
dcbPartner: {
|
|
||||||
email: newEmail
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log('✅ Merchant mis à jour:');
|
console.log('✅ Merchant mis à jour dans MerchantConfig:');
|
||||||
console.log(' Nouveau nom:', newName);
|
console.log(' Nouveau nom:', newName);
|
||||||
console.log(' Nouvel email DCB Partner:', newEmail);
|
console.log(' Description:', updateResult.description);
|
||||||
|
|
||||||
// 3.2 Mettre à jour l'utilisateur
|
// 4.3 Changer le rôle de l'utilisateur dans MerchantConfig
|
||||||
console.log('\n3.2 Mise à jour de l\'utilisateur...');
|
console.log('\n4.3 Changement de rôle utilisateur dans MerchantConfig...');
|
||||||
|
|
||||||
if (this.testData.testUserId) {
|
if (this.testData.testUserId && this.testData.merchantConfigId && this.testData.testMerchantConfigUserId) {
|
||||||
const userUpdateResult = await firstValueFrom(
|
const roleUpdateResult = await firstValueFrom(
|
||||||
this.merchantCrudService.updateMerchantUser(
|
this.merchantCrudService.updateUserRoleInMerchantConfig(
|
||||||
this.testData.testUserId,
|
|
||||||
this.testData.testMerchantConfigUserId,
|
|
||||||
this.testData.merchantConfigId,
|
this.testData.merchantConfigId,
|
||||||
{
|
this.testData.testUserId,
|
||||||
keycloak: {
|
UserRole.MERCHANT_CONFIG_MANAGER
|
||||||
firstName: 'Updated',
|
|
||||||
lastName: 'User'
|
|
||||||
},
|
|
||||||
merchantConfig: {
|
|
||||||
role: UserRole.MERCHANT_CONFIG_MANAGER
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log('✅ Utilisateur mis à jour:');
|
console.log('✅ Rôle utilisateur mis à jour dans MerchantConfig:');
|
||||||
console.log(' Nouveau nom:', 'Updated User');
|
|
||||||
console.log(' Nouveau rôle:', UserRole.MERCHANT_CONFIG_MANAGER);
|
console.log(' Nouveau rôle:', UserRole.MERCHANT_CONFIG_MANAGER);
|
||||||
|
|
||||||
} else {
|
|
||||||
console.log('⚠️ Aucun utilisateur à mettre à jour');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3.3 Activer/désactiver un utilisateur
|
|
||||||
console.log('\n3.3 Changement statut utilisateur...');
|
|
||||||
|
|
||||||
if (this.testData.testUserId) {
|
|
||||||
const toggleResult = await firstValueFrom(
|
|
||||||
this.merchantCrudService.toggleUserStatus(
|
|
||||||
this.testData.testUserId,
|
|
||||||
false // Désactiver
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
console.log('✅ Statut utilisateur changé:');
|
|
||||||
console.log(' Activé:', toggleResult.enabled ? '✅' : '❌');
|
|
||||||
|
|
||||||
// Réactiver pour les tests suivants
|
|
||||||
await firstValueFrom(
|
|
||||||
this.merchantCrudService.toggleUserStatus(
|
|
||||||
this.testData.testUserId,
|
|
||||||
true
|
|
||||||
)
|
|
||||||
);
|
|
||||||
console.log(' Réactivé pour les tests suivants');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -328,10 +353,10 @@ export class Support implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TEST 4: Opérations utilisateurs avancées
|
* TEST 5: Opérations utilisateurs avancées
|
||||||
*/
|
*/
|
||||||
private async testUserOperations(): Promise<void> {
|
private async testUserOperations(): Promise<void> {
|
||||||
console.log('\n👥 TEST 4: Opérations utilisateurs avancées');
|
console.log('\n👥 TEST 5: Opérations utilisateurs avancées');
|
||||||
console.log('-'.repeat(40));
|
console.log('-'.repeat(40));
|
||||||
|
|
||||||
if (!this.testData.testUserId) {
|
if (!this.testData.testUserId) {
|
||||||
@ -340,32 +365,72 @@ export class Support implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 4.1 Réinitialiser le mot de passe
|
// 5.1 Réinitialiser le mot de passe
|
||||||
console.log('4.1 Réinitialisation mot de passe...');
|
console.log('5.1 Réinitialisation mot de passe...');
|
||||||
|
|
||||||
|
const resetPasswordDto = {
|
||||||
|
newPassword: 'NewPassword123!',
|
||||||
|
temporary: false
|
||||||
|
};
|
||||||
|
|
||||||
const resetResult = await firstValueFrom(
|
const resetResult = await firstValueFrom(
|
||||||
this.merchantCrudService.resetUserPassword(
|
this.merchantUsersService.resetMerchantUserPassword(
|
||||||
this.testData.testUserId,
|
this.testData.testUserId,
|
||||||
'NewPassword123!',
|
resetPasswordDto
|
||||||
true
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log('✅ Mot de passe réinitialisé:');
|
console.log('✅ Mot de passe réinitialisé:');
|
||||||
console.log(' Succès:', resetResult.success);
|
|
||||||
console.log(' Message:', resetResult.message);
|
console.log(' Message:', resetResult.message);
|
||||||
|
|
||||||
// 4.2 Rechercher des merchants
|
// 5.2 Dissocier l'utilisateur du marchand
|
||||||
console.log('\n4.2 Recherche de merchants...');
|
console.log('\n5.2 Dissociation de l\'utilisateur du marchand...');
|
||||||
|
|
||||||
const searchResults = await firstValueFrom(
|
if (this.testData.testUserId && this.testData.merchantConfigId) {
|
||||||
this.merchantCrudService.searchMerchants('Test')
|
const dissociateResult = await firstValueFrom(
|
||||||
|
this.merchantCrudService.dissociateUserFromMerchant(
|
||||||
|
this.testData.testUserId,
|
||||||
|
this.testData.merchantConfigId
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log(`✅ ${searchResults.length} merchants trouvés avec "Test"`);
|
console.log('✅ Utilisateur dissocié du marchand:');
|
||||||
|
console.log(' Succès:', dissociateResult.success);
|
||||||
|
console.log(' Message:', dissociateResult.message);
|
||||||
|
|
||||||
if (searchResults.length > 0) {
|
// Vérifier que l'utilisateur n'est plus associé
|
||||||
console.log(' Premier résultat:', searchResults[0].merchantConfig.name);
|
const userMerchants = await firstValueFrom(
|
||||||
|
this.merchantCrudService.getUsersByMerchant(this.testData.merchantConfigId)
|
||||||
|
);
|
||||||
|
|
||||||
|
const userStillLinked = userMerchants.some(
|
||||||
|
user => user.id === this.testData.testUserId
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(` Marchands associés après dissociation: ${userMerchants.length}`);
|
||||||
|
|
||||||
|
if (userStillLinked) {
|
||||||
|
console.error('❌ L’utilisateur est encore associé au marchand ! ❌');
|
||||||
|
} else {
|
||||||
|
console.log('✅ L’utilisateur a été correctement dissocié du marchand.');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5.3 Réassocier l'utilisateur (pour les tests suivants)
|
||||||
|
console.log('\n5.3 Réassociation de l\'utilisateur (pour les tests)...');
|
||||||
|
|
||||||
|
if (this.testData.testUserId && this.testData.merchantConfigId) {
|
||||||
|
const reassociationData = {
|
||||||
|
userId: this.testData.testUserId,
|
||||||
|
merchantConfigId: this.testData.merchantConfigId,
|
||||||
|
role: UserRole.MERCHANT_CONFIG_ADMIN
|
||||||
|
};
|
||||||
|
|
||||||
|
await firstValueFrom(
|
||||||
|
this.merchantCrudService.associateUserToMerchant(reassociationData)
|
||||||
|
);
|
||||||
|
console.log('✅ Utilisateur réassocié pour les tests suivants');
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -374,10 +439,10 @@ export class Support implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TEST 5: Opérations de suppression
|
* TEST 6: Opérations de suppression
|
||||||
*/
|
*/
|
||||||
private async testDeleteOperations(): Promise<void> {
|
private async testDeleteOperations(): Promise<void> {
|
||||||
console.log('\n🗑️ TEST 5: Opérations DELETE');
|
console.log('\n🗑️ TEST 6: Opérations DELETE');
|
||||||
console.log('-'.repeat(40));
|
console.log('-'.repeat(40));
|
||||||
|
|
||||||
if (!this.testData.merchantConfigId) {
|
if (!this.testData.merchantConfigId) {
|
||||||
@ -386,64 +451,71 @@ export class Support implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 5.1 Supprimer l'utilisateur test
|
// 6.1 Dissocier avant suppression
|
||||||
console.log('5.1 Suppression de l\'utilisateur test...');
|
console.log('6.1 Dissociation de l\'utilisateur avant suppression...');
|
||||||
|
|
||||||
|
if (this.testData.testUserId && this.testData.merchantConfigId) {
|
||||||
|
await firstValueFrom(
|
||||||
|
this.merchantCrudService.dissociateUserFromMerchant(
|
||||||
|
this.testData.testUserId,
|
||||||
|
this.testData.merchantConfigId
|
||||||
|
)
|
||||||
|
);
|
||||||
|
console.log('✅ Utilisateur dissocié');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6.2 Supprimer l'utilisateur de Keycloak
|
||||||
|
console.log('\n6.2 Suppression de l\'utilisateur de Keycloak...');
|
||||||
|
|
||||||
if (this.testData.testUserId) {
|
if (this.testData.testUserId) {
|
||||||
const deleteUserResult = await firstValueFrom(
|
const deleteUserResult = await firstValueFrom(
|
||||||
this.merchantCrudService.deleteMerchantUser(
|
this.merchantCrudService.deleteKeycloakUser(
|
||||||
this.testData.testUserId,
|
this.testData.testUserId
|
||||||
this.testData.testMerchantConfigUserId,
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log('✅ Utilisateur supprimé de Keycloak:');
|
||||||
|
console.log(' Succès:', deleteUserResult.success);
|
||||||
|
console.log(' Message:', deleteUserResult.message);
|
||||||
|
|
||||||
|
this.testData.testUserId = '';
|
||||||
|
this.testData.testMerchantConfigUserId = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6.3 Supprimer le merchant de MerchantConfig
|
||||||
|
console.log('\n6.3 Suppression du merchant de MerchantConfig...');
|
||||||
|
|
||||||
|
const deleteMerchantResult = await firstValueFrom(
|
||||||
|
this.merchantCrudService.deleteMerchantFromConfigOnly(
|
||||||
this.testData.merchantConfigId
|
this.testData.merchantConfigId
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log('✅ Utilisateur supprimé:');
|
console.log('✅ Merchant supprimé de MerchantConfig:');
|
||||||
console.log(' Succès:', deleteUserResult.success);
|
|
||||||
console.log(' Message:', deleteUserResult.message);
|
|
||||||
|
|
||||||
// Réinitialiser les IDs utilisateur
|
|
||||||
this.testData.testUserId = '';
|
|
||||||
this.testData.testMerchantConfigUserId = '';
|
|
||||||
} else {
|
|
||||||
console.log('⚠️ Aucun utilisateur à supprimer');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 5.2 Supprimer le merchant test
|
|
||||||
console.log('\n5.2 Suppression du merchant test...');
|
|
||||||
|
|
||||||
const deleteMerchantResult = await firstValueFrom(
|
|
||||||
this.merchantCrudService.deleteMerchant(
|
|
||||||
this.testData.merchantConfigId,
|
|
||||||
this.testData.keycloakMerchantId
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
console.log('✅ Merchant supprimé:');
|
|
||||||
console.log(' Succès:', deleteMerchantResult.success);
|
console.log(' Succès:', deleteMerchantResult.success);
|
||||||
console.log(' Message:', deleteMerchantResult.message);
|
console.log(' Message:', deleteMerchantResult.message);
|
||||||
|
|
||||||
// 5.3 Vérifier la suppression
|
// 6.4 Vérifier la suppression
|
||||||
console.log('\n5.3 Vérification de la suppression...');
|
console.log('\n6.4 Vérification de la suppression...');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await firstValueFrom(
|
await firstValueFrom(
|
||||||
this.merchantCrudService.getMerchant(
|
this.merchantCrudService.getMerchantFromConfigOnly(
|
||||||
this.testData.merchantConfigId,
|
this.testData.merchantConfigId
|
||||||
this.testData.keycloakMerchantId
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
console.log('❌ Le merchant existe toujours - PROBLÈME!');
|
console.log('❌ Le merchant existe toujours dans MerchantConfig - PROBLÈME!');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('✅ Le merchant a bien été supprimé');
|
console.log('✅ Le merchant a bien été supprimé de MerchantConfig');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Réinitialiser toutes les données
|
// Réinitialiser toutes les données
|
||||||
this.testData = {
|
this.testData = {
|
||||||
merchantConfigId: '',
|
merchantConfigId: '',
|
||||||
keycloakMerchantId: '',
|
keycloakUserId: '',
|
||||||
testUserId: '',
|
testUserId: '',
|
||||||
testMerchantConfigUserId: ''
|
testMerchantConfigUserId: '',
|
||||||
|
associatedUserId: ''
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('🧹 Données de test réinitialisées');
|
console.log('🧹 Données de test réinitialisées');
|
||||||
@ -453,14 +525,28 @@ export class Support implements OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// ==================== MÉTHODES POUR TESTS INDIVIDUELS ====================
|
||||||
* Méthodes pour exécuter des tests individuels
|
|
||||||
*/
|
|
||||||
async testCreateOnly(): Promise<void> {
|
async testCreateOnly(): Promise<void> {
|
||||||
console.log('🧪 Test CREATE uniquement');
|
console.log('🧪 Test CREATE uniquement');
|
||||||
|
console.log('📌 Création indépendante');
|
||||||
await this.testCreateOperations();
|
await this.testCreateOperations();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async testAssociationOnly(): Promise<void> {
|
||||||
|
console.log('🧪 Test ASSOCIATION uniquement');
|
||||||
|
|
||||||
|
// Créer d'abord un merchant et un utilisateur si nécessaire
|
||||||
|
if (!this.testData.merchantConfigId) {
|
||||||
|
await this.createTestMerchant();
|
||||||
|
}
|
||||||
|
if (!this.testData.testUserId) {
|
||||||
|
await this.createTestUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.testAssociationOperations();
|
||||||
|
}
|
||||||
|
|
||||||
async testReadOnly(): Promise<void> {
|
async testReadOnly(): Promise<void> {
|
||||||
console.log('🧪 Test READ uniquement');
|
console.log('🧪 Test READ uniquement');
|
||||||
await this.testReadOperations();
|
await this.testReadOperations();
|
||||||
@ -476,16 +562,54 @@ export class Support implements OnInit {
|
|||||||
await this.testDeleteOperations();
|
await this.testDeleteOperations();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== MÉTHODES UTILITAIRES ====================
|
||||||
|
|
||||||
|
private async createTestMerchant(): Promise<void> {
|
||||||
|
const merchantData = {
|
||||||
|
name: 'Test Merchant ' + Date.now(),
|
||||||
|
adresse: '123 Test Street',
|
||||||
|
phone: '+336' + Math.floor(10000000 + Math.random() * 90000000),
|
||||||
|
configs: [],
|
||||||
|
technicalContacts: []
|
||||||
|
};
|
||||||
|
|
||||||
|
const merchant = await firstValueFrom(
|
||||||
|
this.merchantCrudService.createMerchantInConfigOnly(merchantData)
|
||||||
|
);
|
||||||
|
|
||||||
|
this.testData.merchantConfigId = String(merchant.id!);
|
||||||
|
console.log('✅ Merchant de test créé:', this.testData.merchantConfigId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async createTestUser(): Promise<void> {
|
||||||
|
const userData = {
|
||||||
|
username: `testuser.${Date.now()}`,
|
||||||
|
email: `user.${Date.now()}@example.com`,
|
||||||
|
password: 'TestPassword123!',
|
||||||
|
firstName: 'Test',
|
||||||
|
lastName: 'User',
|
||||||
|
role: UserRole.DCB_PARTNER_ADMIN
|
||||||
|
};
|
||||||
|
|
||||||
|
const user = await firstValueFrom(
|
||||||
|
this.merchantCrudService.createKeycloakUser(userData)
|
||||||
|
);
|
||||||
|
|
||||||
|
this.testData.testUserId = user.id;
|
||||||
|
console.log('✅ Utilisateur de test créé:', this.testData.testUserId);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Afficher l'état actuel des tests
|
* Afficher l'état actuel des tests
|
||||||
*/
|
*/
|
||||||
showTestStatus(): void {
|
showTestStatus(): void {
|
||||||
console.log('\n📊 ÉTAT ACTUEL DES TESTS');
|
console.log('\n📊 ÉTAT ACTUEL DES TESTS');
|
||||||
|
console.log('📌 NOUVELLE LOGIQUE: Association séparée');
|
||||||
console.log('-'.repeat(30));
|
console.log('-'.repeat(30));
|
||||||
console.log('Merchant Config ID:', this.testData.merchantConfigId || 'Non créé');
|
console.log('Merchant Config ID:', this.testData.merchantConfigId || 'Non créé');
|
||||||
console.log('Keycloak Merchant ID:', this.testData.keycloakMerchantId || 'Non créé');
|
console.log('Keycloak User ID:', this.testData.testUserId || 'Non créé');
|
||||||
console.log('Test User ID:', this.testData.testUserId || 'Non créé');
|
console.log('Associated User ID:', this.testData.associatedUserId || 'Non associé');
|
||||||
console.log('Test Merchant Config User ID:', this.testData.testMerchantConfigUserId || 'Non créé');
|
console.log('Merchant Config User ID:', this.testData.testMerchantConfigUserId || 'Non créé');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -494,9 +618,10 @@ export class Support implements OnInit {
|
|||||||
resetTestData(): void {
|
resetTestData(): void {
|
||||||
this.testData = {
|
this.testData = {
|
||||||
merchantConfigId: '',
|
merchantConfigId: '',
|
||||||
keycloakMerchantId: '',
|
keycloakUserId: '',
|
||||||
testUserId: '',
|
testUserId: '',
|
||||||
testMerchantConfigUserId: ''
|
testMerchantConfigUserId: '',
|
||||||
|
associatedUserId: ''
|
||||||
};
|
};
|
||||||
console.log('🧹 Données de test réinitialisées');
|
console.log('🧹 Données de test réinitialisées');
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user