TROUBLESHOOTING - PT2QE¶
1. ERREURS FRÉQUENTES¶
1.1. Fichier capping_type_client.csv introuvable¶
Symptôme :
Diagnostic étape par étape :
-
Vérifier l'existence du fichier :
-
Si le fichier n'existe pas, vérifier le répertoire inputs :
-
Créer le répertoire si nécessaire :
Solution - Création du fichier :
- Créer le fichier
inputs\capping_type_client.csvavec ce contenu exact :
Règles de format obligatoires :
- Séparateur : point-virgule (;)
- Décimale : virgule (,)
- Encodage : CP1252 (Windows)
- Pas d'espaces avant/après les valeurs
Vérification du format :
Valeurs attendues : - CAPPING_HIGH : entre 0,01 et 0,10 (1% à 10%) - CAPPING_MEDIUM : entre 0,03 et 0,20 (3% à 20%) - CAPPING_LOW : entre 0,05 et 0,30 (5% à 30%)
1.2. Tables PT1CE_OPTIMAL_* manquantes¶
Symptôme :
Contexte : PT2QE nécessite impérativement que PT1CE ait été exécuté au préalable car il utilise les corridors optimaux calculés par PT1CE.
Diagnostic SQL :
-- Vérifier les tables PT1CE existantes
SELECT table_name, num_rows, last_analyzed
FROM user_tables
WHERE table_name LIKE 'PT1CE_OPTIMAL%'
ORDER BY table_name;
Résultat attendu :
TABLE_NAME NUM_ROWS LAST_ANALYZED
PT1CE_OPTIMAL_ZOOM1 XXXXX DATE
PT1CE_OPTIMAL_ZOOM2 XXXXX DATE
PT1CE_OPTIMAL_ZOOM3 XXXXX DATE
Si aucune table trouvée :
-
Cause : PT1CE n'a jamais été exécuté ou les tables ont été supprimées
-
Solution obligatoire :
- Aller dans le répertoire PT1CE
- Lancer
START.bat - Exécuter dans l'ordre :
- Option 1 : Application nouveaux PAS/PRB
- Option 2 : Finalisation corridors
- Attendre la fin complète de PT1CE
-
Vérifier à nouveau les tables
-
Vérification post-PT1CE :
SELECT 'ZOOM1' as ZOOM, COUNT(*) as NB_CORRIDORS, COUNT(DISTINCT ID_ART) as NB_ARTICLES, COUNT(DISTINCT TYPE_CLIENT) as NB_TYPE_CLIENT FROM PT1CE_OPTIMAL_ZOOM1 WHERE STATUS = 'OPTIMAL' UNION ALL SELECT 'ZOOM2', COUNT(*), COUNT(DISTINCT ID_ART), COUNT(DISTINCT TYPE_CLIENT) FROM PT1CE_OPTIMAL_ZOOM2 WHERE STATUS = 'OPTIMAL' UNION ALL SELECT 'ZOOM3', COUNT(*), COUNT(DISTINCT ID_ART), COUNT(DISTINCT TYPE_CLIENT) FROM PT1CE_OPTIMAL_ZOOM3 WHERE STATUS = 'OPTIMAL';
Si les tables existent mais sont vides :
Si aucune ligne STATUS = 'OPTIMAL', PT1CE n'a pas été finalisé → Relancer PT1CE Option 2.
1.3. Mapping TYPE_CLIENT incomplet¶
Symptôme :
Diagnostic détaillé :
-
Identifier les combinaisons non mappées :
SELECT o.ID_TC_CG, o.ID_TC_CIBLE, o.FG_HM, COUNT(*) as NB_OFFRES, COUNT(DISTINCT o.ID_CLN) as NB_CLIENTS, COUNT(DISTINCT o.ID_ART) as NB_ARTICLES FROM PT2QE_PRICE_OFFERS o WHERE o.TYPE_CLIENT IS NULL OR o.TYPE_CLIENT = 'Hors référentiel' GROUP BY o.ID_TC_CG, o.ID_TC_CIBLE, o.FG_HM ORDER BY NB_OFFRES DESC; -
Vérifier le mapping existant pour ces combinaisons :
Causes possibles :
Cas 1 : FG_HM non déterminé
-- Vérifier les offres sans FG_HM
SELECT
COUNT(*) as NB_OFFRES_SANS_FG_HM
FROM PT2QE_PRICE_OFFERS
WHERE FG_HM IS NULL;
Explication : FG_HM est récupéré depuis l'historique transactionnel (4 derniers quarters). Si NULL, le client n'a pas d'historique.
Solution : - Accepter ces offres (elles auront FG_HM par défaut) - OU les exclure du périmètre
Cas 2 : Combinaison non présente dans PT0CE_TYPE_CLIENT_MAPPING
Solution - Ajouter le mapping dans PT0CE :
-
Identifier la bonne valeur de TYPE_CLIENT :
-
Insérer le nouveau mapping dans PT0CE_TYPE_CLIENT_MAPPING :
-
Relancer PT2QE après avoir complété les mappings.
Cas 3 : Mapping TYPE_RESTAURANT manquant
Diagnostic :
SELECT
o.LC_SFC_CIBLE,
COUNT(*) as NB_OFFRES
FROM PT2QE_PRICE_OFFERS o
WHERE o.TYPE_RESTAURANT IS NULL
OR o.TYPE_RESTAURANT = 'Hors référentiel'
GROUP BY o.LC_SFC_CIBLE
ORDER BY NB_OFFRES DESC;
Vérifier le mapping :
Solution - Ajouter le mapping :
INSERT INTO PT0CE_TYPE_RESTAURANT_MAPPING (
LC_SFC_CIBLE, Type_Restaurant
) VALUES (
'XXX',
'NOM_TYPE_RESTAURANT'
);
COMMIT;
1.4. Erreur de connexion Oracle¶
Symptôme :
ouDiagnostic :
-
Vérifier le fichier tnsnames.ora :
-
Tester la connexion avec SQL*Plus :
-
Vérifier les variables d'environnement :
Solutions selon l'erreur :
ORA-01017 (Mauvais identifiant/mot de passe) : - Vérifier les credentials - Vérifier que le compte n'est pas verrouillé - Contacter l'administrateur Oracle
ORA-12154 (TNS non trouvé) : 1. Vérifier que TARIFAIRE existe dans tnsnames.ora 2. Définir TNS_ADMIN si nécessaire :
ORA-12514 (Listener ne connaît pas le service) : 1. Vérifier le service Oracle :
1.5. Module Python manquant¶
Symptôme :
ouDiagnostic :
python -c "import pandas; print(pandas.__version__)"
python -c "import oracledb; print(oracledb.__version__)"
python -c "import openpyxl; print(openpyxl.__version__)"
Solution - Installation des dépendances :
-
Vérifier pip :
-
Installer les modules manquants :
Note importante : Le flag --break-system-packages est obligatoire dans l'environnement Sysco.
- Vérifier l'installation :
2. PROBLÈMES DE DONNÉES¶
2.1. Taux de matching corridors faible¶
Symptôme :
[INFO] → Résultats du matching :
[INFO] - MASTER : 145,678 offres
[INFO] - NATIONAL : 89,234 offres
[INFO] - NO_MATCH : 234,567 offres (50%)
Contexte : PT2QE fonctionne en ZOOM1 EXCLUSIF. Le matching tente d'abord une jointure MASTER (dimensions spécifiques), puis fallback vers NATIONAL si pas de match.
Diagnostic SQL détaillé :
-
Analyser les offres non matchées :
SELECT CASE WHEN c.ID_ART IS NULL THEN 'Article sans corridor PT1CE' WHEN o.TYPE_CLIENT IS NULL THEN 'TYPE_CLIENT manquant' WHEN o.TYPE_RESTAURANT IS NULL THEN 'TYPE_RESTAURANT manquant' WHEN o.UNIVERS != 'ZOOM1' THEN 'UNIVERS non ZOOM1' ELSE 'Autre raison' END as RAISON_NON_MATCH, COUNT(*) as NB_OFFRES, COUNT(DISTINCT o.ID_CLN) as NB_CLIENTS, COUNT(DISTINCT o.ID_ART) as NB_ARTICLES FROM PT2QE_PRICE_OFFERS o LEFT JOIN ( SELECT DISTINCT ID_ART, TYPE_CLIENT, TYPE_RESTAURANT, GEO FROM PT1CE_OPTIMAL_ZOOM1 WHERE STATUS = 'OPTIMAL' ) c ON o.ID_ART = c.ID_ART WHERE NOT EXISTS ( SELECT 1 FROM PT2QE_PRICE_OFFERS_ENRICHED e WHERE e.ID_CLN = o.ID_CLN AND e.ID_ART = o.ID_ART AND e.HAS_CORRIDOR = 1 ) GROUP BY CASE WHEN c.ID_ART IS NULL THEN 'Article sans corridor PT1CE' WHEN o.TYPE_CLIENT IS NULL THEN 'TYPE_CLIENT manquant' WHEN o.TYPE_RESTAURANT IS NULL THEN 'TYPE_RESTAURANT manquant' WHEN o.UNIVERS != 'ZOOM1' THEN 'UNIVERS non ZOOM1' ELSE 'Autre raison' END ORDER BY NB_OFFRES DESC; -
Vérifier les articles sans corridor :
-- Articles présents dans les offres mais absents de PT1CE SELECT o.ID_ART, o.LC_ART, COUNT(DISTINCT o.ID_CLN) as NB_CLIENTS_CONCERNES, COUNT(*) as NB_OFFRES FROM PT2QE_PRICE_OFFERS o WHERE NOT EXISTS ( SELECT 1 FROM PT1CE_OPTIMAL_ZOOM1 c WHERE c.ID_ART = o.ID_ART AND c.STATUS = 'OPTIMAL' ) GROUP BY o.ID_ART, o.LC_ART ORDER BY NB_OFFRES DESC FETCH FIRST 50 ROWS ONLY;
Solutions selon la cause :
Cas 1 : Articles nouveaux sans corridor
Ces articles n'ont pas de corridor PT1CE car : - Nouveaux dans le référentiel - Pas assez d'historique transactionnel - Exclus du périmètre PT1CE
Options : 1. Accepter le fallback NATIONAL : PT2QE utilise automatiquement les corridors NATIONAL 2. Exclure ces articles : Modifier l'extraction pour les filtrer 3. Créer des corridors manuellement dans PT1CE : Voir documentation PT1CE
Cas 2 : Dimensions non mappées
Voir section 1.3 pour compléter les mappings.
Cas 3 : UNIVERS != ZOOM1
Diagnostic :
Solution : Par design, PT2QE ne traite que ZOOM1. Les offres ZOOM2/ZOOM3 sont filtrées dès l'extraction.
Si vous voyez des offres non-ZOOM1, c'est une anomalie → Vérifier la logique d'attribution d'UNIVERS dans extract_price_offers.py.
2.2. Hausses anormalement élevées¶
Symptôme :
Diagnostic SQL - Identifier les cas extrêmes :
SELECT
r.ID_CLN,
r.LC_CLN,
r.ID_ART,
r.LC_ART,
r.TYPE_CLIENT,
r.TYPE_RESTAURANT,
r.UNIVERS,
-- Prix et hausses
r.PRIX_TARIF_ACTUEL,
r.PRIX_RECOMMANDE,
r.PCT_HAUSSE_FINALE * 100 as PCT_HAUSSE,
(r.PRIX_RECOMMANDE - r.PRIX_TARIF_ACTUEL) as HAUSSE_EUROS,
-- Positions
r.POSITION_TARIF_ACTUEL_DANS_ANCIENNES_BORNES as POS_AVANT_ANCIENNES,
r.PALIER_TARIF_ACTUEL_VS_NOUVELLES_BORNES as POS_AVANT_NOUVELLES,
r.POSITION_NOUVEAU_PRIX_DANS_NOUVELLES_BORNES as POS_APRES,
-- Arbre de décision
r.DECISION_PATH,
r.RECO_SELECTIONNEE,
r.CAPPING_APPLIED,
-- Contexte corridor
r.NEW_PAS,
r.NEW_PRB,
r.PRICE_SENSITIVITY,
-- Recommandations intermédiaires
r.RECO1_BASE,
r.RECO1_APRES_CAPPING_SENSIBILITE,
r.RECO1_AVEC_CAPPING,
r.RECO2
FROM PT2QE_RECOMMENDATIONS r
WHERE r.PCT_HAUSSE_FINALE > 0.30
ORDER BY r.PCT_HAUSSE_FINALE DESC
FETCH FIRST 100 ROWS ONLY;
Analyse des causes fréquentes :
Cause 1 : Prix actuel très bas (sous le PAS)
-- Vérifier les offres en BELOW_PAS
SELECT
COUNT(*) as NB_OFFRES_BELOW_PAS,
AVG(PCT_HAUSSE_FINALE) * 100 as HAUSSE_MOY_PCT
FROM PT2QE_RECOMMENDATIONS
WHERE POSITION_TARIF_ACTUEL_DANS_ANCIENNES_BORNES = 'BELOW_PAS'
AND PCT_HAUSSE_FINALE > 0.30;
Explication : Si le prix actuel est sous le PAS et que RECO1 vise à remonter au PAS minimum, la hausse peut être très importante.
Solution - Ajuster le capping LOW pour ces cas :
-
Créer
corrections\capping_cubes_corrections.csv: -
Relancer avec l'option 2 (Ajuster cappings).
Cause 2 : Repositionnement agressif (CHEMIN 3)
-- Analyser les repositionnements forts
SELECT
POSITION_TARIF_ACTUEL_DANS_ANCIENNES_BORNES,
POSITION_NOUVEAU_PRIX_DANS_NOUVELLES_BORNES,
COUNT(*) as NB_OFFRES,
AVG(PCT_HAUSSE_FINALE) * 100 as HAUSSE_MOY_PCT,
MIN(PCT_HAUSSE_FINALE) * 100 as HAUSSE_MIN_PCT,
MAX(PCT_HAUSSE_FINALE) * 100 as HAUSSE_MAX_PCT
FROM PT2QE_RECOMMENDATIONS
WHERE PCT_HAUSSE_FINALE > 0.30
AND DECISION_PATH = 'OPTIMISATION_STANDARD'
GROUP BY
POSITION_TARIF_ACTUEL_DANS_ANCIENNES_BORNES,
POSITION_NOUVEAU_PRIX_DANS_NOUVELLES_BORNES
ORDER BY HAUSSE_MOY_PCT DESC;
Explication : Les règles de repositionnement RECO1 peuvent être très agressives si configurées pour sauter plusieurs paliers.
Solution - Modifier les règles RECO1 :
-
Éditer
config\pt2qe_config.json: -
Relancer le calcul complet.
Cause 3 : Capping insuffisant
-- Vérifier les cappings appliqués pour les hausses > 30%
SELECT
CAPPING_APPLIED,
PRICE_SENSITIVITY,
COUNT(*) as NB_OFFRES,
AVG(PCT_HAUSSE_FINALE) * 100 as HAUSSE_MOY_PCT
FROM PT2QE_RECOMMENDATIONS
WHERE PCT_HAUSSE_FINALE > 0.30
GROUP BY CAPPING_APPLIED, PRICE_SENSITIVITY
ORDER BY NB_OFFRES DESC;
Si CAPPING_APPLIED = 'NONE', les cappings ne s'appliquent pas → Ajuster les valeurs de capping.
2.3. Données historiques manquantes (4Q)¶
Symptôme :
Contexte : PT2QE enrichit chaque offre avec des métriques transactionnelles sur les 4 derniers trimestres fiscaux COMPLETS.
Diagnostic - Vérifier la période d'extraction :
-- Afficher la période utilisée
SELECT DISTINCT
TO_CHAR(MIN(o.EXTRACTION_DATE), 'YYYY-MM-DD') as DATE_EXTRACTION,
-- Récupérer la période depuis les logs du run
NULL as PERIODE_4Q_DEBUT,
NULL as PERIODE_4Q_FIN
FROM PT2QE_PRICE_OFFERS o;
Note : Les dates exactes de la période 4Q sont affichées au démarrage du traitement dans les logs.
Diagnostic - Offres sans CA :
SELECT
COUNT(*) as TOTAL_OFFRES,
SUM(CASE WHEN MT_CAB_4Q = 0 THEN 1 ELSE 0 END) as NB_SANS_CA,
SUM(CASE WHEN MT_CAB_4Q = 0 THEN 1 ELSE 0 END) * 100.0 / COUNT(*) as PCT_SANS_CA,
SUM(CASE WHEN QT_UF_4Q = 0 THEN 1 ELSE 0 END) as NB_SANS_VOLUME,
SUM(CASE WHEN FG_HM IS NULL THEN 1 ELSE 0 END) as NB_SANS_FG_HM
FROM PT2QE_PRICE_OFFERS;
Diagnostic - Par type client :
SELECT
TYPE_CLIENT,
COUNT(*) as NB_OFFRES,
SUM(CASE WHEN MT_CAB_4Q = 0 THEN 1 ELSE 0 END) as NB_SANS_CA,
ROUND(SUM(CASE WHEN MT_CAB_4Q = 0 THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 1) as PCT_SANS_CA
FROM PT2QE_PRICE_OFFERS
GROUP BY TYPE_CLIENT
ORDER BY PCT_SANS_CA DESC;
Causes et solutions :
Cas 1 : Nouveaux clients sans historique
Normal pour des clients récents. Options :
1. Accepter : Ces offres auront MT_CAB_4Q = 0 et FG_HM sera estimé
2. Exclure : Filtrer ces clients dans l'extraction
Cas 2 : Période 4Q trop ancienne
Si la période 4Q ne couvre pas les transactions récentes :
- Vérifier SYS_MD_CALENDRIER_SYSCO pour la cohérence
- Les 4Q sont calculés automatiquement par PeriodManager
Diagnostic de la période :
-- Vérifier la semaine en cours selon le calendrier fiscal
SELECT
ID_SEM,
LC_EXF_SEF,
ID_EXF,
NO_PEF,
NO_TRF
FROM SYS_MD_CALENDRIER_SYSCO
WHERE FG_SEM_EN_COURS = 'X';
Cas 3 : Filtres transactionnels trop restrictifs
Les filtres appliqués dans extract_price_offers.py sont :
- ID_TYP_FAC = 'ZF2'
- LC_TC_INTRA IN ('Brake', 'D2 hors Brake')
- COALESCE(TRIM(FG_PRESTA), '0') = '0'
- COALESCE(TRIM(FG_MARCHANDISE), ' ') IN ('X', '1')
- MT_GM4 IS NOT NULL
- MT_CAB > 0
- QT_UF > 0
- Exclusion Prix promo (PRP_LABELS)
Vérifier si trop restrictifs :
-- Comparer volume avec/sans filtres
WITH AVEC_FILTRES AS (
SELECT COUNT(*) as NB_LIGNES
FROM SYS_FACTURE_LIGNE f
JOIN SYS_MD_CLIENT c ON f.ID_CLN_KEY = c.ID_CLN_KEY
WHERE f.DT_CDE BETWEEN DATE '2024-01-01' AND DATE '2024-12-31'
AND f.ID_TYP_FAC = 'ZF2'
AND c.LC_TC_INTRA IN ('Brake', 'D2 hors Brake')
AND COALESCE(TRIM(f.FG_PRESTA), '0') = '0'
AND f.MT_CAB > 0
AND f.QT_UF > 0
),
SANS_FILTRES AS (
SELECT COUNT(*) as NB_LIGNES
FROM SYS_FACTURE_LIGNE f
JOIN SYS_MD_CLIENT c ON f.ID_CLN_KEY = c.ID_CLN_KEY
WHERE f.DT_CDE BETWEEN DATE '2024-01-01' AND DATE '2024-12-31'
AND f.ID_TYP_FAC = 'ZF2'
)
SELECT
a.NB_LIGNES as AVEC_FILTRES,
s.NB_LIGNES as SANS_FILTRES,
ROUND(a.NB_LIGNES * 100.0 / s.NB_LIGNES, 1) as PCT_CONSERVE
FROM AVEC_FILTRES a, SANS_FILTRES s;
2.4. Valeurs NULL dans les positions¶
Symptôme :
Des offres ont POSITION_TARIF_ACTUEL_DANS_ANCIENNES_BORNES = NULL.
Diagnostic :
SELECT
COUNT(*) as NB_AVEC_POSITION_NULL
FROM PT2QE_RECOMMENDATIONS
WHERE POSITION_TARIF_ACTUEL_DANS_ANCIENNES_BORNES IS NULL
OR POSITION_NOUVEAU_PRIX_DANS_NOUVELLES_BORNES IS NULL;
Cause : Bornes manquantes ou prix NULL.
Diagnostic détaillé :
SELECT
r.ID_CLN,
r.ID_ART,
r.PRIX_TARIF_ACTUEL,
r.PAS_ACTIF,
r.PRB_ACTIF,
r.BORNE_PL1_PL2,
r.BORNE_PL2_PL3,
r.BORNE_PL3_PL4,
r.POSITION_TARIF_ACTUEL_DANS_ANCIENNES_BORNES
FROM PT2QE_RECOMMENDATIONS r
WHERE r.POSITION_TARIF_ACTUEL_DANS_ANCIENNES_BORNES IS NULL
FETCH FIRST 20 ROWS ONLY;
Solution : Vérifier l'intégrité des données PT1CE pour ces articles.
3. PROBLÈMES DE PERFORMANCE¶
3.1. Phase 1 (Extraction) très lente¶
Symptôme : Phase 1 dure excessivement longtemps.
Diagnostic - Vérifier les statistiques tables :
SELECT
table_name,
num_rows,
blocks,
last_analyzed,
CASE
WHEN last_analyzed IS NULL THEN 'JAMAIS'
WHEN last_analyzed < SYSDATE - 30 THEN 'OBSOLETE (>30j)'
WHEN last_analyzed < SYSDATE - 7 THEN 'ANCIEN (>7j)'
ELSE 'OK'
END as ETAT_STATS
FROM user_tables
WHERE table_name IN (
'SYS_TARIF_SIMULATION',
'SYS_FACTURE_LIGNE',
'SYS_MD_CLIENT',
'SYS_MD_ARTICLE',
'SYS_MD_CONDITION'
)
ORDER BY table_name;
Si ETAT_STATS = 'OBSOLETE' ou 'JAMAIS' :
Solution - Rafraîchir les statistiques :
-- En tant qu'administrateur ou avec droits suffisants
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(
ownname => USER,
tabname => 'SYS_FACTURE_LIGNE',
estimate_percent => 10,
method_opt => 'FOR ALL COLUMNS SIZE AUTO',
cascade => TRUE
);
END;
/
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(
ownname => USER,
tabname => 'SYS_TARIF_SIMULATION',
estimate_percent => 10,
method_opt => 'FOR ALL COLUMNS SIZE AUTO',
cascade => TRUE
);
END;
/
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(
ownname => USER,
tabname => 'SYS_MD_CLIENT',
estimate_percent => 10,
method_opt => 'FOR ALL COLUMNS SIZE AUTO',
cascade => TRUE
);
END;
/
Diagnostic - Vérifier les sessions longues :
Si l'extraction est en cours, vérifier la requête active :
SELECT
s.sid,
s.serial#,
s.username,
s.status,
s.sql_id,
s.last_call_et as SECONDES_ACTIVES,
q.sql_text
FROM v$session s
LEFT JOIN v$sql q ON s.sql_id = q.sql_id
WHERE s.username = USER
AND s.status = 'ACTIVE'
ORDER BY s.last_call_et DESC;
Solution - Optimiser la requête d'extraction :
La requête d'extraction utilise /*+ PARALLEL(8) */. Si trop lent :
-
Réduire le parallélisme : Éditer
extract_price_offers.py, remplacerPARALLEL(8)parPARALLEL(4). -
Ajouter des hints supplémentaires :
3.2. Phase 2 (Calcul recommandations) très lente¶
Symptôme : Phase 2 ne progresse pas.
Diagnostic SQL - Vérifier les tables créées :
SELECT
table_name,
num_rows,
TO_CHAR(last_analyzed, 'YYYY-MM-DD HH24:MI:SS') as last_analyzed
FROM user_tables
WHERE table_name IN (
'PT2QE_PRICE_OFFERS',
'PT2QE_PRICE_OFFERS_ENRICHED',
'PT2QE_CAPPING_CUBES',
'PT2QE_RECOMMENDATIONS'
)
ORDER BY table_name;
Diagnostic - Session active :
-- Vérifier la requête en cours
SELECT
s.sid,
s.serial#,
s.sql_id,
s.last_call_et / 60 as MINUTES_ACTIVES,
SUBSTR(q.sql_text, 1, 200) as DEBUT_SQL
FROM v$session s
LEFT JOIN v$sql q ON s.sql_id = q.sql_id
WHERE s.username = USER
AND s.status = 'ACTIVE';
Solution - Optimisation config :
Éditer config\pt2qe_config.json :
Solution - Réduire le périmètre pour test :
Modifier temporairement calculate_recommendations.py pour limiter le volume :
3.3. Mémoire insuffisante (Python)¶
Symptôme :
Cause : Pandas charge trop de données en mémoire.
Solution 1 - Réduire batch_size :
Éditer config\pt2qe_config.json :
Solution 2 - Augmenter mémoire Python (si possible) :
Solution 3 - Traiter par chunks :
Si le problème persiste, contacter le support pour activer le mode chunk.
4. PROBLÈMES DE CALCUL¶
4.1. Recommandations incohérentes¶
Symptôme : Prix recommandé < Prix actuel (ne devrait JAMAIS arriver).
Diagnostic SQL :
-- Détecter les anomalies
SELECT
r.ID_CLN,
r.ID_ART,
r.PRIX_TARIF_ACTUEL,
r.PRIX_RECOMMANDE,
r.PCT_HAUSSE_FINALE * 100 as PCT_HAUSSE,
r.DECISION_PATH,
r.RECO_SELECTIONNEE,
r.CAPPING_APPLIED
FROM PT2QE_RECOMMENDATIONS r
WHERE r.PRIX_RECOMMANDE < r.PRIX_TARIF_ACTUEL;
Si des lignes sont retournées, c'est un BUG.
Procédure de remontée :
-
Exporter le résultat :
-
Sauvegarder en CSV.
-
Contacter le support avec :
- Le CSV des anomalies
- Les logs complets du run
- Le fichier
capping_type_client.csvutilisé - Le fichier
pt2qe_config.json
Solution temporaire - Corriger manuellement :
-- NE PAS FAIRE en production sans validation
UPDATE PT2QE_RECOMMENDATIONS
SET PRIX_RECOMMANDE = PRIX_TARIF_ACTUEL,
PCT_HAUSSE_FINALE = 0
WHERE PRIX_RECOMMANDE < PRIX_TARIF_ACTUEL;
COMMIT;
4.2. Capping non appliqué¶
Symptôme : RECO1_AVEC_CAPPING = RECO1_BASE malgré hausse importante.
Diagnostic SQL :
SELECT
r.ID_CLN,
r.ID_ART,
r.PRICE_SENSITIVITY,
r.RECO1_BASE,
r.RECO1_APRES_CAPPING_SENSIBILITE,
r.RECO1_AVEC_CAPPING,
r.PRIX_TARIF_ACTUEL,
(r.RECO1_BASE - r.PRIX_TARIF_ACTUEL) / r.PRIX_TARIF_ACTUEL * 100 as PCT_HAUSSE_BASE,
r.TYPE_CLIENT,
r.TYPE_RESTAURANT,
r.GEO,
r.CAPPING_APPLIED
FROM PT2QE_RECOMMENDATIONS r
WHERE r.RECO1_BASE = r.RECO1_AVEC_CAPPING
AND r.RECO1_BASE > r.PRIX_TARIF_ACTUEL * 1.20 -- Hausse > 20%
AND r.DECISION_PATH = 'OPTIMISATION_STANDARD'
FETCH FIRST 50 ROWS ONLY;
Vérifier les cappings associés :
-- Remplacer par les valeurs trouvées ci-dessus
SELECT *
FROM PT2QE_CAPPING_CUBES
WHERE UNIVERS = 'ZOOM1'
AND TYPE_CLIENT = 'XXX'
AND TYPE_RESTAURANT = 'YYY'
AND NVL(GEO, 'NULL') = NVL('ZZZ', 'NULL');
Causes possibles :
Cas 1 : Valeurs NULL dans PT2QE_CAPPING_CUBES
Si CAPPING_HIGH/MEDIUM/LOW = NULL :
Solution :
-- Mettre à jour avec valeurs par défaut
UPDATE PT2QE_CAPPING_CUBES
SET CAPPING_HIGH = 0.05,
CAPPING_MEDIUM = 0.15,
CAPPING_LOW = 0.20
WHERE CAPPING_HIGH IS NULL
OR CAPPING_MEDIUM IS NULL
OR CAPPING_LOW IS NULL;
COMMIT;
Relancer avec Option 2 (Ajuster cappings).
Cas 2 : Jointure cube non réalisée
Vérifier la jointure :
SELECT
COUNT(*) as TOTAL,
SUM(CASE WHEN c.TYPE_CLIENT IS NOT NULL THEN 1 ELSE 0 END) as AVEC_CAPPING
FROM PT2QE_PRICE_OFFERS_ENRICHED e
LEFT JOIN PT2QE_CAPPING_CUBES c
ON e.UNIVERS = c.UNIVERS
AND e.TYPE_CLIENT = c.TYPE_CLIENT
AND e.TYPE_RESTAURANT = c.TYPE_RESTAURANT
AND NVL(e.GEO, 'NULL') = NVL(c.GEO, 'NULL')
WHERE e.HAS_CORRIDOR = 1;
Si AVEC_CAPPING faible, problème de jointure → Vérifier les dimensions.
4.3. DECISION_PATH incorrect¶
Symptôme : Arbre de décision ne suit pas la logique attendue.
Diagnostic - Répartition des chemins :
SELECT
DECISION_PATH,
COUNT(*) as NB_OFFRES,
AVG(PCT_HAUSSE_FINALE) * 100 as HAUSSE_MOY_PCT,
MIN(PCT_HAUSSE_FINALE) * 100 as HAUSSE_MIN_PCT,
MAX(PCT_HAUSSE_FINALE) * 100 as HAUSSE_MAX_PCT
FROM PT2QE_RECOMMENDATIONS
GROUP BY DECISION_PATH
ORDER BY NB_OFFRES DESC;
Résultats attendus :
- PAS_BAISSE_GEL_PRIX : Hausses = 0%
- PL1_CONSERVATION_PREMIUM : Hausses faibles (conservation + plancher)
- OPTIMISATION_STANDARD : Hausses variables selon RECO1/RECO2
Diagnostic détaillé CHEMIN 1 :
-- CHEMIN 1 : Vérifier que NEW_PAS < PAS_ACTIF
SELECT
ID_CLN,
ID_ART,
PAS_ACTIF,
NEW_PAS,
PRIX_TARIF_ACTUEL,
PRIX_RECOMMANDE,
PCT_HAUSSE_FINALE * 100 as PCT_HAUSSE,
DECISION_PATH
FROM PT2QE_RECOMMENDATIONS
WHERE DECISION_PATH = 'PAS_BAISSE_GEL_PRIX'
AND (NEW_PAS >= PAS_ACTIF OR PCT_HAUSSE_FINALE != 0)
FETCH FIRST 20 ROWS ONLY;
Si des lignes retournées → BUG dans la logique du CHEMIN 1.
Diagnostic détaillé CHEMIN 2 :
-- CHEMIN 2 : Vérifier que prix était dans PL1 anciennes bornes
SELECT
ID_CLN,
ID_ART,
PRIX_TARIF_ACTUEL,
PRB_ACTIF,
BORNE_PL1_PL2,
POSITION_TARIF_ACTUEL_DANS_ANCIENNES_BORNES,
DECISION_PATH
FROM PT2QE_RECOMMENDATIONS
WHERE DECISION_PATH = 'PL1_CONSERVATION_PREMIUM'
AND POSITION_TARIF_ACTUEL_DANS_ANCIENNES_BORNES != 'PL1'
FETCH FIRST 20 ROWS ONLY;
Si des lignes retournées → BUG dans la détection PL1 anciennes.
4.4. Les 3 positions incorrectes¶
Contexte : PT2QE calcule 3 positions :
1. POSITION_TARIF_ACTUEL_DANS_ANCIENNES_BORNES : Prix actuel vs bornes PT0CE
2. PALIER_TARIF_ACTUEL_VS_NOUVELLES_BORNES : Prix actuel vs bornes PT1CE
3. POSITION_NOUVEAU_PRIX_DANS_NOUVELLES_BORNES : Prix recommandé vs bornes PT1CE
Diagnostic - Vérifier la cohérence :
SELECT
ID_CLN,
ID_ART,
-- Position 1
PRIX_TARIF_ACTUEL,
PAS_ACTIF,
PRB_ACTIF,
BORNE_PL1_PL2,
POSITION_TARIF_ACTUEL_DANS_ANCIENNES_BORNES,
-- Position 2
NEW_PAS,
NEW_PRB,
NEW_BORNE_PL1_PL2,
PALIER_TARIF_ACTUEL_VS_NOUVELLES_BORNES,
-- Position 3
PRIX_RECOMMANDE,
POSITION_NOUVEAU_PRIX_DANS_NOUVELLES_BORNES
FROM PT2QE_RECOMMENDATIONS
WHERE
-- Vérifier incohérence Position 1
(POSITION_TARIF_ACTUEL_DANS_ANCIENNES_BORNES = 'PL1'
AND (PRIX_TARIF_ACTUEL > PRB_ACTIF OR PRIX_TARIF_ACTUEL <= BORNE_PL1_PL2))
OR
-- Vérifier incohérence Position 2
(PALIER_TARIF_ACTUEL_VS_NOUVELLES_BORNES = 'PL1'
AND (PRIX_TARIF_ACTUEL > NEW_PRB OR PRIX_TARIF_ACTUEL <= NEW_BORNE_PL1_PL2))
OR
-- Vérifier incohérence Position 3
(POSITION_NOUVEAU_PRIX_DANS_NOUVELLES_BORNES = 'PL1'
AND (PRIX_RECOMMANDE > NEW_PRB OR PRIX_RECOMMANDE <= NEW_BORNE_PL1_PL2))
FETCH FIRST 50 ROWS ONLY;
Si des lignes retournées → Problème dans le calcul des positions.
Vérification manuelle des bornes :
-- Recalculer manuellement la position pour vérifier
SELECT
r.ID_CLN,
r.ID_ART,
r.PRIX_TARIF_ACTUEL,
r.NEW_PAS,
r.NEW_PRB,
r.NEW_BORNE_PL1_PL2,
r.NEW_BORNE_PL2_PL3,
r.NEW_BORNE_PL3_PL4,
r.NEW_BORNE_PL4_PL5,
r.NEW_BORNE_PL5_PL6,
r.NEW_BORNE_PL6_PLX,
r.PALIER_TARIF_ACTUEL_VS_NOUVELLES_BORNES,
-- Recalcul manuel
CASE
WHEN r.PRIX_TARIF_ACTUEL > r.NEW_PRB THEN 'ABOVE_PRB'
WHEN r.PRIX_TARIF_ACTUEL >= r.NEW_BORNE_PL1_PL2 THEN 'PL1'
WHEN r.PRIX_TARIF_ACTUEL >= r.NEW_BORNE_PL2_PL3 THEN 'PL2'
WHEN r.PRIX_TARIF_ACTUEL >= r.NEW_BORNE_PL3_PL4 THEN 'PL3'
WHEN r.PRIX_TARIF_ACTUEL >= r.NEW_BORNE_PL4_PL5 THEN 'PL4'
WHEN r.PRIX_TARIF_ACTUEL >= r.NEW_BORNE_PL5_PL6 THEN 'PL5'
WHEN r.PRIX_TARIF_ACTUEL >= r.NEW_BORNE_PL6_PLX THEN 'PL6'
WHEN r.PRIX_TARIF_ACTUEL >= r.NEW_PAS THEN 'PLX'
ELSE 'BELOW_PAS'
END as POSITION_RECALCULEE
FROM PT2QE_RECOMMENDATIONS r
WHERE r.PALIER_TARIF_ACTUEL_VS_NOUVELLES_BORNES !=
CASE
WHEN r.PRIX_TARIF_ACTUEL > r.NEW_PRB THEN 'ABOVE_PRB'
WHEN r.PRIX_TARIF_ACTUEL >= r.NEW_BORNE_PL1_PL2 THEN 'PL1'
WHEN r.PRIX_TARIF_ACTUEL >= r.NEW_BORNE_PL2_PL3 THEN 'PL2'
WHEN r.PRIX_TARIF_ACTUEL >= r.NEW_BORNE_PL3_PL4 THEN 'PL3'
WHEN r.PRIX_TARIF_ACTUEL >= r.NEW_BORNE_PL4_PL5 THEN 'PL4'
WHEN r.PRIX_TARIF_ACTUEL >= r.NEW_BORNE_PL5_PL6 THEN 'PL5'
WHEN r.PRIX_TARIF_ACTUEL >= r.NEW_BORNE_PL6_PLX THEN 'PL6'
WHEN r.PRIX_TARIF_ACTUEL >= r.NEW_PAS THEN 'PLX'
ELSE 'BELOW_PAS'
END
FETCH FIRST 20 ROWS ONLY;
5. DIAGNOSTIC ET LOGS¶
5.1. Activer les logs détaillés¶
Via le menu START.bat :
- Lancer
START.bat - Choisir
[6] CHANGER LE NIVEAU DE LOG - Sélectionner
[3] Détaillé (mode debug)
Via ligne de commande :
Options de log :
- -qq : Silencieux (erreurs seulement)
- (aucun) : Normal (INFO, WARNING, ERROR)
- -vv : Détaillé (DEBUG + tout)
5.2. Requêtes de diagnostic globales¶
Vue d'ensemble du run :
CREATE OR REPLACE VIEW V_PT2QE_DIAGNOSTIC AS
SELECT 'Offres extraites' as METRIQUE, COUNT(*) as VALEUR
FROM PT2QE_PRICE_OFFERS
UNION ALL
SELECT 'Clients distincts', COUNT(DISTINCT ID_CLN)
FROM PT2QE_PRICE_OFFERS
UNION ALL
SELECT 'Articles distincts', COUNT(DISTINCT ID_ART)
FROM PT2QE_PRICE_OFFERS
UNION ALL
SELECT 'Offres avec TYPE_CLIENT',
SUM(CASE WHEN TYPE_CLIENT IS NOT NULL
AND TYPE_CLIENT != 'Hors référentiel'
THEN 1 ELSE 0 END)
FROM PT2QE_PRICE_OFFERS
UNION ALL
SELECT 'Offres avec TYPE_RESTAURANT',
SUM(CASE WHEN TYPE_RESTAURANT IS NOT NULL
AND TYPE_RESTAURANT != 'Hors référentiel'
THEN 1 ELSE 0 END)
FROM PT2QE_PRICE_OFFERS
UNION ALL
SELECT 'Offres avec FG_HM',
SUM(CASE WHEN FG_HM IS NOT NULL THEN 1 ELSE 0 END)
FROM PT2QE_PRICE_OFFERS
UNION ALL
SELECT 'Offres enrichies avec corridor',
SUM(HAS_CORRIDOR)
FROM PT2QE_PRICE_OFFERS_ENRICHED
UNION ALL
SELECT 'Recommandations calculées',
COUNT(*)
FROM PT2QE_RECOMMENDATIONS
UNION ALL
SELECT 'Hausse moyenne (%)',
ROUND(AVG(PCT_HAUSSE_FINALE) * 100, 2)
FROM PT2QE_RECOMMENDATIONS;
-- Utilisation
SELECT * FROM V_PT2QE_DIAGNOSTIC;
Statistiques par étape :
-- Étape 1 : Extraction
SELECT
'EXTRACTION' as ETAPE,
COUNT(*) as NB_LIGNES,
COUNT(DISTINCT ID_CLN) as NB_CLIENTS,
COUNT(DISTINCT ID_ART) as NB_ARTICLES,
TO_CHAR(MAX(EXTRACTION_DATE), 'YYYY-MM-DD HH24:MI:SS') as DATE_EXTRACTION
FROM PT2QE_PRICE_OFFERS
UNION ALL
-- Étape 2 : Enrichissement
SELECT
'ENRICHISSEMENT',
COUNT(*),
COUNT(DISTINCT ID_CLN),
COUNT(DISTINCT ID_ART),
NULL
FROM PT2QE_PRICE_OFFERS_ENRICHED
UNION ALL
-- Étape 3 : Recommandations
SELECT
'RECOMMANDATIONS',
COUNT(*),
COUNT(DISTINCT ID_CLN),
COUNT(DISTINCT ID_ART),
TO_CHAR(MAX(CALCULATION_DATE), 'YYYY-MM-DD HH24:MI:SS')
FROM PT2QE_RECOMMENDATIONS;
5.3. Logs à surveiller¶
Extraction réussie :
[INFO] ✓ 2,345,678 offres de prix extraites (ZOOM1 uniquement)
[INFO] Statistiques d'enrichissement:
[INFO] - Total offres: 2,345,678
[INFO] - Clients uniques: 45,678
[INFO] - Articles uniques: 23,456
[INFO] - Avec TYPE_CLIENT: 2,298,765 (98.0%)
[INFO] - Avec TYPE_RESTAURANT: 2,312,456 (98.6%)
[INFO] - Avec FG_HM: 2,156,432 (91.9%)
Matching corridors :
[INFO] → Résultats du matching :
[INFO] - MASTER : 1,876,543 offres, 34,567 clients, 18,765 articles
[INFO] - NATIONAL : 234,567 offres, 5,678 clients, 3,456 articles
[INFO] - NO_MATCH : 234,568 offres, 5,433 clients, 1,235 articles
[INFO] → Total : 2,111,110/2,345,678 offres avec corridor (90.0%)
Calcul recommandations :
[INFO] ✓ 2,111,110 recommandations calculées
[INFO] - 1,876,543 clients
[INFO] - 18,765 articles
[INFO] - Hausse moyenne: 3.7%
Analyse et export :
[INFO] → Export détaillé : 2,111,110 lignes
[INFO] → Statistiques par dimension exportées
[INFO] → Statistiques par path exportées
[INFO] → Statistiques des distributions de capping exportées
[INFO] → Analyse d'impact exportée
[INFO] → Distribution des hausses exportée
5.4. Historique des exécutions¶
Lister les runs précédents :
Comparer deux runs :
-- Comparer hausse moyenne entre deux runs
WITH RUN1 AS (
SELECT AVG(PCT_HAUSSE_FINALE) * 100 as HAUSSE_MOY
FROM PT2QE_RECOMMENDATIONS -- Run actuel
),
RUN2 AS (
SELECT AVG(PCT_HAUSSE_FINALE) * 100 as HAUSSE_MOY
FROM PT2QE_RECOMMENDATIONS_BACKUP -- Run précédent sauvegardé
)
SELECT
r1.HAUSSE_MOY as HAUSSE_RUN_ACTUEL,
r2.HAUSSE_MOY as HAUSSE_RUN_PRECEDENT,
r1.HAUSSE_MOY - r2.HAUSSE_MOY as DIFFERENCE
FROM RUN1 r1, RUN2 r2;
Sauvegarder un run pour comparaison :
-- Avant de relancer
CREATE TABLE PT2QE_RECOMMENDATIONS_BACKUP AS
SELECT * FROM PT2QE_RECOMMENDATIONS;
6. SOLUTIONS DE CONTOURNEMENT¶
6.1. Exclure des offres problématiques¶
Créer une table d'exclusion :
CREATE TABLE PT2QE_EXCLUSIONS (
ID_CLN VARCHAR2(20),
ID_ART VARCHAR2(20),
RAISON VARCHAR2(255),
DATE_AJOUT DATE DEFAULT SYSDATE
);
Ajouter des exclusions :
-- Exclure un client×article spécifique
INSERT INTO PT2QE_EXCLUSIONS (ID_CLN, ID_ART, RAISON)
VALUES ('123456', '789012', 'Prix bloqué manuellement');
-- Exclure tous les articles d'un client
INSERT INTO PT2QE_EXCLUSIONS (ID_CLN, ID_ART, RAISON)
SELECT '123456', ID_ART, 'Client en litiges'
FROM SYS_MD_ARTICLE
WHERE ID_GMM = 'XXX';
COMMIT;
Modifier l'extraction pour tenir compte des exclusions :
Éditer extract_price_offers.py, ajouter dans la clause WHERE finale :
AND NOT EXISTS (
SELECT 1 FROM PT2QE_EXCLUSIONS e
WHERE e.ID_CLN = o.ID_CLN
AND (e.ID_ART = o.ID_ART OR e.ID_ART IS NULL)
)
6.2. Forcer un TYPE_CLIENT par défaut¶
Si trop d'offres sans TYPE_CLIENT :
Éditer extract_price_offers.py, après l'extraction, ajouter :
-- Après création de la table PT2QE_PRICE_OFFERS
UPDATE PT2QE_PRICE_OFFERS
SET TYPE_CLIENT = 'AUTRES',
TYPE_RESTAURANT = 'AUTRES'
WHERE (TYPE_CLIENT IS NULL OR TYPE_CLIENT = 'Hors référentiel')
OR (TYPE_RESTAURANT IS NULL OR TYPE_RESTAURANT = 'Hors référentiel')
AND UNIVERS = 'ZOOM1';
COMMIT;
Note : Nécessite de créer les mappings AUTRES dans PT0CE au préalable.
6.3. Limiter les hausses maximales¶
Post-traitement pour plafonner à X% :
-
Après le calcul des recommandations, exécuter :
-
Régénérer les analyses :
python -c "from analyze_recommendations import RecommendationAnalyzer; from sysco.db.oracle import SysOraDB; from sysco.application import SysApplication; app = SysApplication('PT2QE', '1.0.0', 'Post-processing'); db = SysOraDB('TARIFAIRE'); analyzer = RecommendationAnalyzer(app, db); analyzer.analyze_and_export('PT2QE_RECOMMENDATIONS', Path('outputs/post_processing'))"
6.4. Reprise après échec¶
Identifier l'étape d'échec :
- Vérifier les tables existantes :
Scénarios de reprise :
Scénario 1 : Échec pendant Phase 1 (Extraction) - Tables présentes : Aucune ou PT2QE_PRICE_OFFERS vide - Solution : Relancer normalement (Option 1)
Scénario 2 : Échec après Phase 1
- Tables présentes : PT2QE_PRICE_OFFERS remplie
- Solution : Utiliser --skip-extraction
Scénario 3 : Échec pendant Phase 2
- Tables présentes : PT2QE_PRICE_OFFERS, PT2QE_PRICE_OFFERS_ENRICHED
- Solution : Nettoyer les tables partielles et relancer avec --skip-extraction
-- Nettoyer les tables partielles
DROP TABLE PT2QE_RECOMMENDATIONS PURGE;
DROP TABLE PT2QE_CAPPING_CUBES PURGE;
COMMIT;
Puis :
6.5. Mode test sur volume réduit¶
Pour tester rapidement sans traiter tout le volume :
-
Créer une table de test :
-
Modifier temporairement
calculate_recommendations.pypour utiliser cette table. -
Ou utiliser un fichier de config test avec batch_size réduit.
7. VÉRIFICATIONS AVANT ESCALADE¶
Avant de contacter le support, effectuer ces vérifications :
Checklist complète¶
- [ ] Tables PT1CE : Vérifier que PT1CE_OPTIMAL_* existent et sont remplies (STATUS = 'OPTIMAL')
- [ ] Fichier capping : Vérifier
inputs\capping_type_client.csvexiste et format correct - [ ] Mappings : Vérifier PT0CE_TYPE_CLIENT_MAPPING et PT0CE_TYPE_RESTAURANT_MAPPING
- [ ] Connexion Oracle : Tester avec SQL*Plus ou test_connection.py
- [ ] Espace disque : Vérifier espace disponible sur le serveur
- [ ] Statistiques Oracle : Vérifier que les tables systèmes ont des stats à jour
- [ ] Locks Oracle : Vérifier qu'aucun lock ne bloque les tables
- [ ] Période 4Q : Vérifier que SYS_MD_CALENDRIER_SYSCO est à jour
- [ ] Logs complets : Sauvegarder les logs du run en échec
- [ ] Résultats SQL diagnostic : Exécuter les requêtes de diagnostic et sauvegarder les résultats
Informations à fournir au support¶
- Logs complets du run (copier la sortie console complète)
- Résultat de la requête diagnostic :
- Configuration utilisée :
inputs\capping_type_client.csvconfig\pt2qe_config.json(si modifié)- Période d'exécution (date et heure)
- Tables existantes :
- Message d'erreur exact (si applicable)
- Commande exécutée (ligne de commande ou option menu)
8. ERREURS SPÉCIFIQUES¶
8.1. ORA-01555: snapshot too old¶
Symptôme :
Cause : Transaction trop longue, espace UNDO insuffisant.
Solution :
-
Réduire la taille des transactions : Éditer
config\pt2qe_config.json: -
Réexécuter rapidement : Éviter les interruptions pendant le traitement.
-
Contacter DBA si le problème persiste (augmenter UNDO_RETENTION).
8.2. ORA-01652: unable to extend temp segment¶
Symptôme :
Cause : Espace temporaire Oracle insuffisant.
Diagnostic :
SELECT
tablespace_name,
ROUND(SUM(bytes)/1024/1024/1024, 2) as SIZE_GB,
ROUND(SUM(bytes - NVL(free_bytes, 0))/1024/1024/1024, 2) as USED_GB
FROM (
SELECT tablespace_name, bytes, 0 as free_bytes
FROM dba_temp_files
UNION ALL
SELECT tablespace_name, 0, bytes
FROM dba_free_space
WHERE tablespace_name LIKE 'TEMP%'
)
GROUP BY tablespace_name;
Solution :
- Réduire le volume traité (voir section 6.5)
- Contacter DBA pour étendre le tablespace TEMP
- Nettoyer les objets temporaires :
8.3. Timeout Python/Oracle¶
Symptôme : Programme s'arrête sans message d'erreur après longue attente.
Diagnostic : Vérifier les sessions Oracle actives :
SELECT
s.sid,
s.serial#,
s.username,
s.status,
s.last_call_et / 60 as MINUTES_INACTIVES
FROM v$session s
WHERE s.username = USER
ORDER BY s.last_call_et DESC;
Solution :
- Augmenter le timeout Python (si configurable)
- Vérifier le réseau entre client et serveur Oracle
- Relancer en mode verbose pour voir la progression
8.4. Fichiers de sortie corrompus ou vides¶
Symptôme : Fichiers CSV générés sont vides ou illisibles.
Diagnostic :
Causes possibles :
- Encodage incorrect : Vérifier que
encoding='cp1252'est utilisé - Permissions : Vérifier les droits d'écriture sur le dossier outputs
- Espace disque plein : Vérifier l'espace disponible
Solution - Régénérer les exports :
Si les tables Oracle sont OK :
# Relancer uniquement les exports
python -c "
from analyze_recommendations import RecommendationAnalyzer
from sysco.db.oracle import SysOraDB
from sysco.application import SysApplication
from pathlib import Path
app = SysApplication('PT2QE_REEXPORT', '1.0.0', 'Reexport')
db = SysOraDB('TARIFAIRE')
analyzer = RecommendationAnalyzer(app, db)
analyzer.analyze_and_export('PT2QE_RECOMMENDATIONS', Path('outputs/reexport'))
"
9. PROBLÈMES DE CONFIGURATION¶
9.1. Modification des règles RECO1¶
Fichier à éditer : config\pt2qe_config.json
Structure actuelle :
{
"recommendations": {
"reco1_rules": [
{
"position": "ABOVE_PL1",
"condition": "PRIX_TARIF_ACTUEL > NEW_BORNE_PL1_PL2",
"action": "NO_CHANGE",
"target": "PRIX_TARIF_ACTUEL",
"comment": "Prix déjà en PL1, pas de changement"
},
{
"position": "PL1_PL2",
"condition": "PRIX_TARIF_ACTUEL > NEW_BORNE_PL2_PL3",
"action": "TO_PL1",
"target": "NEW_BORNE_PL1_PL2",
"comment": "Remonter vers PL1"
}
]
}
}
Modifier une règle existante :
Exemple : Changer PL1_PL2 pour aller vers PL2 au lieu de PL1 :
{
"position": "PL1_PL2",
"condition": "PRIX_TARIF_ACTUEL > NEW_BORNE_PL2_PL3",
"action": "TO_PL2",
"target": "NEW_BORNE_PL2_PL3",
"comment": "Remonter vers PL2 (modifié)"
}
Ajouter une règle :
{
"position": "CUSTOM_RULE",
"condition": "PRIX_TARIF_ACTUEL > NEW_BORNE_PL5_PL6 AND PRIX_TARIF_ACTUEL <= NEW_BORNE_PL4_PL5",
"action": "TO_PL4",
"target": "NEW_BORNE_PL4_PL5",
"comment": "Règle personnalisée"
}
Ordre des règles : Les règles sont évaluées dans l'ordre du fichier. La première condition vraie est appliquée.
Validation après modification :
- Sauvegarder le fichier
- Relancer un calcul complet (Option 1)
- Vérifier la colonne
RECO1_BASEdans les résultats
9.2. Modifier les cappings par défaut¶
Fichier à éditer : config\pt2qe_config.json
{
"capping": {
"default_high": 0.05,
"default_medium": 0.15,
"default_low": 0.20,
"basiques": 0.50,
"allow_overrides": true
}
}
Valeurs recommandées :
- default_high : 0.02 à 0.10 (produits sensibles)
- default_medium : 0.05 à 0.20 (produits standards)
- default_low : 0.10 à 0.30 (produits peu sensibles)
- basiques : 0.30 à 0.70 (capping spécifique produits basiques)
Note : Ces valeurs par défaut sont utilisées si le fichier capping_type_client.csv ne contient pas de valeur pour un TYPE_CLIENT.
9.3. Problèmes avec le calendrier fiscal (PeriodManager)¶
Symptôme :
Diagnostic :
-- Vérifier la semaine en cours
SELECT
ID_SEM,
LC_EXF_SEF,
ID_EXF,
NO_TRF,
FG_SEM_EN_COURS
FROM SYS_MD_CALENDRIER_SYSCO
WHERE FG_SEM_EN_COURS = 'X';
Si aucune ligne :
La table SYS_MD_CALENDRIER_SYSCO n'est pas à jour → Contacter l'équipe Data.
Vérifier les trimestres disponibles :
SELECT
ID_EXF || '_Q' || NO_TRF as QUARTER,
MIN(ID_SEM) as START_DATE,
MAX(ID_SEM) as END_DATE,
COUNT(DISTINCT ID_SEM) as NB_SEMAINES
FROM SYS_MD_CALENDRIER_SYSCO
WHERE ID_EXF >= '2023'
GROUP BY ID_EXF, NO_TRF
ORDER BY ID_EXF DESC, NO_TRF DESC;
Solution temporaire :
Si la table est incomplète, modifier manuellement les dates dans pt2qe_main.py :
# Forcer des dates spécifiques (TEMPORAIRE)
app.start_date = date(2024, 1, 1)
app.end_date = date(2024, 12, 31)
app.fiscal_quarters = ['2024_Q01', '2024_Q02', '2024_Q03', '2024_Q04']
Puis commenter l'appel à period_manager.get_last_four_complete_fiscal_quarters().
10. MAINTENANCE ET NETTOYAGE¶
10.1. Purger les anciennes tables¶
Lister les tables PT2QE :
SELECT
table_name,
num_rows,
TO_CHAR(last_analyzed, 'YYYY-MM-DD') as last_analyzed,
ROUND(bytes/1024/1024, 2) as SIZE_MB
FROM user_tables t
LEFT JOIN user_segments s ON t.table_name = s.segment_name
WHERE table_name LIKE 'PT2QE_%'
ORDER BY last_analyzed DESC NULLS LAST;
Supprimer les tables obsolètes :
-- ATTENTION : Vérifier avant de supprimer
DROP TABLE PT2QE_PRICE_OFFERS_20240101 PURGE;
DROP TABLE PT2QE_RECOMMENDATIONS_20240101 PURGE;
Script de purge automatique (à exécuter manuellement) :
-- Supprimer les tables PT2QE de plus de 30 jours
DECLARE
v_sql VARCHAR2(4000);
BEGIN
FOR t IN (
SELECT table_name
FROM user_tables
WHERE table_name LIKE 'PT2QE_%'
AND last_analyzed < SYSDATE - 30
) LOOP
v_sql := 'DROP TABLE ' || t.table_name || ' PURGE';
EXECUTE IMMEDIATE v_sql;
DBMS_OUTPUT.PUT_LINE('Supprimé : ' || t.table_name);
END LOOP;
END;
/
10.2. Archiver les résultats¶
Sauvegarder un run important :
REM Créer un dossier d'archive
mkdir archives\run_YYYYMMDD_description
REM Copier les fichiers CSV
xcopy outputs\run_YYYYMMDD_HHMMSS\*.csv archives\run_YYYYMMDD_description\ /Y
REM Copier la config utilisée
copy config\pt2qe_config.json archives\run_YYYYMMDD_description\
copy inputs\capping_type_client.csv archives\run_YYYYMMDD_description\
Sauvegarder les tables Oracle :
-- Créer des copies permanentes
CREATE TABLE PT2QE_RECOMMENDATIONS_ARCHIVE_YYYYMMDD AS
SELECT * FROM PT2QE_RECOMMENDATIONS;
CREATE TABLE PT2QE_PRICE_OFFERS_ARCHIVE_YYYYMMDD AS
SELECT * FROM PT2QE_PRICE_OFFERS;
10.3. Nettoyer les fichiers temporaires¶
Supprimer les dossiers de run :
REM Supprimer tous les runs sauf le dernier
for /d %%d in (outputs\run_*) do (
echo Supprimer %%d ? (Ctrl+C pour annuler)
pause
rmdir /s /q "%%d"
)
Nettoyer le dossier corrections :
11. CONTACT SUPPORT¶
Si aucune solution de ce document ne résout votre problème :
- Rassembler les informations (voir section 7)
- Créer un dossier incident avec :
- Description détaillée du problème
- Logs complets
- Résultats des requêtes de diagnostic
- Configuration utilisée
- Contacter le support technique Pricing
Informations à ne PAS oublier : - Date et heure du run - Version de PT2QE (affichée au démarrage) - Environnement (TARIFAIRE, test, etc.) - Modifications apportées à la configuration standard