pierreguillou commited on
Commit
cf0f5ef
·
verified ·
1 Parent(s): c1c25ed

Create rapport_generator.py

Browse files
Files changed (1) hide show
  1. helpers/rapport_generator.py +390 -0
helpers/rapport_generator.py ADDED
@@ -0,0 +1,390 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## class to generate the DOCX report
2
+ import json
3
+
4
+ from docx import Document
5
+ from docx.shared import Pt, RGBColor, Inches
6
+ from docx.enum.text import WD_ALIGN_PARAGRAPH
7
+ from docx.enum.section import WD_SECTION
8
+ from docx.oxml import OxmlElement
9
+ from docx.oxml.ns import qn
10
+ from typing import Dict, Any, List, Union # Ajout des imports typing nécessaires
11
+ import logging
12
+
13
+ class RapportGenerator:
14
+ def __init__(self, json_file: str):
15
+ self.doc = Document()
16
+ self.logger = logging.getLogger(__name__)
17
+ logging.basicConfig(level=logging.INFO)
18
+ self.json_data = self.load_json(json_file)
19
+ self._setup_document()
20
+
21
+ def load_json(self, json_file: str) -> Dict:
22
+ """Charge le fichier JSON"""
23
+ try:
24
+ with open(json_file, 'r', encoding='utf-8') as f:
25
+ return json.load(f)
26
+ except Exception as e:
27
+ self.logger.error(f"Erreur lors de la lecture du JSON: {str(e)}")
28
+ raise
29
+
30
+ def _setup_document(self):
31
+ """Configure le document"""
32
+ sections = self.doc.sections
33
+ for section in sections:
34
+ section.bottom_margin = Inches(1)
35
+ self._create_page_number()
36
+
37
+ def _create_page_number(self):
38
+ """Crée le numéro de page dans le pied de page"""
39
+ section = self.doc.sections[0]
40
+ footer = section.footer
41
+ paragraph = footer.paragraphs[0]
42
+ paragraph.alignment = WD_ALIGN_PARAGRAPH.RIGHT
43
+
44
+ run = paragraph.add_run()
45
+ self._create_element(run, 'PAGE')
46
+ run = paragraph.add_run(" / ")
47
+ run = paragraph.add_run()
48
+ self._create_element(run, 'NUMPAGES')
49
+
50
+ def _create_element(self, run, text):
51
+ """Crée un élément de champ Word"""
52
+ fldChar1 = OxmlElement('w:fldChar')
53
+ fldChar1.set(qn('w:fldCharType'), 'begin')
54
+ run._r.append(fldChar1)
55
+
56
+ instrText = OxmlElement('w:instrText')
57
+ instrText.text = text
58
+ run._r.append(instrText)
59
+
60
+ fldChar2 = OxmlElement('w:fldChar')
61
+ fldChar2.set(qn('w:fldCharType'), 'end')
62
+ run._r.append(fldChar2)
63
+
64
+ def _add_title(self, text: str, level: int = 1):
65
+ """Ajoute un titre avec style et taille appropriés"""
66
+ heading = self.doc.add_heading(level=level)
67
+ heading.alignment = WD_ALIGN_PARAGRAPH.LEFT
68
+ run = heading.add_run(text.strip()) # Ajout de strip()
69
+ font_sizes = {0: 18, 1: 16, 2: 14, 3: 12}
70
+ run.font.size = Pt(font_sizes.get(level, 12))
71
+
72
+ def _format_key(self, key: str) -> str:
73
+ """Formate la clé en supprimant les suffixes _DEMANDEUR et _DEFENDEUR"""
74
+ key = key.replace("_", " ").title()
75
+ key = key.replace(" Demandeur", "")
76
+ key = key.replace(" Defendeur", "")
77
+ return key
78
+
79
+ def _get_safe_value(self, data: Dict, key: str, default: str = '') -> str:
80
+ """Récupère une valeur en toute sécurité du dictionnaire"""
81
+ if isinstance(data, dict):
82
+ return str(data.get(key, default))
83
+ return default
84
+
85
+ def _format_person_info(self, data: Dict, is_lawyer: bool = False) -> Dict[str, str]:
86
+ """Formate les informations d'une personne"""
87
+ info = {}
88
+
89
+ if not isinstance(data, dict):
90
+ return info
91
+
92
+ if is_lawyer:
93
+ # Informations de l'avocat
94
+ civilite = self._get_safe_value(data, 'CIVILITE_AVOCAT_DEMANDEUR') or self._get_safe_value(data, 'CIVILITE_AVOCAT_DEFENDEUR')
95
+ prenom = self._get_safe_value(data, 'PRENOM_AVOCAT_DEMANDEUR') or self._get_safe_value(data, 'PRENOM_AVOCAT_DEFENDEUR')
96
+ nom = self._get_safe_value(data, 'NOM_AVOCAT_DEMANDEUR') or self._get_safe_value(data, 'NOM_AVOCAT_DEFENDEUR')
97
+
98
+ info['Nom'] = f"{civilite} {prenom} {nom}".strip()
99
+ info['Barreau'] = self._get_safe_value(data, 'BARREAU_AVOCAT_DEMANDEUR') or self._get_safe_value(data, 'BARREAU_AVOCAT_DEFENDEUR')
100
+ info['Bureau d\'avocats'] = self._get_safe_value(data, 'BUREAU_AVOCAT_DEMANDEUR') or self._get_safe_value(data, 'BUREAU_AVOCAT_DEFENDEUR')
101
+
102
+ adresse = data.get('ADRESSE_AVOCAT_DEMANDEUR', {}) if isinstance(data.get('ADRESSE_AVOCAT_DEMANDEUR'), dict) else {}
103
+ if not adresse:
104
+ adresse = data.get('ADRESSE_AVOCAT_DEFENDEUR', {}) if isinstance(data.get('ADRESSE_AVOCAT_DEFENDEUR'), dict) else {}
105
+
106
+ info['Adresse Complete'] = self._get_safe_value(adresse, 'ADRESSE_COMPLETE_AVOCAT_DEMANDEUR') or self._get_safe_value(adresse, 'ADRESSE_COMPLETE_AVOCAT_DEFENDEUR')
107
+ info['Email'] = self._get_safe_value(data, 'EMAIL_AVOCAT_DEMANDEUR') or self._get_safe_value(data, 'EMAIL_AVOCAT_DEFENDEUR')
108
+ info['Telephone'] = self._get_safe_value(data, 'TELEPHONE_AVOCAT_DEMANDEUR') or self._get_safe_value(data, 'TELEPHONE_AVOCAT_DEFENDEUR')
109
+ else:
110
+ # Informations de la partie
111
+ civilite = self._get_safe_value(data, 'CIVILITE_DEMANDEUR') or self._get_safe_value(data, 'CIVILITE_DEFENDEUR')
112
+ prenom = self._get_safe_value(data, 'PRENOM_DEMANDEUR') or self._get_safe_value(data, 'PRENOM_DEFENDEUR')
113
+ nom = self._get_safe_value(data, 'NOM_DEMANDEUR') or self._get_safe_value(data, 'NOM_DEFENDEUR')
114
+
115
+ info['Nom'] = f"{civilite} {prenom} {nom}".strip()
116
+ info['Organisme'] = self._get_safe_value(data, 'ORGANISME_DEMANDEUR') or self._get_safe_value(data, 'ORGANISME_DEFENDEUR')
117
+
118
+ adresse = data.get('ADRESSE_DEMANDEUR', {}) if isinstance(data.get('ADRESSE_DEMANDEUR'), dict) else {}
119
+ if not adresse:
120
+ adresse = data.get('ADRESSE_DEFENDEUR', {}) if isinstance(data.get('ADRESSE_DEFENDEUR'), dict) else {}
121
+
122
+ info['Adresse Complete'] = self._get_safe_value(adresse, 'ADRESSE_COMPLETE_DEMANDEUR') or self._get_safe_value(adresse, 'ADRESSE_COMPLETE_DEFENDEUR')
123
+ info['Email'] = self._get_safe_value(data, 'EMAIL_DEMANDEUR') or self._get_safe_value(data, 'EMAIL_DEFENDEUR')
124
+ info['Telephone'] = self._get_safe_value(data, 'TELEPHONE_DEMANDEUR') or self._get_safe_value(data, 'TELEPHONE_DEFENDEUR')
125
+
126
+ return {k: v for k, v in info.items() if v and v != "Non spécifié"}
127
+
128
+ def _process_special_fields(self, key: str, value: Any) -> bool:
129
+ """Traite les champs spéciaux (HISTORIQUE et MISSION)"""
130
+ if key in ["HISTORIQUE", "MISSION"]:
131
+ self._add_title(key.upper().strip(), 1)
132
+
133
+ # Vérifier si la valeur est une liste
134
+ if isinstance(value, list):
135
+ for item in value:
136
+ p = self.doc.add_paragraph()
137
+ p.add_run(str(item).strip())
138
+ else:
139
+ # Si c'est une chaîne simple ou autre type
140
+ p = self.doc.add_paragraph()
141
+ p.add_run(str(value).strip())
142
+
143
+ # Ajouter un espace après HISTORIQUE seulement
144
+ if key == "HISTORIQUE":
145
+ self.doc.add_paragraph()
146
+
147
+ return True
148
+ return False
149
+
150
+ def _process_parties(self, title: str, items: Union[str, List], level: int):
151
+ """Traite les parties (demandeurs/défendeurs)"""
152
+ self._add_title(title, level)
153
+
154
+ # Si aucune partie n'est spécifiée
155
+ if isinstance(items, str) and items == "Non spécifié":
156
+ p = self.doc.add_paragraph(style='List Bullet')
157
+ p.add_run("Non spécifié")
158
+ return
159
+
160
+ # Traitement de chaque partie
161
+ if isinstance(items, list):
162
+ for idx, item in enumerate(items, 1):
163
+ if not isinstance(item, dict):
164
+ continue
165
+
166
+ # Sous-titre pour chaque partie
167
+ partie_title = f"{title.rstrip('S')} {idx}"
168
+ self._add_title(partie_title, level + 1)
169
+
170
+ # Formatage du nom complet
171
+ civilite = self._get_safe_value(item, f'CIVILITE_{title.rstrip("S")}', '')
172
+ prenom = self._get_safe_value(item, f'PRENOM_{title.rstrip("S")}', '')
173
+ nom = self._get_safe_value(item, f'NOM_{title.rstrip("S")}', '')
174
+ nom_complet = f"{civilite} {prenom} {nom}".strip()
175
+
176
+ # Ajout du nom
177
+ if nom_complet and nom_complet != "Non spécifié":
178
+ p = self.doc.add_paragraph(style='List Bullet')
179
+ p.add_run("Nom: ").bold = True
180
+ p.add_run(nom_complet)
181
+
182
+ # Récupération de l'adresse
183
+ adresse = item.get(f'ADRESSE_{title.rstrip("S")}', {})
184
+ if isinstance(adresse, dict):
185
+ adresse_complete = adresse.get(f'ADRESSE_COMPLETE_{title.rstrip("S")}', '')
186
+ if adresse_complete and adresse_complete != "Non spécifié":
187
+ p = self.doc.add_paragraph(style='List Bullet')
188
+ p.add_run("Adresse Complete: ").bold = True
189
+ p.add_run(adresse_complete)
190
+
191
+ # Ajout du téléphone
192
+ telephone = self._get_safe_value(item, f'TELEPHONE_{title.rstrip("S")}', '')
193
+ if telephone and telephone != "Non spécifié":
194
+ p = self.doc.add_paragraph(style='List Bullet')
195
+ p.add_run("Téléphone: ").bold = True
196
+ p.add_run(telephone)
197
+
198
+ # Ajout de l'email
199
+ email = self._get_safe_value(item, f'EMAIL_{title.rstrip("S")}', '')
200
+ if email and email != "Non spécifié":
201
+ p = self.doc.add_paragraph(style='List Bullet')
202
+ p.add_run("Email: ").bold = True
203
+ p.add_run(email)
204
+
205
+ # Traitement des avocats
206
+ avocat_key = f'AVOCAT_{title.rstrip("S")}'
207
+ avocats = item.get(avocat_key, [])
208
+
209
+ if isinstance(avocats, list) and avocats and avocats != "Non spécifié":
210
+ for avocat_idx, avocat in enumerate(avocats, 1):
211
+ if isinstance(avocat, dict):
212
+ # Sous-titre pour chaque avocat
213
+ self._add_title(f"Avocat {avocat_idx}", level + 2)
214
+
215
+ # Nom de l'avocat
216
+ civilite_avocat = self._get_safe_value(avocat, f'CIVILITE_AVOCAT_{title.rstrip("S")}', '')
217
+ prenom_avocat = self._get_safe_value(avocat, f'PRENOM_AVOCAT_{title.rstrip("S")}', '')
218
+ nom_avocat = self._get_safe_value(avocat, f'NOM_AVOCAT_{title.rstrip("S")}', '')
219
+ nom_complet_avocat = f"{civilite_avocat} {prenom_avocat} {nom_avocat}".strip()
220
+
221
+ if nom_complet_avocat and nom_complet_avocat != "Non spécifié":
222
+ p = self.doc.add_paragraph(style='List Bullet')
223
+ p.add_run("Nom: ").bold = True
224
+ p.add_run(nom_complet_avocat)
225
+
226
+ # Barreau
227
+ barreau = self._get_safe_value(avocat, f'BARREAU_AVOCAT_{title.rstrip("S")}', '')
228
+ if barreau and barreau != "Non spécifié":
229
+ p = self.doc.add_paragraph(style='List Bullet')
230
+ p.add_run("Barreau: ").bold = True
231
+ p.add_run(barreau)
232
+
233
+ # Bureau d'avocats
234
+ bureau = self._get_safe_value(avocat, f'BUREAU_AVOCAT_{title.rstrip("S")}', '')
235
+ if bureau and bureau != "Non spécifié":
236
+ p = self.doc.add_paragraph(style='List Bullet')
237
+ p.add_run("Bureau d'avocats: ").bold = True
238
+ p.add_run(bureau)
239
+
240
+ # Adresse de l'avocat
241
+ adresse_avocat = avocat.get(f'ADRESSE_AVOCAT_{title.rstrip("S")}', {})
242
+ if isinstance(adresse_avocat, dict):
243
+ adresse_complete_avocat = adresse_avocat.get(f'ADRESSE_COMPLETE_AVOCAT_{title.rstrip("S")}', '')
244
+ if adresse_complete_avocat and adresse_complete_avocat != "Non spécifié":
245
+ p = self.doc.add_paragraph(style='List Bullet')
246
+ p.add_run("Adresse Complete: ").bold = True
247
+ p.add_run(adresse_complete_avocat)
248
+
249
+ # Téléphone de l'avocat
250
+ tel_avocat = self._get_safe_value(avocat, f'TELEPHONE_AVOCAT_{title.rstrip("S")}', '')
251
+ if tel_avocat and tel_avocat != "Non spécifié":
252
+ p = self.doc.add_paragraph(style='List Bullet')
253
+ p.add_run("Téléphone: ").bold = True
254
+ p.add_run(tel_avocat)
255
+
256
+ # Email de l'avocat
257
+ email_avocat = self._get_safe_value(avocat, f'EMAIL_AVOCAT_{title.rstrip("S")}', '')
258
+ if email_avocat and email_avocat != "Non spécifié":
259
+ p = self.doc.add_paragraph(style='List Bullet')
260
+ p.add_run("Email: ").bold = True
261
+ p.add_run(email_avocat)
262
+
263
+ # Ajouter un espace entre chaque partie
264
+ if idx < len(items):
265
+ self.doc.add_paragraph()
266
+
267
+ def _add_table_of_contents(self):
268
+ """Ajoute une table des matières au document"""
269
+ paragraph = self.doc.add_paragraph()
270
+ run = paragraph.add_run("TABLE DES MATIÈRES")
271
+ run.bold = True
272
+ run.font.size = Pt(14)
273
+
274
+ self.doc.add_paragraph()
275
+ paragraph = self.doc.add_paragraph()
276
+
277
+ # Ajouter le champ TOC
278
+ run = paragraph.add_run()
279
+ fldChar1 = OxmlElement('w:fldChar')
280
+ fldChar1.set(qn('w:fldCharType'), 'begin')
281
+ run._r.append(fldChar1)
282
+
283
+ instrText = OxmlElement('w:instrText')
284
+ instrText.set(qn('xml:space'), 'preserve')
285
+ instrText.text = 'TOC \\o "1-3" \\h \\z \\u'
286
+ run._r.append(instrText)
287
+
288
+ fldChar2 = OxmlElement('w:fldChar')
289
+ fldChar2.set(qn('w:fldCharType'), 'separate')
290
+ run._r.append(fldChar2)
291
+
292
+ # Ajouter un espace pour la mise à jour
293
+ run = paragraph.add_run()
294
+
295
+ fldChar4 = OxmlElement('w:fldChar')
296
+ fldChar4.set(qn('w:fldCharType'), 'end')
297
+ run._r.append(fldChar4)
298
+
299
+ self.doc.add_page_break()
300
+
301
+ def _format_person_info_simple(self, data: Dict, prefix: str) -> str:
302
+ """Formate les informations d'une personne (magistrat ou greffier)"""
303
+ prenom = data.get(f'PRENOM_{prefix}', '').strip()
304
+ nom = data.get(f'NOM_{prefix}', '').strip()
305
+ titre = data.get(f'TITRE_{prefix}', '').strip()
306
+ return f"{prenom} {nom}, {titre}".strip()
307
+
308
+ def _format_monetary_value(self, data: Dict, prefix: str) -> str:
309
+ """Formate les valeurs monétaires"""
310
+ valeur = str(data.get(f'VALEUR_{prefix}', 0)).strip()
311
+ monnaie = data.get(f'MONNAIE_{prefix}', '€').strip()
312
+ return f"{valeur} {monnaie}".strip()
313
+
314
+ def generate_report(self):
315
+ """Génère le rapport complet"""
316
+ try:
317
+ # Titre principal
318
+ title = self.doc.add_heading("Données extraites d'une ordonnance de référé", 0)
319
+ title.alignment = WD_ALIGN_PARAGRAPH.CENTER
320
+
321
+ # Informations générales
322
+ self._add_title("INFORMATIONS GÉNÉRALES", 1)
323
+ if isinstance(self.json_data.get("INFORMATIONS_GENERALES"), dict):
324
+ info_gen = self.json_data["INFORMATIONS_GENERALES"]
325
+
326
+ # Liste des champs à traiter
327
+ fields_to_process = [
328
+ # Champs simples
329
+ ("DATE_ORDONNANCE_REFERE", "Date Ordonnance Refere"),
330
+ ("VILLE_TRIBUNAL", "Ville Tribunal"),
331
+ ("NUMERO_RG", "Numero RG"),
332
+
333
+ # Champs complexes avec formatage spécial
334
+ ("MAGISTRAT_ORDONNANCE_REFERE", "Magistrat Ordonnance Refere",
335
+ lambda x: self._format_person_info_simple(x, "MAGISTRAT_ORDONNANCE_REFERE")),
336
+
337
+ ("GREFFIER_ORDONNANCE_REFERE", "Greffier Ordonnance Refere",
338
+ lambda x: self._format_person_info_simple(x, "GREFFIER_ORDONNANCE_REFERE")),
339
+
340
+ ("CONSIGNATION", "Consignation",
341
+ lambda x: self._format_monetary_value(x, "CONSIGNATION")),
342
+
343
+ ("SOMME_A_CONSIGER", "Somme A Consiger",
344
+ lambda x: self._format_monetary_value(x, "SOMME_A_CONSIGER"))
345
+ ]
346
+
347
+ # Traitement de chaque champ
348
+ for field in fields_to_process:
349
+ key = field[0]
350
+ display_name = field[1]
351
+
352
+ if key in info_gen:
353
+ p = self.doc.add_paragraph(style='List Bullet')
354
+ p.add_run(f"{display_name}: ").bold = True
355
+
356
+ # Si c'est un champ avec formatage spécial (longueur du tuple = 3)
357
+ if len(field) == 3:
358
+ formatter = field[2]
359
+ value = formatter(info_gen[key])
360
+ else:
361
+ value = str(info_gen[key])
362
+
363
+ p.add_run(value)
364
+
365
+ # Traitement des demandeurs
366
+ if "DEMANDEURS" in self.json_data:
367
+ self._process_parties("DEMANDEURS", self.json_data["DEMANDEURS"], 1)
368
+
369
+ # Traitement des défendeurs
370
+ if "DEFENDEURS" in self.json_data:
371
+ self._process_parties("DEFENDEURS", self.json_data["DEFENDEURS"], 1)
372
+
373
+ # Historique
374
+ if "HISTORIQUE" in self.json_data:
375
+ self._process_special_fields("HISTORIQUE", self.json_data["HISTORIQUE"])
376
+
377
+ # Mission
378
+ if "MISSION" in self.json_data:
379
+ self._process_special_fields("MISSION", self.json_data["MISSION"])
380
+
381
+ # Sauvegarde du document
382
+ output_file = "rapport_extraction.docx"
383
+ self.doc.save(output_file)
384
+ self.logger.info(f"Rapport généré avec succès: {output_file}")
385
+
386
+ return output_file
387
+
388
+ except Exception as e:
389
+ self.logger.error(f"Erreur lors de la génération du rapport: {str(e)}")
390
+ raise