File size: 18,889 Bytes
cf0f5ef
 
 
 
 
 
 
 
 
 
 
 
 
4483a9e
cf0f5ef
 
 
 
4483a9e
cf0f5ef
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
786dbf7
 
2927efc
 
786dbf7
 
 
 
 
 
2927efc
 
 
 
cf0f5ef
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2927efc
ba9cdf6
2927efc
 
cf0f5ef
 
2927efc
cf0f5ef
 
2927efc
cf0f5ef
 
 
 
 
2927efc
 
cf0f5ef
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4483a9e
 
cf0f5ef
7551ec0
cf0f5ef
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
## class to generate the DOCX report
import json

from docx import Document
from docx.shared import Pt, RGBColor, Inches
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.section import WD_SECTION
from docx.oxml import OxmlElement
from docx.oxml.ns import qn
from typing import Dict, Any, List, Union  # Ajout des imports typing nécessaires
import logging

class RapportGenerator:
    def __init__(self, json_file: str, docx_path: str):
        self.doc = Document()
        self.logger = logging.getLogger(__name__)
        logging.basicConfig(level=logging.INFO)
        self.json_data = self.load_json(json_file)
        self.docx_path = docx_path
        self._setup_document()

    def load_json(self, json_file: str) -> Dict:
        """Charge le fichier JSON"""
        try:
            with open(json_file, 'r', encoding='utf-8') as f:
                return json.load(f)
        except Exception as e:
            self.logger.error(f"Erreur lors de la lecture du JSON: {str(e)}")
            raise

    def _setup_document(self):
        """Configure le document"""
        sections = self.doc.sections
        for section in sections:
            section.bottom_margin = Inches(1)
        self._create_page_number()

    def _create_page_number(self):
        """Crée le numéro de page dans le pied de page"""
        section = self.doc.sections[0]
        footer = section.footer
        paragraph = footer.paragraphs[0]
        paragraph.alignment = WD_ALIGN_PARAGRAPH.RIGHT

        run = paragraph.add_run()
        self._create_element(run, 'PAGE')
        run = paragraph.add_run(" / ")
        run = paragraph.add_run()
        self._create_element(run, 'NUMPAGES')

    def _create_element(self, run, text):
        """Crée un élément de champ Word"""
        fldChar1 = OxmlElement('w:fldChar')
        fldChar1.set(qn('w:fldCharType'), 'begin')
        run._r.append(fldChar1)

        instrText = OxmlElement('w:instrText')
        instrText.text = text
        run._r.append(instrText)

        fldChar2 = OxmlElement('w:fldChar')
        fldChar2.set(qn('w:fldCharType'), 'end')
        run._r.append(fldChar2)

    def _add_title(self, text: str, level: int = 1):
        """Ajoute un titre avec style et taille appropriés"""
        heading = self.doc.add_heading(level=level)
        heading.alignment = WD_ALIGN_PARAGRAPH.LEFT
        run = heading.add_run(text.strip())  # Ajout de strip()
        font_sizes = {0: 18, 1: 16, 2: 14, 3: 12}
        run.font.size = Pt(font_sizes.get(level, 12))

    def _format_key(self, key: str) -> str:
        """Formate la clé en supprimant les suffixes _DEMANDEUR et _DEFENDEUR"""
        key = key.replace("_", " ").title()
        key = key.replace(" Demandeur", "")
        key = key.replace(" Defendeur", "")
        return key

    def _get_safe_value(self, data: Dict, key: str, default: str = '') -> str:
        """Récupère une valeur en toute sécurité du dictionnaire"""
        if isinstance(data, dict):
            return str(data.get(key, default))
        return default

    def _format_person_info(self, data: Dict, is_lawyer: bool = False) -> Dict[str, str]:
        """Formate les informations d'une personne"""
        info = {}

        if not isinstance(data, dict):
            return info

        if is_lawyer:
            # Informations de l'avocat
            civilite = self._get_safe_value(data, 'CIVILITE_AVOCAT_DEMANDEUR') or self._get_safe_value(data, 'CIVILITE_AVOCAT_DEFENDEUR')
            prenom = self._get_safe_value(data, 'PRENOM_AVOCAT_DEMANDEUR') or self._get_safe_value(data, 'PRENOM_AVOCAT_DEFENDEUR')
            nom = self._get_safe_value(data, 'NOM_AVOCAT_DEMANDEUR') or self._get_safe_value(data, 'NOM_AVOCAT_DEFENDEUR')

            info['Nom'] = f"{civilite} {prenom} {nom}".strip()
            info['Barreau'] = self._get_safe_value(data, 'BARREAU_AVOCAT_DEMANDEUR') or self._get_safe_value(data, 'BARREAU_AVOCAT_DEFENDEUR')
            info['Bureau d\'avocats'] = self._get_safe_value(data, 'BUREAU_AVOCAT_DEMANDEUR') or self._get_safe_value(data, 'BUREAU_AVOCAT_DEFENDEUR')

            adresse = data.get('ADRESSE_AVOCAT_DEMANDEUR', {}) if isinstance(data.get('ADRESSE_AVOCAT_DEMANDEUR'), dict) else {}
            if not adresse:
                adresse = data.get('ADRESSE_AVOCAT_DEFENDEUR', {}) if isinstance(data.get('ADRESSE_AVOCAT_DEFENDEUR'), dict) else {}

            info['Adresse Complete'] = self._get_safe_value(adresse, 'ADRESSE_COMPLETE_AVOCAT_DEMANDEUR') or self._get_safe_value(adresse, 'ADRESSE_COMPLETE_AVOCAT_DEFENDEUR')
            info['Email'] = self._get_safe_value(data, 'EMAIL_AVOCAT_DEMANDEUR') or self._get_safe_value(data, 'EMAIL_AVOCAT_DEFENDEUR')
            info['Telephone'] = self._get_safe_value(data, 'TELEPHONE_AVOCAT_DEMANDEUR') or self._get_safe_value(data, 'TELEPHONE_AVOCAT_DEFENDEUR')
        else:
            # Informations de la partie
            civilite = self._get_safe_value(data, 'CIVILITE_DEMANDEUR') or self._get_safe_value(data, 'CIVILITE_DEFENDEUR')
            prenom = self._get_safe_value(data, 'PRENOM_DEMANDEUR') or self._get_safe_value(data, 'PRENOM_DEFENDEUR')
            nom = self._get_safe_value(data, 'NOM_DEMANDEUR') or self._get_safe_value(data, 'NOM_DEFENDEUR')

            info['Nom'] = f"{civilite} {prenom} {nom}".strip()
            info['Organisme'] = self._get_safe_value(data, 'ORGANISME_DEMANDEUR') or self._get_safe_value(data, 'ORGANISME_DEFENDEUR')

            adresse = data.get('ADRESSE_DEMANDEUR', {}) if isinstance(data.get('ADRESSE_DEMANDEUR'), dict) else {}
            if not adresse:
                adresse = data.get('ADRESSE_DEFENDEUR', {}) if isinstance(data.get('ADRESSE_DEFENDEUR'), dict) else {}

            info['Adresse Complete'] = self._get_safe_value(adresse, 'ADRESSE_COMPLETE_DEMANDEUR') or self._get_safe_value(adresse, 'ADRESSE_COMPLETE_DEFENDEUR')
            info['Email'] = self._get_safe_value(data, 'EMAIL_DEMANDEUR') or self._get_safe_value(data, 'EMAIL_DEFENDEUR')
            info['Telephone'] = self._get_safe_value(data, 'TELEPHONE_DEMANDEUR') or self._get_safe_value(data, 'TELEPHONE_DEFENDEUR')

        return {k: v for k, v in info.items() if v and v != "Non spécifié"}

    def _process_special_fields(self, key: str, value: Any) -> bool:
        """Traite les champs spéciaux (HISTORIQUE et MISSION)"""
        if key in ["HISTORIQUE", "MISSION"]:
            self._add_title(key.upper().strip(), 1)

            # Vérifier si la valeur est une liste
            if isinstance(value, list):
                for item in value:
                    p = self.doc.add_paragraph()
                    p.add_run(str(item).strip())
            else:
                # Si c'est une chaîne simple ou autre type
                p = self.doc.add_paragraph()
                p.add_run(str(value).strip())

            # Ajouter un espace après HISTORIQUE seulement
            if key == "HISTORIQUE":
                self.doc.add_paragraph()

            return True
        return False

    def _process_parties(self, title: str, items: Union[str, List], level: int):
        """Traite les parties (demandeurs/défendeurs)"""
        self._add_title(title, level)

        # Si aucune partie n'est spécifiée
        if isinstance(items, str) and items == "Non spécifié":
            p = self.doc.add_paragraph(style='List Bullet')
            p.add_run("Non spécifié")
            return

        # Traitement de chaque partie
        if isinstance(items, list):
            for idx, item in enumerate(items, 1):
                if not isinstance(item, dict):
                    continue

                # Sous-titre pour chaque partie
                partie_title = f"{title.rstrip('S')} {idx}"
                self._add_title(partie_title, level + 1)

                # Formatage du nom complet
                civilite = self._get_safe_value(item, f'CIVILITE_{title.rstrip("S")}', '')
                prenom = self._get_safe_value(item, f'PRENOM_{title.rstrip("S")}', '')
                nom = self._get_safe_value(item, f'NOM_{title.rstrip("S")}', '')
                nom_complet = f"{civilite} {prenom} {nom}".strip()

                # Ajout du nom
                if nom_complet and nom_complet != "Non spécifié":
                    p = self.doc.add_paragraph(style='List Bullet')
                    p.add_run("Nom: ").bold = True
                    p.add_run(nom_complet)

                # Récupération de l'adresse
                adresse = item.get(f'ADRESSE_{title.rstrip("S")}', {})
                if isinstance(adresse, dict):
                    adresse_complete = adresse.get(f'ADRESSE_COMPLETE_{title.rstrip("S")}', '')
                    if adresse_complete and adresse_complete != "Non spécifié":
                        p = self.doc.add_paragraph(style='List Bullet')
                        p.add_run("Adresse Complete: ").bold = True
                        p.add_run(adresse_complete)

                # Ajout du téléphone
                telephone = self._get_safe_value(item, f'TELEPHONE_{title.rstrip("S")}', '')
                if telephone and telephone != "Non spécifié":
                    p = self.doc.add_paragraph(style='List Bullet')
                    p.add_run("Téléphone: ").bold = True
                    p.add_run(telephone)

                # Ajout de l'email
                email = self._get_safe_value(item, f'EMAIL_{title.rstrip("S")}', '')
                if email and email != "Non spécifié":
                    p = self.doc.add_paragraph(style='List Bullet')
                    p.add_run("Email: ").bold = True
                    p.add_run(email)

                # Traitement des avocats
                avocat_key = f'AVOCAT_{title.rstrip("S")}'
                avocats = item.get(avocat_key, [])

                if isinstance(avocats, list) and avocats and avocats != "Non spécifié":
                    for avocat_idx, avocat in enumerate(avocats, 1):
                        if isinstance(avocat, dict):
                            # Sous-titre pour chaque avocat
                            self._add_title(f"Avocat {avocat_idx}", level + 2)

                            # Nom de l'avocat
                            civilite_avocat = self._get_safe_value(avocat, f'CIVILITE_AVOCAT_{title.rstrip("S")}', '')
                            prenom_avocat = self._get_safe_value(avocat, f'PRENOM_AVOCAT_{title.rstrip("S")}', '')
                            nom_avocat = self._get_safe_value(avocat, f'NOM_AVOCAT_{title.rstrip("S")}', '')
                            nom_complet_avocat = f"{civilite_avocat} {prenom_avocat} {nom_avocat}".strip()

                            if nom_complet_avocat and nom_complet_avocat != "Non spécifié":
                                p = self.doc.add_paragraph(style='List Bullet')
                                p.add_run("Nom: ").bold = True
                                p.add_run(nom_complet_avocat)

                            # Barreau
                            barreau = self._get_safe_value(avocat, f'BARREAU_AVOCAT_{title.rstrip("S")}', '')
                            if barreau and barreau != "Non spécifié":
                                p = self.doc.add_paragraph(style='List Bullet')
                                p.add_run("Barreau: ").bold = True
                                p.add_run(barreau)

                            # Bureau d'avocats
                            bureau = self._get_safe_value(avocat, f'BUREAU_AVOCAT_{title.rstrip("S")}', '')
                            if bureau and bureau != "Non spécifié":
                                p = self.doc.add_paragraph(style='List Bullet')
                                p.add_run("Bureau d'avocats: ").bold = True
                                p.add_run(bureau)

                            # Adresse de l'avocat
                            adresse_avocat = avocat.get(f'ADRESSE_AVOCAT_{title.rstrip("S")}', {})
                            if isinstance(adresse_avocat, dict):
                                adresse_complete_avocat = adresse_avocat.get(f'ADRESSE_COMPLETE_AVOCAT_{title.rstrip("S")}', '')
                                if adresse_complete_avocat and adresse_complete_avocat != "Non spécifié":
                                    p = self.doc.add_paragraph(style='List Bullet')
                                    p.add_run("Adresse Complete: ").bold = True
                                    p.add_run(adresse_complete_avocat)

                            # Téléphone de l'avocat
                            tel_avocat = self._get_safe_value(avocat, f'TELEPHONE_AVOCAT_{title.rstrip("S")}', '')
                            if tel_avocat and tel_avocat != "Non spécifié":
                                p = self.doc.add_paragraph(style='List Bullet')
                                p.add_run("Téléphone: ").bold = True
                                p.add_run(tel_avocat)

                            # Email de l'avocat
                            email_avocat = self._get_safe_value(avocat, f'EMAIL_AVOCAT_{title.rstrip("S")}', '')
                            if email_avocat and email_avocat != "Non spécifié":
                                p = self.doc.add_paragraph(style='List Bullet')
                                p.add_run("Email: ").bold = True
                                p.add_run(email_avocat)

                # Ajouter un espace entre chaque partie
                if idx < len(items):
                    self.doc.add_paragraph()

    def _add_table_of_contents(self):
        """Ajoute une table des matières au document"""
        paragraph = self.doc.add_paragraph()
        run = paragraph.add_run("TABLE DES MATIÈRES")
        run.bold = True
        run.font.size = Pt(14)

        self.doc.add_paragraph()
        paragraph = self.doc.add_paragraph()

        # Ajouter le champ TOC
        run = paragraph.add_run()
        fldChar1 = OxmlElement('w:fldChar')
        fldChar1.set(qn('w:fldCharType'), 'begin')
        run._r.append(fldChar1)

        instrText = OxmlElement('w:instrText')
        instrText.set(qn('xml:space'), 'preserve')
        instrText.text = 'TOC \\o "1-3" \\h \\z \\u'
        run._r.append(instrText)

        fldChar2 = OxmlElement('w:fldChar')
        fldChar2.set(qn('w:fldCharType'), 'separate')
        run._r.append(fldChar2)

        # Ajouter un espace pour la mise à jour
        run = paragraph.add_run()

        fldChar4 = OxmlElement('w:fldChar')
        fldChar4.set(qn('w:fldCharType'), 'end')
        run._r.append(fldChar4)

        self.doc.add_page_break()

    def _format_person_info_simple(self, data: Dict, prefix: str) -> str:
        """Formate les informations d'une personne (magistrat ou greffier)"""
        prenom = data.get(f'PRENOM_{prefix}', '').strip()
        nom = data.get(f'NOM_{prefix}', '').strip()
        titre = data.get(f'TITRE_{prefix}', '').strip()
        return f"{prenom} {nom}, {titre}".strip()

    def _format_monetary_value(self, data: Dict, prefix: str) -> str:
        """Formate les valeurs monétaires"""
        try:
            valeur = str(data.get(f'VALEUR_{prefix}', 0)).strip()
            if valeur == "None":
                valeur = "0.0"
        except:
            valeur = "0.0"
        try:
            monnaie = data.get(f'MONNAIE_{prefix}', '€').strip()
        except:
            monnaie = "euros"
        if valeur == "0.0":
            return "Non spécifié"
        else:
            return f"{valeur} {monnaie}".strip()

    def generate_report(self):
        """Génère le rapport complet"""
        try:
            # Titre principal
            title = self.doc.add_heading("Données extraites d'une ordonnance de référé", 0)
            title.alignment = WD_ALIGN_PARAGRAPH.CENTER

            # Informations générales
            self._add_title("INFORMATIONS GÉNÉRALES", 1)
            if isinstance(self.json_data.get("INFORMATIONS_GENERALES"), dict):
                info_gen = self.json_data["INFORMATIONS_GENERALES"]

                # Liste des champs à traiter
                fields_to_process = [
                    # Champs simples
                    ("DATE_ORDONNANCE_REFERE", "Date Ordonnance Référé"),
                    ("TRIBUNAL_ORDONNANCE_REFERE", "Tribunal"),
                    ("REFERENCE_DOSSIER", "Référence Dossier"),
                    ("REFERENCE_PORTALIS", "Référence Portalis"),

                    # Champs complexes avec formatage spécial
                    ("MAGISTRAT_ORDONNANCE_REFERE", "Magistrat", 
                    lambda x: self._format_person_info_simple(x, "MAGISTRAT_ORDONNANCE_REFERE")),

                    ("GREFFIER_ORDONNANCE_REFERE", "Greffier",
                    lambda x: self._format_person_info_simple(x, "GREFFIER_ORDONNANCE_REFERE")),

                    ("CONSIGNATION", "Consignation",
                    lambda x: self._format_monetary_value(x, "CONSIGNATION")),

                    #("SOMME_A_CONSIGER", "Somme A Consiger",
                    #lambda x: self._format_monetary_value(x, "SOMME_A_CONSIGER"))
                ]

                # Traitement de chaque champ
                for field in fields_to_process:
                    key = field[0]
                    display_name = field[1]

                    if key in info_gen:
                        p = self.doc.add_paragraph(style='List Bullet')
                        p.add_run(f"{display_name}: ").bold = True

                        # Si c'est un champ avec formatage spécial (longueur du tuple = 3)
                        if len(field) == 3:
                            formatter = field[2]
                            value = formatter(info_gen[key])
                        else:
                            value = str(info_gen[key])

                        p.add_run(value)

            # Traitement des demandeurs
            if "DEMANDEURS" in self.json_data:
                self._process_parties("DEMANDEURS", self.json_data["DEMANDEURS"], 1)

            # Traitement des défendeurs
            if "DEFENDEURS" in self.json_data:
                self._process_parties("DEFENDEURS", self.json_data["DEFENDEURS"], 1)

            # Historique
            if "HISTORIQUE" in self.json_data:
                self._process_special_fields("HISTORIQUE", self.json_data["HISTORIQUE"])

            # Mission
            if "MISSION" in self.json_data:
                self._process_special_fields("MISSION", self.json_data["MISSION"])

            # Sauvegarde du document
            self.doc.save(self.docx_path)
            self.logger.info(f"Rapport généré avec succès: {self.docx_path}")

            return self.docx_path

        except Exception as e:
            self.logger.error(f"Erreur lors de la génération du rapport: {str(e)}")
            raise