This commit is contained in:
OnlyPapy98
2025-12-30 19:09:01 +01:00
parent ed79cae77d
commit f21a5fd4e6
22 changed files with 554 additions and 315 deletions

View File

@@ -9,64 +9,72 @@ import { normalizePage } from '@shared/paging/normalize-page';
import { ListParams, PagedResult } from '@shared/paging/paging';
const USE_SERVER = true;
const API_BASE = '/api/v1/tpes';
const API_BASE = '/api/terminaux';
// Interface to match the API response structure for Agent (nested in TPE)
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;
createdAt?: string;
updatedAt?: string;
createdBy?: string;
id: number,
code: String,
profil: String,
principalCode: String,
caisseProfile: String,
statut: AgentStatus,
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,
"limiteInferieure": number,
"limiteSuperieure": number,
"limiteParTransaction": number,
"limiteMinAirtime": number,
"limiteMaxAirtime": number,
"maxPeripheriques": number,
"limitId": String,
"nationalite": String,
"cni": String,
"cniDelivreeLe": String,
"cniDelivreeA": String,
"residence": String,
"autreAdresse1": String,
"statutMarital": String,
"epoux": String,
"autreTelephone": String,
"createdAt": String,
"updatedAt": String,
"createdBy": String,
"terminauxIds": [
number[]
]
}
// Interface to match the API response structure
interface TpeApiResponse {
id: number;
imei: string;
serial: string;
type: string;
marque: string;
modele: string;
statut: string; // API uses uppercase: VALIDE, INVALIDE, EN_PANNE, BLOQUE
agent?: AgentApiResponse;
assigne: boolean;
createdAt?: string;
updatedAt?: string;
id: number,
numeroSerie: String,
pointDeVenteId: number,
statut: TpeStatus,
derniereConnexion: String,
versionLogicielle: String,
typeTerminal: String,
plateforme: String,
modeleAppareil: String,
systemeExploitation: String,
versionOs: String,
adresseIp: String,
adresseMac: String,
agentConnecteId: number,
derniereConnexionAgent: String,
derniereDeconnexionAgent: String,
journalSession: String
}
// Stats interfaces
@@ -114,29 +122,29 @@ export class TpeService {
return statut; // Already uppercase, no transformation needed
}
// Transform API Agent response to Agent
// Transform API Agent response to Agent (lightweight mapping)
private transformAgent(apiAgent: AgentApiResponse): Agent {
return {
id: String(apiAgent.id),
code: apiAgent.code,
profile: apiAgent.profile,
principalCode: apiAgent.principalCode,
caisseProfile: apiAgent.caisseProfile,
code: String((apiAgent as any).code || ''),
profile: String((apiAgent as any).profile || ''),
principalCode: (apiAgent as any).principalCode ? String((apiAgent as any).principalCode) : undefined,
caisseProfile: (apiAgent as any).caisseProfile ? String((apiAgent as any).caisseProfile) : undefined,
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,
zone: (apiAgent as any).zone ? String((apiAgent as any).zone) : undefined,
kiosk: (apiAgent as any).kiosk ? String((apiAgent as any).kiosk) : undefined,
fonction: (apiAgent as any).fonction ? String((apiAgent as any).fonction) : undefined,
dateEmbauche: apiAgent.dateEmbauche ? String(apiAgent.dateEmbauche) : undefined,
nom: String(apiAgent.nom || ''),
prenom: String(apiAgent.prenom || ''),
autresNoms: apiAgent.autresNoms ? String(apiAgent.autresNoms) : undefined,
dateNaissance: apiAgent.dateNaissance ? String(apiAgent.dateNaissance) : undefined,
lieuNaissance: apiAgent.lieuNaissance ? String(apiAgent.lieuNaissance) : undefined,
ville: apiAgent.ville ? String(apiAgent.ville) : undefined,
adresse: apiAgent.adresse ? String(apiAgent.adresse) : undefined,
autoriserAides: Boolean(apiAgent.autoriserAides),
phone: String(apiAgent.phone || ''),
pin: (apiAgent as any).pin ? String((apiAgent as any).pin) : undefined,
limiteInferieure: apiAgent.limiteInferieure,
limiteSuperieure: apiAgent.limiteSuperieure,
limiteParTransaction: apiAgent.limiteParTransaction,
@@ -144,146 +152,138 @@ export class TpeService {
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,
createdAt: apiAgent.createdAt,
updatedAt: apiAgent.updatedAt,
createdBy: apiAgent.createdBy,
nationalite: apiAgent.nationalite ? String(apiAgent.nationalite) : undefined,
cni: apiAgent.cni ? String(apiAgent.cni) : undefined,
cniDelivreeLe: apiAgent.cniDelivreeLe ? String(apiAgent.cniDelivreeLe) : undefined,
cniDelivreeA: apiAgent.cniDelivreeA ? String(apiAgent.cniDelivreeA) : undefined,
residence: apiAgent.residence ? String(apiAgent.residence) : undefined,
autreAdresse1: apiAgent.autreAdresse1 ? String(apiAgent.autreAdresse1) : undefined,
statutMarital: apiAgent.statutMarital ? String(apiAgent.statutMarital) : undefined,
epoux: apiAgent.epoux ? String(apiAgent.epoux) : undefined,
autreTelephone: apiAgent.autreTelephone ? String(apiAgent.autreTelephone) : undefined,
createdAt: apiAgent.createdAt ? String(apiAgent.createdAt) : undefined,
updatedAt: apiAgent.updatedAt ? String(apiAgent.updatedAt) : undefined,
createdBy: apiAgent.createdBy ? String(apiAgent.createdBy) : undefined,
};
}
// Transform API response to TpeDevice
private transformTpe(apiTpe: TpeApiResponse): TpeDevice {
// Map API-specific names to our generic interface where possible
const serial = (apiTpe as any).numeroSerie || (apiTpe as any).serial || '';
const imei = (apiTpe as any).imei || serial || '';
const typeRaw = String((apiTpe as any).typeTerminal || '').toUpperCase();
const type = typeRaw.includes('POS') ? ('POS' as TpeType) : ('OTHER' as TpeType);
const marque = (apiTpe as any).plateforme || (apiTpe as any).marque || '';
const modele = (apiTpe as any).modeleAppareil || (apiTpe as any).modele || '';
const statut = this.transformStatut(String(apiTpe.statut || 'INVALIDE'));
// Agent mapping: sometimes API returns an agent object or only an id
let agent: Agent | undefined = undefined;
if ((apiTpe as any).agent && typeof (apiTpe as any).agent === 'object' && (apiTpe as any).agent.id) {
agent = this.transformAgent((apiTpe as any).agent as AgentApiResponse);
}
const assigne = Boolean((apiTpe as any).agentConnecteId || (apiTpe as any).assigne);
return {
id: String(apiTpe.id),
imei: apiTpe.imei,
serial: apiTpe.serial,
type: apiTpe.type as TpeType,
marque: apiTpe.marque,
modele: apiTpe.modele,
statut: this.transformStatut(apiTpe.statut),
agent: apiTpe.agent ? this.transformAgent(apiTpe.agent) : undefined,
assigne: apiTpe.assigne,
createdAt: apiTpe.createdAt,
updatedAt: apiTpe.updatedAt,
imei: String(imei),
serial: String(serial),
type,
marque: String(marque),
modele: String(modele),
statut,
agent,
assigne,
createdAt: (apiTpe as any).createdAt,
updatedAt: (apiTpe as any).updatedAt,
};
}
// Transform TpeDevice to API payload
// Transform TpeDevice to API payload (best-effort)
private transformToApiPayload(tpe: Partial<TpeDevice>): any {
const payload: any = {};
if (tpe.imei !== undefined) payload.imei = tpe.imei;
if (tpe.serial !== undefined) payload.serial = tpe.serial;
if (tpe.type !== undefined) payload.type = tpe.type;
if (tpe.marque !== undefined) payload.marque = tpe.marque;
if (tpe.modele !== undefined) payload.modele = tpe.modele;
if (tpe.imei !== undefined) payload.numeroSerie = tpe.imei;
if (tpe.serial !== undefined) payload.numeroSerie = tpe.serial;
if (tpe.type !== undefined) payload.typeTerminal = tpe.type;
if (tpe.marque !== undefined) payload.plateforme = tpe.marque;
if (tpe.modele !== undefined) payload.modeleAppareil = tpe.modele;
if (tpe.statut !== undefined) payload.statut = this.transformStatutToApi(tpe.statut);
if (tpe.assigne !== undefined) payload.assigne = tpe.assigne;
return payload;
}
// GET /api/v1/tpes/{id} - Get by ID
getById(id: string): Observable<TpeDevice | undefined> {
if (USE_SERVER) {
return this.http
.get<TpeApiResponse>(`${this.apiUrl}/${id}`, { headers: this.getNgrokHeaders() })
.pipe(
map((apiTpe) => this.transformTpe(apiTpe)),
catchError((err) => {
console.error(`Error fetching TPE ${id}:`, err);
return of(undefined);
})
);
}
return of(undefined);
getById(id: string): Observable<TpeDevice | undefined> {
if (USE_SERVER) {
return this.http.get<TpeApiResponse>(`${this.apiUrl}/${id}`, { headers: this.getNgrokHeaders() }).pipe(
map((api) => this.transformTpe(api)),
catchError((err) => {
console.error(`Error fetching TPE ${id}:`, err);
return of(undefined);
})
);
}
return of(undefined);
}
// GET /api/v1/tpes - List all
list(params?: ListParams): Observable<PagedResult<TpeDevice>> {
if (USE_SERVER) {
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<TpeApiResponse[]>(this.apiUrl, {
params: httpParams,
headers: this.getNgrokHeaders(),
})
.pipe(
map((list) => {
const tpes = list.map((apiTpe) => this.transformTpe(apiTpe));
// If pagination params provided, return paginated result
if (params) {
return normalizePage<TpeDevice>(
{ data: tpes, meta: { total: tpes.length } },
params.page || 1,
params.size || 10
);
}
// Otherwise return all as single page
return normalizePage<TpeDevice>(
{ data: tpes, meta: { total: tpes.length } },
1,
tpes.length
);
}),
catchError((err) => {
console.error('Error fetching TPEs:', err);
return of(normalizePage<TpeDevice>({ data: [], meta: { total: 0 } }, 1, 10));
})
);
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 of(normalizePage<TpeDevice>({ data: [], meta: { total: 0 } }, 1, 10));
}
return this.http
.get<PagedResult<TpeApiResponse>>(this.apiUrl, {
params: httpParams,
headers: this.getNgrokHeaders(),
})
.pipe(
map((list) => {
const content = (list.content || []).map((api) => this.transformTpe(api));
return { ...list, content } as PagedResult<TpeDevice>;
}),
catchError((err) => {
console.error('Error fetching TPEs:', err);
return of(normalizePage<TpeDevice>({ content: [], meta: { total: 0 } }, 1, 10));
})
);
}
// POST /api/v1/tpes - Create
create(payload: Omit<TpeDevice, 'id' | 'createdAt' | 'updatedAt'>): Observable<TpeDevice> {
if (USE_SERVER) {
const apiPayload = this.transformToApiPayload(payload);
return this.http
.post<TpeApiResponse>(this.apiUrl, apiPayload, { headers: this.getNgrokHeaders() })
.pipe(
map((apiTpe) => this.transformTpe(apiTpe)),
catchError((err) => {
console.error('Error creating TPE:', err);
throw err;
})
);
}
throw new Error('Server mode is required');
create(payload: Partial<TpeDevice>): Observable<TpeDevice> {
const apiPayload = this.transformToApiPayload(payload);
return this.http
.post<TpeApiResponse>(this.apiUrl, apiPayload, { headers: this.getNgrokHeaders() })
.pipe(
map((apiTpe) => this.transformTpe(apiTpe)),
catchError((err) => {
console.error('Error creating TPE:', err);
throw err;
})
);
}
// PUT /api/v1/tpes/{id} - Update
update(id: string, payload: Partial<TpeDevice>): Observable<TpeDevice | undefined> {
if (USE_SERVER) {
const apiPayload = this.transformToApiPayload(payload);
return this.http
.put<TpeApiResponse>(`${this.apiUrl}/${id}`, apiPayload, {
headers: this.getNgrokHeaders(),
// PUT /api/v1/tpes/{id} - Update
update(id: string, payload: Partial<TpeDevice>): Observable<TpeDevice | undefined> {
const apiPayload = this.transformToApiPayload(payload);
return this.http
.put<TpeApiResponse>(`${this.apiUrl}/${id}`, apiPayload, {
headers: this.getNgrokHeaders(),
})
.pipe(
map((apiTpe) => this.transformTpe(apiTpe)),
catchError((err) => {
console.error(`Error updating TPE ${id}:`, err);
return of(undefined);
})
.pipe(
map((apiTpe) => this.transformTpe(apiTpe)),
catchError((err) => {
console.error(`Error updating TPE ${id}:`, err);
return of(undefined);
})
);
}
return of(undefined);
}
);
}
// DELETE /api/v1/tpes/{id} - Delete
delete(id: string): Observable<boolean> {