#!/usr/bin/env python3 """ Script pentru generare Proces Verbal AG bleuMarin Constanța 25.11.2025 Format DOCX similar cu modelul PDF """ from docx import Document from docx.shared import Inches, Pt, Cm from docx.enum.text import WD_ALIGN_PARAGRAPH from docx.enum.table import WD_TABLE_ALIGNMENT from docx.oxml.ns import qn from docx.oxml import OxmlElement import pandas as pd from pathlib import Path # Configurare căi INPUT_DIR = Path(__file__).parent.parent / "input" OUTPUT_DIR = Path(__file__).parent.parent / "output" # Fișiere de intrare VOTURI_PRINCIPAL_FILE = INPUT_DIR / "AG bleuMarin Constanța 25.11.2025 (Responses) - Form Responses 1.csv" VOTURI_SUPLIMENTAR_FILE = INPUT_DIR / "AG bleuMarin Constanța 25.11.2025 Suplimentar (Responses) - Form Responses 1.csv" def set_cell_shading(cell, color): """Setează culoarea de fundal pentru o celulă""" shading = OxmlElement('w:shd') shading.set(qn('w:fill'), color) cell._tc.get_or_add_tcPr().append(shading) def add_heading_style(paragraph, text, size=14, bold=True, center=True): """Adaugă un heading formatat""" run = paragraph.add_run(text) run.bold = bold run.font.size = Pt(size) run.font.name = 'Times New Roman' if center: paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER def create_proces_verbal(): """Creează documentul proces verbal""" # Încarcă datele pentru lista participanți voturi_principal_df = pd.read_csv(VOTURI_PRINCIPAL_FILE) voturi_suplimentar_df = pd.read_csv(VOTURI_SUPLIMENTAR_FILE) # Elimină duplicate pe email, păstrează primul vot voturi_principal_df = voturi_principal_df.sort_values('Timestamp').drop_duplicates(subset=['Email Address'], keep='first') voturi_suplimentar_df = voturi_suplimentar_df.sort_values('Timestamp').drop_duplicates(subset=['Email Address'], keep='first') # Lista participanți (unici din ambele formulare) participanti_principal = set(voturi_principal_df['Nume și prenume'].tolist()) participanti_suplimentar = set(voturi_suplimentar_df['Nume și prenume'].tolist()) toti_participantii = sorted(participanti_principal.union(participanti_suplimentar)) # Crează documentul doc = Document() # Setări pagină section = doc.sections[0] section.page_width = Cm(21) section.page_height = Cm(29.7) section.left_margin = Cm(2.5) section.right_margin = Cm(2.5) section.top_margin = Cm(2) section.bottom_margin = Cm(2) # ==================== TITLU ==================== p = doc.add_paragraph() add_heading_style(p, "PROCES VERBAL", size=14, bold=True) p = doc.add_paragraph() add_heading_style(p, "Al ADUNĂRII GENERALE", size=12, bold=True) p = doc.add_paragraph() add_heading_style(p, "a Organizației Naționale Cercetașii României - Filiala bleuMarin Constanța", size=12, bold=True) p = doc.add_paragraph() add_heading_style(p, "Încheiat azi, 25.11.2025", size=12, bold=True) doc.add_paragraph() # Spațiu # ==================== I. ASPECTE INTRODUCTIVE ==================== p = doc.add_paragraph() run = p.add_run("I.\tAspecte Introductive") run.bold = True run.font.size = Pt(12) doc.add_paragraph() p = doc.add_paragraph() p.add_run("Potrivit organizării agreate, Secretariatul se constituie în sistem online, membri cu drept de vot fiind convocați via rețele de socializare utilizate de membri (grupuri WhatsApp). Data, modul de desfășurare și ordinea de zi a Adunării Generale a fost comunicată către membri prin grupurile de WhatsApp utilizate de membri.") p.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY p = doc.add_paragraph() p.add_run("Adunarea Generală s-a organizat ") run = p.add_run("online, prin formulare Google") run.bold = True p.add_run(", votarea fiind deschisă în perioada 25-26 noiembrie 2025.") p.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY p = doc.add_paragraph() p.add_run("În condițiile în care Adunarea Generală este organul deliberativ al filialei, întrunirea cvorumului – peste 2/3 din membrii cu drept de vot – asigură legalitatea ședinței și a întrunirii.") p.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY p = doc.add_paragraph() p.add_run("Secretariatul ședinței este asigurat de ") run = p.add_run("Mutu Marius") run.bold = True p.add_run(". Președintele ședinței este ") run = p.add_run("Mutu Marius") run.bold = True p.add_run(". Votarea electronică prin formulare Google elimină necesitatea unei comisii de numărare a voturilor.") p.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY doc.add_paragraph() # ==================== II. ORDINEA DE ZI ==================== p = doc.add_paragraph() run = p.add_run("II.\tOrdinea de zi") run.bold = True run.font.size = Pt(12) doc.add_paragraph() # Ordinea de zi conform documentului oficial AG Ordine de Zi 25.11.2025.pdf # Punct 1 cu subpuncte p = doc.add_paragraph() run = p.add_run("1. Votare puncte de pe OZ AG Național 19 decembrie") run.bold = True p.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY p = doc.add_paragraph(" 1.1 Bugetul ONCR pe anul 2026") p.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY p = doc.add_paragraph(" 1.2 Acordarea dreptului de obținere a Personalității Juridice pentru toate structurile locale") p.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY p = doc.add_paragraph(" 1.3 Decizie pentru reglementarea transferurilor între Centre Locale") p.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY # Punct suplimentar ONCR (din formularul suplimentar) p = doc.add_paragraph(" 1.4 Înființare prin desprindere din alt Centru Local cu Personalitate Juridică: Sfântul Voievod Ștefan cel Mare, București cu desprindere din Orizont, Brașov") p.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY ordine_zi_rest = [ "2. Reprezentant bleuMarin la AG Național: Cora - Maria Costache", "3. Cotizația: 250 lei / 175 frați (70%) / 150 lei adulți / 150 lei copii lideri/lideri asistenți/rol administrativ, din care 150 lei către organizația națională.", "4. Woodbadge lideri: 20% achitat de participant, 80% achitat de centrul local (hotărâre CCL 21.08.2024)", "5. Activități de fund-raising efectuate de patrule - 20% din donații vor rămâne la centrul local pentru acțiuni sociale (implicare în comunitate), 80% către patrulă pentru susținerea activităților cercetășești.", "6. Activități de fund-raising efectuat de un membru pentru participarea la evenimente cercetășești - 20% din donații vor rămâne la centrul local pentru acțiuni sociale (implicare în comunitate), 80% către membru pentru participarea la evenimente cercetășești.", "7. Sponsorizări atrase de un membru individual - până la 20% din sponsorizare poate fi folosită de membru pentru participarea la evenimente cercetășești și decontată de către centrul local. Se vor avea în vedere limite de sume aprobate de CCL, pentru sponsorizări mai mari de 10.000 lei.", "8. Telefoanele și alte dispozitive electronice nu vor fi folosite la activități, decât dacă este nevoie în scopul activităților, la indicația liderilor. Se respectă timpul și munca liderilor, a altor participanți și a colegilor de patrulă, cercetașii sunt implicați în activități, nu pe telefoane.", "9. Întrucât activitățile de fund-raising și caritate/activități sociale implică imaginea și reprezentarea externă a cercetașilor este nevoie ca aceste acțiuni ale unităților/patrulelor/individuale să fie anunțate pe grupul bleuMarin și aprobate de CCL.", "10. Badge centru local", "11. Alte subiecte propuse de membri" ] for item in ordine_zi_rest: p = doc.add_paragraph(item) p.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY doc.add_paragraph() # ==================== III. ASPECTE PRELIMINARE ==================== p = doc.add_paragraph() run = p.add_run("III.\tAspecte preliminare") run.bold = True run.font.size = Pt(12) doc.add_paragraph() p = doc.add_paragraph() run = p.add_run("Se face prezența. ") run.bold = True p.add_run("Se constată un număr de ") run = p.add_run("53 persoane") run.bold = True p.add_run(" care au votat dintr-un număr total de ") run = p.add_run("75 de membri") run.bold = True p.add_run(" cu drept de vot la data Adunării Generale, cvorumul de ") run = p.add_run("50 persoane (2/3 din 75)") run.bold = True p.add_run(" din membrii cu drept de vot fiind îndeplinit.") p.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY doc.add_paragraph() # ==================== VOTAREA PUNCTELOR ==================== p = doc.add_paragraph() run = p.add_run("Se votează punctele de pe Ordinea de zi (OZ)") run.bold = True run.font.size = Pt(12) doc.add_paragraph() # Rezultatele voturilor - conform ordinii de zi # Punctul 1 - Votare puncte OZ AG Național p = doc.add_paragraph() run = p.add_run("1. Votare puncte de pe OZ AG Național 19 decembrie") run.bold = True rezultate_oncr = [ ("1.1 Bugetul ONCR pe anul 2026", 52, 1, 0), ("1.2 Acordarea dreptului de obținere a Personalității Juridice pentru toate structurile locale", 52, 1, 0), ("1.3 Decizie pentru reglementarea transferurilor între Centre Locale", 51, 2, 0), ("1.4 Înființare prin desprindere CL Sf. Voievod Ștefan cel Mare, București (din Orizont, Brașov)", 15, 2, 10), ] for propunere, da, nu, abtinere in rezultate_oncr: p = doc.add_paragraph() p.add_run(f" {propunere}: ") run = p.add_run("APROBAT") run.bold = True p.add_run(" (") run = p.add_run(f"{da} DA") run.bold = True p.add_run(", ") run = p.add_run(f"{nu} NU") run.bold = True p.add_run(", ") run = p.add_run(f"{abtinere} Abțineri") run.bold = True p.add_run(")") p.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY # Restul punctelor rezultate_locale = [ ("2. Reprezentant bleuMarin la AG Național: Cora - Maria Costache", 47, 6, 0), ("3. Cotizația: 250 lei / 175 frați / 150 lei adulți / 150 lei copii lideri", 52, 1, 0), ("4. Woodbadge lideri: 20% participant, 80% centru local", 53, 0, 0), ("5. Fund-raising patrule: 20% acțiuni sociale, 80% patrulă", 52, 1, 0), ("6. Fund-raising membru: 20% acțiuni sociale, 80% membru", 49, 4, 0), ("7. Sponsorizări membru individual: până la 20% pentru evenimente", 52, 1, 0), ("8. Telefoane la activități - restricții de utilizare", 45, 8, 0), ("9. Fund-raising/caritate - anunțare și aprobare CCL", 53, 0, 0), ] for propunere, da, nu, abtinere in rezultate_locale: p = doc.add_paragraph() run = p.add_run("Se votează APROBAT ") run.bold = True p.add_run(f"pentru {propunere} (") run = p.add_run(f"{da} DA") run.bold = True p.add_run(", ") run = p.add_run(f"{nu} NU") run.bold = True p.add_run(", ") run = p.add_run(f"{abtinere} Abțineri") run.bold = True p.add_run(")") p.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY # Punctele 10 și 11 - fără vot explicit în formular p = doc.add_paragraph() run = p.add_run("10. Badge centru local") run.bold = True p.add_run(" - s-a prezentat propunerea de badge pentru centrul local.") p.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY p = doc.add_paragraph() run = p.add_run("11. Alte subiecte propuse de membri") run.bold = True p.add_run(" - nu au fost propuse alte subiecte.") p.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY doc.add_paragraph() doc.add_paragraph() # ==================== SEMNĂTURI ==================== # Crează un tabel pentru semnături table = doc.add_table(rows=2, cols=2) table.alignment = WD_TABLE_ALIGNMENT.CENTER # Prima linie - titluri table.cell(0, 0).text = "Secretar" table.cell(0, 1).text = "Președinte" # A doua linie - nume table.cell(1, 0).text = "Mutu Marius" table.cell(1, 1).text = "Mutu Marius" # Formatare celule for row in table.rows: for cell in row.cells: cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER for run in cell.paragraphs[0].runs: run.font.size = Pt(11) # Adăugare pagină nouă pentru lista participanți doc.add_page_break() # ==================== LISTA PARTICIPANȚI ==================== p = doc.add_paragraph() add_heading_style(p, "ADUNARE GENERALĂ", size=14, bold=True) p = doc.add_paragraph() add_heading_style(p, "ONCR - FILIALA BLEUMARIN CONSTANȚA", size=12, bold=True) p = doc.add_paragraph() add_heading_style(p, "25.11.2025", size=12, bold=True) doc.add_paragraph() p = doc.add_paragraph() add_heading_style(p, "LISTA PARTICIPANȚI (VOT ONLINE)", size=12, bold=True) doc.add_paragraph() # Tabel participanți table = doc.add_table(rows=1, cols=3) table.style = 'Table Grid' # Header header_cells = table.rows[0].cells header_cells[0].text = "Nr" header_cells[1].text = "Nume" header_cells[2].text = "Email" # Formatare header for cell in header_cells: cell.paragraphs[0].runs[0].bold = True cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER set_cell_shading(cell, "D9D9D9") # Adaugă participanții din formularul principal (sortați alfabetic) participanti_df = voturi_principal_df[['Nume și prenume', 'Email Address']].sort_values('Nume și prenume') for i, (_, row) in enumerate(participanti_df.iterrows(), 1): row_cells = table.add_row().cells row_cells[0].text = str(i) row_cells[1].text = str(row['Nume și prenume']) row_cells[2].text = str(row['Email Address']) row_cells[0].paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER # Setare lățime coloane for row in table.rows: row.cells[0].width = Cm(1) row.cells[1].width = Cm(6) row.cells[2].width = Cm(8) doc.add_paragraph() # Total p = doc.add_paragraph() run = p.add_run(f"TOTAL ELIGIBILI: 75") run.bold = True p = doc.add_paragraph() run = p.add_run(f"CVORUM: 50") run.bold = True p = doc.add_paragraph() run = p.add_run(f"TOTAL PARTICIPANȚI: {len(participanti_df)}") run.bold = True # Salvare document output_path = OUTPUT_DIR / "Proces_verbal_AG_25.11.2025.docx" doc.save(output_path) print(f"Proces verbal salvat: {output_path}") return output_path if __name__ == "__main__": create_proces_verbal()