Files
pmu-plateforme-jeux-admin-plr/src/app/core/services/agent.ts
OnlyPapy98 f21a5fd4e6 test
2025-12-30 19:09:01 +01:00

475 lines
17 KiB
TypeScript

import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable, of, forkJoin } from 'rxjs';
import { map, catchError, switchMap } from 'rxjs/operators';
import { Agent, AgentStatus } from '../interfaces/agent';
import { TpeDevice, TpeStatus, TpeType } from '../interfaces/tpe';
import { environment } from 'src/environments/environment.development';
import { normalizePage } from '@shared/paging/normalize-page';
import { ListParams, PagedResult } from '@shared/paging/paging';
const USE_SERVER = true;
const API_BASE = '/api/agents';
// Interface to match the API response structure for TPE (nested in Agent)
// Note: When TPE is nested in Agent's tpes array, the agent field might be omitted or be a reference
interface TpeApiResponse {
id: number;
imei: string;
serial: string;
type: string;
marque: string;
modele: string;
statut: string;
agent?: any; // Can be Agent object or string reference, we'll handle it in transformTpe
assigne: boolean;
createdAt?: string;
updatedAt?: string;
}
// Interface to match the API response structure
interface AgentApiResponse {
id: number;
code: string;
profile: string;
principalCode?: string;
caisseProfile?: string;
statut: string;
zone?: string;
kiosk?: string;
fonction?: string;
dateEmbauche?: string;
nom: string;
prenom: string;
autresNoms?: string;
dateNaissance?: string;
lieuNaissance?: string;
ville?: string;
adresse?: string;
autoriserAides?: boolean;
phone: string;
pin?: string;
limiteInferieure?: number;
limiteSuperieure?: number;
limiteParTransaction?: number;
limiteMinAirtime?: number;
limiteMaxAirtime?: number;
maxPeripheriques?: number;
limitId?: number;
nationalite?: string;
cni?: string;
cniDelivreeLe?: string;
cniDelivreeA?: string;
residence?: string;
autreAdresse1?: string;
statutMarital?: string;
epoux?: string;
autreTelephone?: string;
tpes?: TpeApiResponse[];
createdAt?: string;
updatedAt?: string;
createdBy?: string;
}
@Injectable({ providedIn: 'root' })
export class AgentService {
private apiUrl = environment.apiBaseUrl + API_BASE;
constructor(private http: HttpClient) {}
// Helper method to get ngrok bypass headers
private getNgrokHeaders(): Record<string, string> {
const isNgrok =
environment.apiBaseUrl.includes('ngrok-free.app') ||
environment.apiBaseUrl.includes('ngrok.io') ||
environment.apiBaseUrl.includes('ngrok');
return isNgrok ? { 'ngrok-skip-browser-warning': 'true' } : {};
}
// Transform API TPE response to TpeDevice
private transformTpe(apiTpe: TpeApiResponse): TpeDevice {
const transformStatut = (apiStatut: string): TpeStatus => {
const upperStatut = apiStatut.toUpperCase() as TpeStatus;
const validStatuses: TpeStatus[] = [
'VALIDE',
'INVALIDE',
'EN_PANNE',
'BLOQUE',
'DISPONIBLE',
'AFFECTE',
'EN_MAINTENANCE',
'HORS_SERVICE',
'VOLE',
];
return validStatuses.includes(upperStatut) ? upperStatut : 'INVALIDE';
};
// Transform agent if it's an object (not just a string reference)
let transformedAgent: Agent | undefined = undefined;
if (apiTpe.agent && typeof apiTpe.agent === 'object' && apiTpe.agent.id) {
// If agent is a full object, transform it
transformedAgent = this.transformAgent(apiTpe.agent as any);
}
return {
id: String(apiTpe.id),
imei: apiTpe.imei,
serial: apiTpe.serial,
type: apiTpe.type as TpeType,
marque: apiTpe.marque,
modele: apiTpe.modele,
statut: transformStatut(apiTpe.statut),
agent: transformedAgent,
assigne: apiTpe.assigne,
createdAt: apiTpe.createdAt,
updatedAt: apiTpe.updatedAt,
};
}
// Transform API response to Agent
private transformAgent(apiAgent: AgentApiResponse): Agent {
return {
id: String(apiAgent.id),
code: apiAgent.code,
profile: apiAgent.profile,
principalCode: apiAgent.principalCode,
caisseProfile: apiAgent.caisseProfile,
statut: apiAgent.statut as AgentStatus,
zone: apiAgent.zone,
kiosk: apiAgent.kiosk,
fonction: apiAgent.fonction,
dateEmbauche: apiAgent.dateEmbauche,
nom: apiAgent.nom,
prenom: apiAgent.prenom,
autresNoms: apiAgent.autresNoms,
dateNaissance: apiAgent.dateNaissance,
lieuNaissance: apiAgent.lieuNaissance,
ville: apiAgent.ville,
adresse: apiAgent.adresse,
autoriserAides: apiAgent.autoriserAides,
phone: apiAgent.phone,
pin: apiAgent.pin,
limiteInferieure: apiAgent.limiteInferieure,
limiteSuperieure: apiAgent.limiteSuperieure,
limiteParTransaction: apiAgent.limiteParTransaction,
limiteMinAirtime: apiAgent.limiteMinAirtime,
limiteMaxAirtime: apiAgent.limiteMaxAirtime,
maxPeripheriques: apiAgent.maxPeripheriques,
limitId: apiAgent.limitId ? String(apiAgent.limitId) : undefined,
nationalite: apiAgent.nationalite,
cni: apiAgent.cni,
cniDelivreeLe: apiAgent.cniDelivreeLe,
cniDelivreeA: apiAgent.cniDelivreeA,
residence: apiAgent.residence,
autreAdresse1: apiAgent.autreAdresse1,
statutMarital: apiAgent.statutMarital,
epoux: apiAgent.epoux,
autreTelephone: apiAgent.autreTelephone,
tpes: apiAgent.tpes?.map((tpe) => {
const transformed = this.transformTpe(tpe);
return transformed;
}),
createdAt: apiAgent.createdAt,
updatedAt: apiAgent.updatedAt,
createdBy: apiAgent.createdBy,
};
}
// Helper method to convert date string to LocalDateTime format (YYYY-MM-DDTHH:mm:ss)
private formatDateForApi(dateStr: string | undefined): string | undefined {
if (!dateStr) return undefined;
// If already in ISO format with time, return as is
if (dateStr.includes('T') || dateStr.includes(' ')) {
return dateStr;
}
// If only date (YYYY-MM-DD), add time component
if (dateStr.match(/^\d{4}-\d{2}-\d{2}$/)) {
return `${dateStr}T00:00:00`;
}
return dateStr;
}
// Transform Agent to API payload
private transformToApiPayload(agent: Partial<Agent>): any {
const payload: any = {};
if (agent.code !== undefined) payload.code = agent.code;
if (agent.profile !== undefined) payload.profile = agent.profile;
if (agent.principalCode !== undefined) payload.principalCode = agent.principalCode;
if (agent.caisseProfile !== undefined) payload.caisseProfile = agent.caisseProfile;
if (agent.statut !== undefined) payload.statut = agent.statut;
if (agent.zone !== undefined) payload.zone = agent.zone;
if (agent.kiosk !== undefined) payload.kiosk = agent.kiosk;
if (agent.fonction !== undefined) payload.fonction = agent.fonction;
if (agent.dateEmbauche !== undefined)
payload.dateEmbauche = this.formatDateForApi(agent.dateEmbauche);
if (agent.nom !== undefined) payload.nom = agent.nom;
if (agent.prenom !== undefined) payload.prenom = agent.prenom;
if (agent.autresNoms !== undefined) payload.autresNoms = agent.autresNoms;
if (agent.dateNaissance !== undefined)
payload.dateNaissance = this.formatDateForApi(agent.dateNaissance);
if (agent.lieuNaissance !== undefined) payload.lieuNaissance = agent.lieuNaissance;
if (agent.ville !== undefined) payload.ville = agent.ville;
if (agent.adresse !== undefined) payload.adresse = agent.adresse;
if (agent.autoriserAides !== undefined) payload.autoriserAides = agent.autoriserAides;
if (agent.phone !== undefined) payload.phone = agent.phone;
if (agent.pin !== undefined) payload.pin = agent.pin;
if (agent.limiteInferieure !== undefined) payload.limiteInferieure = agent.limiteInferieure;
if (agent.limiteSuperieure !== undefined) payload.limiteSuperieure = agent.limiteSuperieure;
if (agent.limiteParTransaction !== undefined)
payload.limiteParTransaction = agent.limiteParTransaction;
if (agent.limiteMinAirtime !== undefined) payload.limiteMinAirtime = agent.limiteMinAirtime;
if (agent.limiteMaxAirtime !== undefined) payload.limiteMaxAirtime = agent.limiteMaxAirtime;
if (agent.maxPeripheriques !== undefined) payload.maxPeripheriques = agent.maxPeripheriques;
if (agent.limitId !== undefined)
payload.limitId = agent.limitId ? Number(agent.limitId) : undefined;
if (agent.nationalite !== undefined) payload.nationalite = agent.nationalite;
if (agent.cni !== undefined) payload.cni = agent.cni;
if (agent.cniDelivreeLe !== undefined)
payload.cniDelivreeLe = this.formatDateForApi(agent.cniDelivreeLe);
if (agent.cniDelivreeA !== undefined) payload.cniDelivreeA = agent.cniDelivreeA;
if (agent.residence !== undefined) payload.residence = agent.residence;
if (agent.autreAdresse1 !== undefined) payload.autreAdresse1 = agent.autreAdresse1;
if (agent.statutMarital !== undefined) payload.statutMarital = agent.statutMarital;
if (agent.epoux !== undefined) payload.epoux = agent.epoux;
if (agent.autreTelephone !== undefined) payload.autreTelephone = agent.autreTelephone;
if (agent.createdBy !== undefined) payload.createdBy = agent.createdBy;
// Include tpes if provided - transform to API format
if (agent.tpes !== undefined) {
payload.tpes = agent.tpes.map((tpe) => ({
id: tpe.id ? Number(tpe.id) : undefined,
imei: tpe.imei,
serial: tpe.serial,
type: tpe.type,
marque: tpe.marque,
modele: tpe.modele,
statut: tpe.statut,
agent: undefined, // Will be set by backend
assigne: tpe.assigne,
createdAt: tpe.createdAt,
updatedAt: tpe.updatedAt,
}));
}
return payload;
}
// GET /api/v1/agents/{id} - Get by ID
getById(id: string): Observable<Agent | undefined> {
if (USE_SERVER) {
return this.http
.get<AgentApiResponse>(`${this.apiUrl}/${id}`, { headers: this.getNgrokHeaders() })
.pipe(
map((apiAgent) => this.transformAgent(apiAgent)),
catchError((err) => {
console.error(`Error fetching agent ${id}:`, err);
return of(undefined);
})
);
}
return of(undefined);
}
// GET /api/v1/agents - List all
list(params?: ListParams): Observable<PagedResult<Agent>> {
let httpParams = new HttpParams();
if (params) {
if (params.page) httpParams = httpParams.set('page', params.page.toString());
if (params.size) httpParams = httpParams.set('perPage', params.size.toString());
if (params.search) httpParams = httpParams.set('search', params.search);
if (params.sortKey) httpParams = httpParams.set('sortKey', params.sortKey);
if (params.sortDir) httpParams = httpParams.set('sortDir', params.sortDir);
}
return this.http
.get<PagedResult<AgentApiResponse>>(this.apiUrl, {
params: httpParams,
headers: this.getNgrokHeaders(),
})
.pipe(
map((res) => {
const agents = res.content.map((apiAgent) => {
const transformed = this.transformAgent(apiAgent);
return transformed;
});
// If pagination params provided, return paginated result
const resAgent = {
...res,
content: agents
}
// Otherwise return all as single page
return resAgent;
}),
catchError((err) => {
console.error('Error fetching agents:', err);
return of(normalizePage<Agent>({ content: [], meta: { total: 0 } }, 1, 10));
})
);
}
// POST /api/v1/agents - Create
create(payload: Omit<Agent, 'id' | 'createdAt' | 'updatedAt'>): Observable<Agent> {
if (USE_SERVER) {
const apiPayload = this.transformToApiPayload(payload);
return this.http
.post<AgentApiResponse>(this.apiUrl, apiPayload, { headers: this.getNgrokHeaders() })
.pipe(
map((apiAgent) => this.transformAgent(apiAgent)),
catchError((err) => {
console.error('Error creating agent:', err);
throw err;
})
);
}
throw new Error('Server mode is required');
}
// PUT /api/v1/agents/{id} - Update
update(id: string, payload: Partial<Agent>): Observable<Agent | undefined> {
if (USE_SERVER) {
const apiPayload = this.transformToApiPayload(payload);
return this.http
.put<AgentApiResponse>(`${this.apiUrl}/${id}`, apiPayload, {
headers: this.getNgrokHeaders(),
})
.pipe(
map((apiAgent) => this.transformAgent(apiAgent)),
catchError((err) => {
console.error(`Error updating agent ${id}:`, err);
return of(undefined);
})
);
}
return of(undefined);
}
// DELETE /api/v1/agents/{id} - Delete
delete(id: string): Observable<boolean> {
if (USE_SERVER) {
return this.http
.delete<void>(`${this.apiUrl}/${id}`, { headers: this.getNgrokHeaders() })
.pipe(
map(() => true),
catchError((err) => {
console.error(`Error deleting agent ${id}:`, err);
return of(false);
})
);
}
return of(false);
}
// GET /api/v1/agents/ville/{ville} - List by ville
getByVille(ville: string): Observable<Agent[]> {
if (USE_SERVER) {
return this.http
.get<AgentApiResponse[]>(`${this.apiUrl}/ville/${ville}`, {
headers: this.getNgrokHeaders(),
})
.pipe(
map((list) => list.map((apiAgent) => this.transformAgent(apiAgent))),
catchError((err) => {
console.error(`Error fetching agents by ville ${ville}:`, err);
return of([]);
})
);
}
return of([]);
}
// GET /api/v1/agents/statut/{statut} - List by statut
getByStatut(statut: AgentStatus): Observable<Agent[]> {
if (USE_SERVER) {
return this.http
.get<AgentApiResponse[]>(`${this.apiUrl}/statut/${statut}`, {
headers: this.getNgrokHeaders(),
})
.pipe(
map((list) => list.map((apiAgent) => this.transformAgent(apiAgent))),
catchError((err) => {
console.error(`Error fetching agents by statut ${statut}:`, err);
return of([]);
})
);
}
return of([]);
}
// GET /api/v1/agents/search - Search by nom or prenom
search(query: string): Observable<Agent[]> {
if (USE_SERVER) {
return this.http
.get<AgentApiResponse[]>(`${this.apiUrl}/search`, {
params: { q: query.trim() },
headers: this.getNgrokHeaders(),
})
.pipe(
map((list) => list.map((apiAgent) => this.transformAgent(apiAgent))),
catchError((err) => {
console.error(`Error searching agents with query ${query}:`, err);
return of([]);
})
);
}
return of([]);
}
// GET /api/v1/agents/code/{code} - Get by code
getByCode(code: string): Observable<Agent | undefined> {
if (USE_SERVER) {
return this.http
.get<AgentApiResponse>(`${this.apiUrl}/code/${code}`, { headers: this.getNgrokHeaders() })
.pipe(
map((apiAgent) => this.transformAgent(apiAgent)),
catchError((err) => {
console.error(`Error fetching agent by code ${code}:`, err);
return of(undefined);
})
);
}
return of(undefined);
}
// Helper method to update all agents' limitId to a new default limit
// This is used when a limit is set as default
updateAllAgentsLimitId(limitId: string): Observable<boolean> {
if (USE_SERVER) {
// Get all agents first
return this.list({
page: 1,
size: 10000,
search: '',
sortKey: 'code',
sortDir: 'asc',
} as any).pipe(
switchMap((result) => {
const agents = result.content;
if (agents.length === 0) {
return of(true);
}
// Update each agent's limitId in parallel
const updateObservables = agents.map((agent) =>
this.update(agent.id, { limitId }).pipe(
catchError((err) => {
console.error(`Error updating agent ${agent.id} limitId:`, err);
return of(undefined);
})
)
);
// Wait for all updates to complete
return forkJoin(updateObservables).pipe(
map(() => true),
catchError((err) => {
console.error('Error updating all agents limitId:', err);
return of(false);
})
);
}),
catchError((err) => {
console.error('Error fetching agents for limitId update:', err);
return of(false);
})
);
}
return of(false);
}
}