import axios from 'axios'; import { API_CONFIG } from '../config/api'; import { MaterielPhase, FournisseurPhase, AnalysePrixPhase, ApiResponse } from '../types/btp-extended'; class MaterielPhaseService { private readonly basePath = '/materiels-phases'; private api = axios.create({ baseURL: API_CONFIG.baseURL, timeout: API_CONFIG.timeout, headers: API_CONFIG.headers, }); constructor() { // Interceptor pour ajouter le token JWT this.api.interceptors.request.use( (config) => { let token = null; try { const authTokenItem = sessionStorage.getItem('auth_token') || localStorage.getItem('auth_token'); if (authTokenItem) { const parsed = JSON.parse(authTokenItem); token = parsed.value; } } catch (e) { token = localStorage.getItem('token'); } if (token) { config.headers['Authorization'] = `Bearer ${token}`; } return config; }, (error) => Promise.reject(error) ); // Interceptor pour les réponses this.api.interceptors.response.use( (response) => response, (error) => { if (error.response?.status === 401) { localStorage.removeItem('token'); localStorage.removeItem('user'); window.location.href = '/api/auth/login'; } return Promise.reject(error); } ); } /** * Récupérer les matériels d'une phase */ async getByPhase(phaseId: string): Promise { if (!phaseId || phaseId === 'undefined' || phaseId === 'null' || phaseId === 'NaN') { console.warn(`ID de phase invalide: ${phaseId}`); return []; } try { const response = await this.api.get(`${this.basePath}/phase/${phaseId}`); return response.data; } catch (error) { console.warn(`Endpoint ${this.basePath}/phase/${phaseId} non disponible:`, error); return []; } } /** * Récupérer un matériel de phase par ID */ async getById(id: number): Promise { const response = await this.api.get(`${this.basePath}/${id}`); return response.data; } /** * Créer un nouveau matériel de phase */ async create(materielPhase: Omit): Promise { console.log('Creating materiel phase with data:', materielPhase); const response = await this.api.post(this.basePath, materielPhase); return response.data; } /** * Modifier un matériel de phase existant */ async update(id: number, materielPhase: Partial): Promise { const response = await this.api.put(`${this.basePath}/${id}`, materielPhase); return response.data; } /** * Supprimer un matériel de phase */ async delete(id: number): Promise { await this.api.delete(`${this.basePath}/${id}`); } /** * Calculer le coût total des matériels d'une phase */ async calculerCoutTotal(phaseId: string): Promise { try { const materiels = await this.getByPhase(phaseId); return materiels.reduce((total, materiel) => { const prix = materiel.prixUnitaireNegocie || materiel.prixUnitaireCatalogue || 0; const quantite = materiel.quantiteUtilisee || materiel.quantitePrevue || 0; return total + (prix * quantite); }, 0); } catch (error) { console.error('Erreur lors du calcul du coût total:', error); return 0; } } /** * Obtenir les matériels en rupture de stock pour une phase */ async getMaterielsEnRupture(phaseId: string): Promise { try { const materiels = await this.getByPhase(phaseId); return materiels.filter(materiel => materiel.enStock === false || (materiel.quantiteStock || 0) < (materiel.quantitePrevue || 0) ); } catch (error) { console.error('Erreur lors de la vérification du stock:', error); return []; } } /** * Obtenir les alternatives de fournisseurs pour un matériel */ async getFournisseursAlternatifs(materielPhaseId: number): Promise { try { const response = await this.api.get(`${this.basePath}/${materielPhaseId}/fournisseurs-alternatifs`); return response.data; } catch (error) { console.warn('Fournisseurs alternatifs non disponibles:', error); return []; } } /** * Négocier un prix avec un fournisseur */ async negocierPrix(materielPhaseId: number, fournisseurId: number, prixNegocie: number): Promise { const response = await this.api.post(`${this.basePath}/${materielPhaseId}/negocier-prix`, { fournisseurId, prixNegocie }); return response.data; } /** * Valider la sélection d'un fournisseur */ async validerFournisseur(materielPhaseId: number, fournisseurPhaseId: number): Promise { const response = await this.api.post(`${this.basePath}/${materielPhaseId}/valider-fournisseur`, { fournisseurPhaseId }); return response.data; } /** * Calculer l'analyse de prix pour une phase */ async calculerAnalysePrix(phaseId: string): Promise { try { const response = await this.api.post(`/analyses-prix/calculer/${phaseId}`); return response.data; } catch (error) { // Calcul côté client si l'endpoint n'existe pas const materiels = await this.getByPhase(phaseId); const coutMateriauxTotal = materiels.reduce((total, materiel) => { const prix = materiel.prixUnitaireNegocie || materiel.prixUnitaireCatalogue || 0; const quantite = materiel.quantiteUtilisee || materiel.quantitePrevue || 0; return total + (prix * quantite); }, 0); return { phase: { id: parseInt(phaseId) } as any, coutMateriauxTotal, coutMainOeuvreTotal: 0, coutSousTraitanceTotal: 0, coutAutresTotal: 0, coutTotalDirect: coutMateriauxTotal, coutTotalAvecFrais: coutMateriauxTotal, prixVenteCalcule: coutMateriauxTotal * 1.2, // Marge de 20% par défaut dateAnalyse: new Date() }; } } } export default new MaterielPhaseService();