Initial commit
This commit is contained in:
203
services/materielPhaseService.ts
Normal file
203
services/materielPhaseService.ts
Normal file
@@ -0,0 +1,203 @@
|
||||
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<MaterielPhase[]> {
|
||||
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<MaterielPhase> {
|
||||
const response = await this.api.get(`${this.basePath}/${id}`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Créer un nouveau matériel de phase
|
||||
*/
|
||||
async create(materielPhase: Omit<MaterielPhase, 'id'>): Promise<MaterielPhase> {
|
||||
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<MaterielPhase>): Promise<MaterielPhase> {
|
||||
const response = await this.api.put(`${this.basePath}/${id}`, materielPhase);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Supprimer un matériel de phase
|
||||
*/
|
||||
async delete(id: number): Promise<void> {
|
||||
await this.api.delete(`${this.basePath}/${id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculer le coût total des matériels d'une phase
|
||||
*/
|
||||
async calculerCoutTotal(phaseId: string): Promise<number> {
|
||||
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<MaterielPhase[]> {
|
||||
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<FournisseurPhase[]> {
|
||||
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<MaterielPhase> {
|
||||
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<MaterielPhase> {
|
||||
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<AnalysePrixPhase> {
|
||||
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();
|
||||
Reference in New Issue
Block a user