didi-website-erp-crm/website/scripts/archive/generate_propunere.py

875 lines
47 KiB
Python

import sys, io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
from docx import Document
from docx.shared import Inches, Pt, Cm, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT
from docx.enum.section import WD_ORIENT
from docx.oxml.ns import qn
from docx.oxml import OxmlElement
import datetime
doc = Document()
# ── Page margins ──
for section in doc.sections:
section.top_margin = Cm(2.5)
section.bottom_margin = Cm(2)
section.left_margin = Cm(2.5)
section.right_margin = Cm(2.5)
style = doc.styles['Normal']
font = style.font
font.name = 'Calibri'
font.size = Pt(11)
font.color.rgb = RGBColor(0x33, 0x33, 0x33)
style.paragraph_format.space_after = Pt(6)
style.paragraph_format.line_spacing = 1.15
# Heading styles
for level, size, color in [(1, 16, 0x0D9488), (2, 13, 0x0F766E), (3, 11, 0x115E59)]:
hs = doc.styles[f'Heading {level}']
hs.font.name = 'Calibri'
hs.font.size = Pt(size)
hs.font.color.rgb = RGBColor((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF)
hs.font.bold = True
hs.paragraph_format.space_before = Pt(18 if level == 1 else 14)
hs.paragraph_format.space_after = Pt(8)
def add_bullet(text, bold_prefix=None, level=0):
p = doc.add_paragraph(style='List Bullet')
p.paragraph_format.left_indent = Cm(1.2 + level * 0.8)
p.paragraph_format.space_after = Pt(3)
if bold_prefix:
run = p.add_run(bold_prefix)
run.bold = True
run.font.size = Pt(10)
run2 = p.add_run(text)
run2.font.size = Pt(10)
else:
run = p.add_run(text)
run.font.size = Pt(10)
return p
def add_para(text, bold=False, italic=False, size=11, align=None, space_after=6):
p = doc.add_paragraph()
run = p.add_run(text)
run.font.size = Pt(size)
run.bold = bold
run.italic = italic
if align:
p.alignment = align
p.paragraph_format.space_after = Pt(space_after)
return p
def add_table_row(table, cells_data, bold=False, bg_color=None):
row = table.add_row()
for i, text in enumerate(cells_data):
cell = row.cells[i]
cell.text = ''
p = cell.paragraphs[0]
run = p.add_run(str(text))
run.font.size = Pt(9)
run.bold = bold
if bg_color:
shading = OxmlElement('w:shd')
shading.set(qn('w:fill'), bg_color)
shading.set(qn('w:val'), 'clear')
cell._tc.get_or_add_tcPr().append(shading)
return row
def set_table_header_bg(table, color='0D9488'):
for cell in table.rows[0].cells:
shading = OxmlElement('w:shd')
shading.set(qn('w:fill'), color)
shading.set(qn('w:val'), 'clear')
cell._tc.get_or_add_tcPr().append(shading)
for p in cell.paragraphs:
for run in p.runs:
run.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
run.bold = True
# ═══════════════════════════════════════════════════════
# COVER PAGE
# ═══════════════════════════════════════════════════════
for _ in range(6):
doc.add_paragraph()
add_para('PROPUNERE TEHNICA', bold=True, size=24, align=WD_ALIGN_PARAGRAPH.CENTER, space_after=4)
add_para('RAPORT INTERMEDIAR DE IMPLEMENTARE', bold=True, size=14, align=WD_ALIGN_PARAGRAPH.CENTER, space_after=20)
# Separator line
p = doc.add_paragraph()
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
run = p.add_run('_' * 60)
run.font.color.rgb = RGBColor(0x0D, 0x94, 0x88)
p.paragraph_format.space_after = Pt(20)
add_para('Dezvoltare website cu e-commerce,\ncu ERP si CRM in cloud', bold=True, size=13, align=WD_ALIGN_PARAGRAPH.CENTER, space_after=8)
add_para('in cadrul proiectului', italic=True, size=10, align=WD_ALIGN_PARAGRAPH.CENTER, space_after=4)
add_para('PLATFORMA DIGITALA INTELIGENTA PENTRU\nPREVENIREA SI COMBATEREA DEZINFORMARII', bold=True, size=12, align=WD_ALIGN_PARAGRAPH.CENTER, space_after=30)
add_para(f'Data document: {datetime.date.today().strftime("%d.%m.%Y")}', size=10, align=WD_ALIGN_PARAGRAPH.CENTER, space_after=4)
add_para('Stadiu: Implementare in curs', italic=True, size=10, align=WD_ALIGN_PARAGRAPH.CENTER)
doc.add_page_break()
# ═══════════════════════════════════════════════════════
# CUPRINS
# ═══════════════════════════════════════════════════════
doc.add_heading('CUPRINS', level=1)
cuprins = [
'1. Scopul documentului',
'2. Stiva tehnologica propusa',
'3. Arhitectura generala si interconectare componente',
'4. Componenta Website — Stadiu implementare',
'5. Componenta ERP/CRM — Stadiu implementare',
'6. Integrari realizate si flux de date',
'7. Securitate si protectia datelor (GDPR)',
'8. Stadiu general si pasi urmatori',
'9. Tabel de conformitate — stadiu curent',
]
for item in cuprins:
add_para(item, size=11, space_after=4)
doc.add_page_break()
# ═══════════════════════════════════════════════════════
# 1. SCOPUL DOCUMENTULUI
# ═══════════════════════════════════════════════════════
doc.add_heading('1. Scopul documentului', level=1)
add_para(
'Prezentul document constituie un raport intermediar de implementare al solutiei tehnice '
'pentru dezvoltarea website-ului cu e-commerce, ERP si CRM in cloud. '
'Documentul prezinta stadiul actual al dezvoltarii, arhitectura implementata, '
'tehnologiile utilizate, functionalitatile livrate pana in acest moment si pasii urmatori.'
)
add_para(
'Scopul este de a oferi Beneficiarului o imagine clara asupra progresului tehnic, '
'a deciziilor arhitecturale luate si a modului in care solutia propusa raspunde '
'cerintelor din Caietul de Sarcini (Capitolul II).'
)
add_para(
'Acest document nu reprezinta livrabilul final — este un punct de referinta intermediar '
'care permite validarea directiei tehnice si colectarea de feedback inainte de finalizare.',
italic=True
)
# ═══════════════════════════════════════════════════════
# 2. STIVA TEHNOLOGICA
# ═══════════════════════════════════════════════════════
doc.add_heading('2. Stiva tehnologica propusa', level=1)
add_para(
'Solutia a fost construita folosind o stiva tehnologica moderna, bazata exclusiv pe '
'tehnologii open-source si frameworkuri cu suport activ pe termen lung. '
'Alegerea fiecarei componente a fost facuta in concordanta cu cerintele din Caietul de Sarcini '
'si cu principiile de modularitate, scalabilitate si securitate.'
)
doc.add_heading('2.1. Componente principale', level=2)
table = doc.add_table(rows=1, cols=4)
table.style = 'Light Grid Accent 1'
table.alignment = WD_TABLE_ALIGNMENT.CENTER
hdr = table.rows[0].cells
hdr[0].text = 'Componenta'
hdr[1].text = 'Tehnologie'
hdr[2].text = 'Versiune'
hdr[3].text = 'Rol in solutie'
set_table_header_bg(table)
tech_rows = [
['Website (Frontend)', 'Next.js (React)', 'v16', 'Website prezentare, e-commerce, dashboard client; Server-Side Rendering pentru SEO'],
['Website (Backend API)', 'Node.js / API Routes', 'v22', 'API-uri server-side pentru checkout, facturare, comunicare cu servicii externe'],
['Limbaj programare', 'TypeScript', 'v5', 'Tipizare statica pe intregul proiect, reducerea erorilor la compilare'],
['Stilizare', 'Tailwind CSS', 'v4', 'Framework CSS utility-first, design responsive, componente consistente'],
['ERP + CRM', 'ERPNext', 'v15', 'Contabilitate, facturare, CRM, rapoarte; solutie open-source GPL, configurata pentru legislatia RO'],
['Baza de date ERP', 'MariaDB', 'v10.11', 'Baza de date relationala pentru ERPNext, optimizata pentru tranzactii'],
['Cache si cozi', 'Redis', 'v7 (Alpine)', 'Cache pentru performanta si coada de taskuri asincrone ERPNext'],
['Autentificare (IAM)', 'Keycloak (SSO)', '-', 'Autentificare unificata prin OpenID Connect, gestionata de platforma existenta'],
['Procesor plati', 'Stripe', 'API v2024', 'Plati securizate cu card, checkout sessions, webhook-uri pentru confirmare'],
['Containerizare', 'Docker + Compose', '-', 'Izolare servicii, deployment reproducibil, orchestrare multi-container'],
['Reverse proxy', 'Nginx', '-', 'Rutare trafic, servire assets statice, proxy catre aplicatie'],
['Internationalizare', 'Custom i18n', '-', 'Suport complet romana (RO) si engleza (EN), comutare dinamica'],
]
for row_data in tech_rows:
add_table_row(table, row_data)
doc.add_heading('2.2. Justificarea alegerii tehnologiilor', level=2)
add_para('Next.js (React)', bold=True, size=10, space_after=2)
add_para(
'Framework-ul Next.js a fost ales pentru capacitatea de Server-Side Rendering (SSR) si '
'Static Site Generation (SSG), esentiale pentru performanta si SEO. App Router-ul permite '
'o structura clara a rutelor, iar React ofera un ecosistem matur de componente reutilizabile. '
'Ref. CS: II.6.1 — "Website dezvoltat cu tehnologii web moderne".',
size=10
)
add_para('ERPNext v15', bold=True, size=10, space_after=2)
add_para(
'ERPNext este o solutie ERP open-source (licenta GPL) cu module native de contabilitate, '
'facturare si CRM. Versiunea 15 ofera API REST complet, suport pentru custom DocTypes '
'si un sistem de permisiuni granulare. Configurarea pentru legislatia romaneasca (plan de conturi, '
'TVA 19%, serie facturi) este realizata prin scripturi de setup automate. '
'Ref. CS: II.6.2 — "Solutia ERP/CRM gazduita in cloud, configurabila".',
size=10
)
add_para('Stripe', bold=True, size=10, space_after=2)
add_para(
'Stripe a fost ales ca procesor de plati pentru suportul nativ de plati recurente (subscriptii), '
'webhook-uri pentru confirmare in timp real, compatibilitate cu piata din Romania si conformitate PCI DSS. '
'Ref. CS: II.6.3 — "Procesor de plati cu suport plati recurente, compatibil Romania".',
size=10
)
add_para('Docker', bold=True, size=10, space_after=2)
add_para(
'Containerizarea cu Docker asigura un mediu de deployment reproductibil si izolat. '
'Fiecare componenta (ERPNext, MariaDB, Redis, workers) ruleaza in container propriu, '
'facilitand scalarea independenta si deployment-ul in cloud EU. '
'Ref. CS: II.3 — "Cloud hosting EU", II.6.2 — "Backup automat".',
size=10
)
doc.add_page_break()
# ═══════════════════════════════════════════════════════
# 3. ARHITECTURA
# ═══════════════════════════════════════════════════════
doc.add_heading('3. Arhitectura generala si interconectare componente', level=1)
add_para(
'Arhitectura solutiei este modulara, cu separare clara intre componenta de prezentare (website), '
'componenta de business logic (ERP/CRM) si serviciile externe (autentificare, plati, email). '
'Comunicarea intre componente se realizeaza exclusiv prin API-uri REST securizate.'
)
doc.add_heading('3.1. Diagrama de interconectare', level=2)
add_para(
'Schema de mai jos ilustreaza fluxul de date intre componentele principale:',
size=10, space_after=10
)
# ASCII-style architecture diagram
arch_text = """
┌─────────────────────────────────────────────────────────────┐
│ UTILIZATOR (Browser) │
│ Desktop / Tableta / Mobil │
└──────────────────────────┬──────────────────────────────────┘
│ HTTPS
┌──────────────────────────▼──────────────────────────────────┐
│ WEBSITE (Next.js / React) │
│ ┌──────────────┐ ┌──────────────┐ ┌───────────────────┐ │
│ │ Pagini │ │ Dashboard │ │ API Routes │ │
│ │ Publice │ │ Client │ │ (Server-side) │ │
│ │ (SSR/SSG) │ │ (Protejat) │ │ │ │
│ └──────────────┘ └──────────────┘ └─────┬─────────────┘ │
└────────────────────────────────────────────┬┼────────────────┘
┌────────────────────────┘│
│ ┌──────────┘
API REST │ │ API REST + Webhooks
┌───────────────────▼───┐ ┌────▼──────────────────────────┐
│ ERP/CRM (ERPNext) │ │ SERVICII EXTERNE │
│ ┌─────────────────┐ │ │ ┌────────────────────────┐ │
│ │ Contabilitate │ │ │ │ IAM (SSO/OpenID) │ │
│ │ Facturare │ │ │ │ Autentificare unificata│ │
│ │ CRM / Pipeline │ │ │ └────────────────────────┘ │
│ │ CMS (Continut) │ │ │ ┌────────────────────────┐ │
│ │ DocTypes Custom │ │ │ │ Procesor Plati │ │
│ └────────┬────────┘ │ │ │ Checkout + Webhooks │ │
│ ┌────────▼────────┐ │ │ └────────────────────────┘ │
│ │ MariaDB + Redis │ │ │ ┌────────────────────────┐ │
│ │ (Persistenta) │ │ │ │ API Platforma DiDi │ │
│ └─────────────────┘ │ │ │ Analize + Credite │ │
└───────────────────────┘ └───────────────────────────────┘
"""
p = doc.add_paragraph()
run = p.add_run(arch_text)
run.font.name = 'Consolas'
run.font.size = Pt(7.5)
p.paragraph_format.space_after = Pt(12)
doc.add_heading('3.2. Principii arhitecturale implementate', level=2)
add_bullet('Comunicarea intre website si ERP/CRM se realizeaza prin proxy server-side — '
'credentialele API nu sunt niciodata expuse in browser', bold_prefix='Securitate API: ')
add_bullet('Website-ul (frontend + API) si ERPNext (ERP/CRM) ruleaza in containere Docker separate, '
'cu retea interna partajata; pot fi deployate pe servere diferite', bold_prefix='Separare componente: ')
add_bullet('Continutul paginilor publice (homepage, servicii, despre, privacy, termeni) este gestionat '
'din interfata ERPNext si preluat dinamic de website prin API', bold_prefix='CMS centralizat: ')
add_bullet('Toate paginile publice beneficiaza de Server-Side Rendering pentru indexare optima '
'de catre motoarele de cautare', bold_prefix='SEO prin SSR: ')
add_bullet('Suport complet pentru romana si engleza, cu posibilitate de extindere; '
'comutare dinamica din interfata', bold_prefix='Internationalizare: ')
add_bullet('Utilizator unic autentificat prin SSO — o singura sesiune valida '
'pentru website, dashboard si platforma', bold_prefix='Autentificare unificata: ')
doc.add_heading('3.3. Fluxuri de date principale', level=2)
add_para('Flux 1 — Autentificare utilizator', bold=True, size=10, space_after=2)
add_para(
'Utilizatorul acceseaza pagina de login → este redirectionat catre serverul IAM (OpenID Connect) '
'→ se autentifica → primeste un token JWT → este redirectionat inapoi in website cu sesiune activa '
'→ middleware-ul protejeaza rutele din dashboard pe baza sesiunii.',
size=10
)
add_para('Flux 2 — Achizitie serviciu (one-time)', bold=True, size=10, space_after=2)
add_para(
'Utilizatorul selecteaza un serviciu din pagina de pricing → este redirectionat catre checkout-ul '
'procesorului de plati → efectueaza plata → procesorul trimite un webhook la API-ul website-ului '
'→ API-ul creeaza automat: clientul in ERP (daca nu exista), factura fiscala (Sales Invoice), '
'log-ul tranzactiei → factura este disponibila in dashboard pentru vizualizare si download PDF.',
size=10
)
add_para('Flux 3 — Analiza continut (DiDi API)', bold=True, size=10, space_after=2)
add_para(
'Utilizatorul acceseaza sectiunea de analize din dashboard → selecteaza un serviciu achizitionat '
'si neconsmat → introduce textul sau URL-ul de analizat → API-ul website-ului trimite cererea catre '
'API-ul platformei DiDi → rezultatele sunt preluate prin polling → sunt afisate detaliat '
'(scor de risc, tehnici detectate, verificare afirmatii, detectie AI, credibilitate sursa).',
size=10
)
add_para('Flux 4 — Lead din formular contact', bold=True, size=10, space_after=2)
add_para(
'Vizitatorul completeaza formularul de contact de pe website → datele sunt trimise catre API-ul '
'website-ului → API-ul creeaza automat un Lead in modulul CRM al ERPNext cu sursa, '
'pagina de origine si parametri UTM → Lead-ul intra in pipeline-ul de vanzari.',
size=10
)
add_para('Flux 5 — Gestiune continut CMS', bold=True, size=10, space_after=2)
add_para(
'Administratorul editeaza continutul paginilor (texte, imagini) din interfata ERPNext '
'→ website-ul preia automat continutul actualizat prin API REST '
'→ paginile publice se actualizeaza fara interventie tehnica (fara deploy).',
size=10
)
doc.add_page_break()
# ═══════════════════════════════════════════════════════
# 4. WEBSITE
# ═══════════════════════════════════════════════════════
doc.add_heading('4. Componenta Website — Stadiu implementare', level=1)
add_para(
'Website-ul a fost dezvoltat integral cu Next.js (React) si TypeScript, folosind App Router '
'pentru structurarea rutelor si Tailwind CSS pentru stilizare. Toate paginile sunt responsive '
'si au suport bilingv (RO/EN).'
)
doc.add_heading('4.1. Pagini publice implementate', level=2)
add_para('Ref. CS: II.5.1 — Website de prezentare', italic=True, size=9, space_after=4)
table = doc.add_table(rows=1, cols=3)
table.style = 'Light Grid Accent 1'
hdr = table.rows[0].cells
hdr[0].text = 'Pagina'
hdr[1].text = 'Functionalitate'
hdr[2].text = 'Sursa continut'
set_table_header_bg(table)
pages_data = [
['Homepage', 'Sectiune hero, prezentare servicii (carduri), cum functioneaza (pasi), statistici platforma, cazuri de utilizare, apel la actiune', 'CMS din ERP (dinamic)'],
['Servicii', '6 module AI detaliate cu capabilitati tehnice: analiza text, deepfake, fact-checking, evaluare surse, tehnici manipulare, monitorizare media', 'CMS din ERP (dinamic)'],
['Despre', 'Prezentare companie, misiune, proiect, tehnologie utilizata', 'CMS din ERP (dinamic)'],
['Pricing', 'Grila de preturi pentru 4 tipuri de servicii x 4 tipuri media (text, imagine, audio, video); buton achizitie integrat cu procesorul de plati', 'Configuratie locala + ERP'],
['Contact', 'Formular de contact (nume, email, mesaj) cu trimitere automata in CRM; informatii de contact companie', 'CMS din ERP + formular'],
['Politica confidentialitate', 'Pagina GDPR completa cu descrierea datelor colectate, scopuri, drepturi utilizator, stocare', 'CMS din ERP (dinamic)'],
['Termeni si conditii', 'Definitii, servicii, plati, proprietate intelectuala, raspundere, legislatie aplicabila', 'CMS din ERP (dinamic)'],
]
for row_data in pages_data:
add_table_row(table, row_data)
doc.add_heading('4.2. Zona client autentificata (Dashboard)', level=2)
add_para('Ref. CS: II.4 — Zona client dashboard, II.5.2 — Gestiune abonamente', italic=True, size=9, space_after=4)
table = doc.add_table(rows=1, cols=3)
table.style = 'Light Grid Accent 1'
hdr = table.rows[0].cells
hdr[0].text = 'Pagina'
hdr[1].text = 'Functionalitate'
hdr[2].text = 'Sursa date'
set_table_header_bg(table)
dash_data = [
['Overview', 'Sumar: numar facturi, analize achizitionate, ultimele facturi emise, acces rapid la achizitie', 'ERP (API REST)'],
['Facturi', 'Lista completa facturi cu numar, data, suma, status; download PDF pentru fiecare factura', 'ERP (Sales Invoice)'],
['Analize', 'Lista servicii achizitionate si neconsumate; selectare si rulare analiza; afisare rezultate detaliate (scor risc, tehnici, verificari, detectie AI)', 'ERP + API Platforma'],
['Profil', 'Vizualizare si editare date personale (companie, cod fiscal); sectiune GDPR cu export date si solicitare stergere', 'ERP (Customer)'],
['Abonament', 'Detalii plan activ, lista functionalitati per nivel, data activare', 'ERP (Customer)'],
['Achizitioneaza', 'Grila servicii disponibile cu preturi; flux de achizitie integrat cu procesorul de plati', 'Configuratie + Stripe'],
['Checkout', 'Flux in 2 pasi: selectare plan + date facturare cu acceptare termeni; creare acord de servicii', 'ERP + Stripe'],
['Credite', 'Afisare credite disponibile si consum (pregatit pentru integrare cu API platforma)', 'API Platforma (partial)'],
]
for row_data in dash_data:
add_table_row(table, row_data)
doc.add_heading('4.3. API Routes implementate (Server-side)', level=2)
table = doc.add_table(rows=1, cols=3)
table.style = 'Light Grid Accent 1'
hdr = table.rows[0].cells
hdr[0].text = 'Endpoint'
hdr[1].text = 'Metoda'
hdr[2].text = 'Functionalitate'
set_table_header_bg(table)
api_data = [
['Autentificare', 'GET/POST', 'Handler OpenID Connect — login, callback, refresh token, logout'],
['Proxy ERP', 'GET/POST/PUT', 'Proxy server-side catre API-ul ERP; credentialele nu ajung in browser'],
['Lead-uri', 'POST', 'Creare Lead in CRM din formularul de contact website'],
['Checkout', 'POST', 'Creare sesiune de plata in procesorul de plati; redirect catre pagina de plata'],
['Webhook plati', 'POST', 'Procesare confirmare plata; creare automata client, factura si log tranzactie in ERP'],
['PDF Factura', 'GET', 'Download factura in format PDF din ERP, livrata prin proxy securizat'],
['Analize', 'GET/POST', 'Listare analize disponibile, trimitere cerere analiza, preluare rezultate'],
]
for row_data in api_data:
add_table_row(table, row_data)
doc.add_heading('4.4. Functionalitati transversale', level=2)
add_bullet('Suport complet romana (RO) si engleza (EN) cu comutare din navbar; '
'dictionare JSON pentru toate textele interfetei', bold_prefix='Internationalizare (i18n): ')
add_bullet('Banner cookie consent cu 3 categorii (necesare, functionale, analitice); '
'preferintele se salveaza in browser si se respecta la navigare', bold_prefix='Cookie consent GDPR: ')
add_bullet('Generare automata sitemap.xml si robots.txt; meta tags SEO pe toate paginile; '
'Open Graph tags pentru partajare pe retele sociale', bold_prefix='SEO: ')
add_bullet('Navbar responsive cu meniu hamburger pe mobil; footer cu linkuri utile; '
'sidebar dashboard pe desktop cu navigare vizuala', bold_prefix='Componente layout: ')
add_bullet('Rutele din zona client sunt protejate prin middleware — '
'utilizatorii neautentificati sunt redirectionati automat la pagina de login', bold_prefix='Protectie rute: ')
doc.add_page_break()
# ═══════════════════════════════════════════════════════
# 5. ERP/CRM
# ═══════════════════════════════════════════════════════
doc.add_heading('5. Componenta ERP/CRM — Stadiu implementare', level=1)
add_para(
'Componenta ERP/CRM este construita pe ERPNext v15 (open-source, licenta GPL), '
'containerizata cu Docker si configurata specific pentru legislatia romaneasca si '
'nevoile proiectului. Intreaga configurare este automatizata prin scripturi Python '
'reproductibile.'
)
doc.add_heading('5.1. Infrastructura Docker', level=2)
add_para('Ref. CS: II.6.2 — ERP/CRM gazduita in cloud', italic=True, size=9, space_after=4)
add_para('Mediul ERP/CRM este compus din 7 containere Docker orchestrate prin Docker Compose:')
table = doc.add_table(rows=1, cols=3)
table.style = 'Light Grid Accent 1'
hdr = table.rows[0].cells
hdr[0].text = 'Serviciu'
hdr[1].text = 'Tehnologie'
hdr[2].text = 'Rol'
set_table_header_bg(table)
docker_data = [
['Aplicatie ERP', 'ERPNext v15 (Frappe)', 'Aplicatia principala ERP/CRM; interfata web de administrare; API REST'],
['Baza de date', 'MariaDB 10.11', 'Stocare persistenta; configurata cu InnoDB, UTF8MB4, buffer pool optimizat'],
['Cache', 'Redis (Alpine)', 'Cache pentru performanta — reduce timpul de raspuns al interfetei ERP'],
['Coada de taskuri', 'Redis (Alpine)', 'Coada pentru procesare asincrona (emailuri, taskuri background)'],
['Worker scurt', 'Frappe Worker', 'Procesare taskuri rapide (notificari, actualizari cache)'],
['Worker lung', 'Frappe Worker', 'Procesare taskuri de durata (rapoarte, import-uri, backup)'],
['Scheduler', 'Frappe Scheduler', 'Executie taskuri programate (facturare recurenta, cleanup)'],
]
for row_data in docker_data:
add_table_row(table, row_data)
add_para(
'Toate containerele comunica pe o retea Docker interna izolata. '
'Reverse proxy-ul Nginx gestioneaza traficul HTTP, serveste asseturile statice '
'si ofera suport WebSocket pentru interfata in timp real.',
size=10
)
doc.add_heading('5.2. Configurare contabilitate si facturare', level=2)
add_para('Ref. CS: II.5.3, II.5.4 — Facturare automata, Componenta ERP', italic=True, size=9, space_after=4)
add_bullet('Plan de conturi adaptat legislatiei romanesti (OMFP 1802/2014)', bold_prefix='Plan conturi: ')
add_bullet('TVA 19% Romania — aplicat automat pe net total la emitere factura', bold_prefix='Taxe: ')
add_bullet('Format personalizat cu serie anuala secventiala (format: PREFIX-YYYY-#####)', bold_prefix='Serie facturi: ')
add_bullet('Template PDF personalizat cu antet, date companie, detaliere articole, '
'subtotal + TVA + total, nota legala conform art. 106 alin. 2 din Legea 227/2015',
bold_prefix='Print Format custom: ')
add_bullet('Conturi de cheltuieli configurate: hosting, servicii software, marketing, comisioane plati',
bold_prefix='Conturi cheltuieli: ')
add_bullet('Evidenta furnizori principali (hosting EU, procesor plati, email tranzactional)',
bold_prefix='Furnizori: ')
doc.add_heading('5.3. Configurare CRM', level=2)
add_para('Ref. CS: II.5.5 — Componenta CRM', italic=True, size=9, space_after=4)
add_bullet('4 etape configurate: Lead → Calificat → Demo → Client', bold_prefix='Pipeline vanzari: ')
add_bullet('Surse configurate: formular contact website, pagina pricing, cerere demo',
bold_prefix='Surse lead-uri: ')
add_bullet('Campuri pentru sursa formular, pagina de origine si parametri UTM '
'(sursa, mediu, campanie) — permit analiza eficientei canalelor de marketing',
bold_prefix='Campuri custom pe Lead: ')
add_bullet('Campuri pentru ID utilizator in platforma IAM, rol activ (free/paid/enterprise), '
'plan activ si data activarii',
bold_prefix='Campuri custom pe Client: ')
doc.add_heading('5.4. DocTypes custom create', level=2)
add_para('Ref. CS: II.5.6 — Gestiune contractuala, II.8 — Audit', italic=True, size=9, space_after=4)
add_para(
'Pe langa configurarea modulelor standard ERPNext, au fost create 3 DocTypes (entitati de date) '
'custom, specifice nevoilor proiectului:'
)
add_para('Acord de Servicii (Service Agreement)', bold=True, size=10, space_after=2)
add_para(
'Se genereaza automat la activarea unui serviciu platit. Contine: clientul, planul selectat, '
'status-ul acordului (Draft / Acceptat / Expirat / Anulat), data si ora acceptarii, '
'versiunea termenilor, continutul HTML al acordului si legatura catre abonament. '
'Numerotare automata secventiala. Asigura trasabilitate completa (audit trail) conform cerintei II.5.6.',
size=10
)
add_para('Log Plati (Payment Log)', bold=True, size=10, space_after=2)
add_para(
'Inregistreaza fiecare eveniment de plata receptionat prin webhook de la procesorul de plati. '
'Contine: clientul, tipul evenimentului (plata reusita, esec, rambursare, modificare abonament), '
'status-ul, suma, moneda si datele brute ale webhook-ului in format JSON. '
'Permite audit complet al tranzactiilor financiare conform cerintei II.8.',
size=10
)
add_para('Continut Website / CMS (Website Content)', bold=True, size=10, space_after=2)
add_para(
'Permite administratorului sa editeze continutul tuturor paginilor publice direct din interfata ERP, '
'fara interventie tehnica. Fiecare intrare are: pagina (homepage, pricing, contact, despre, privacy, termeni), '
'cheie sectiune, ordine afisare, status activ/inactiv, continut in limba romana, continut in limba engleza, '
'imagine si date structurate suplimentare in format JSON. '
'In prezent sunt configurate 26 de intrari CMS corespunzand tuturor sectiunilor de pe paginile publice.',
size=10
)
doc.add_heading('5.5. Catalog servicii', level=2)
add_para(
'In ERP au fost create 14 articole (Item) corespunzand serviciilor platformei, '
'organizate pe 4 categorii de servicii x tipuri de media suportate:'
)
table = doc.add_table(rows=1, cols=2)
table.style = 'Light Grid Accent 1'
hdr = table.rows[0].cells
hdr[0].text = 'Categorie serviciu'
hdr[1].text = 'Tipuri media'
set_table_header_bg(table)
items_data = [
['Detectie tehnici de manipulare', 'Text, Imagine, Audio, Video'],
['Detectie AI si Deepfake', 'Text, Imagine, Audio, Video'],
['Verificare automata afirmatii (Fact-checking)', 'Text, Imagine, Audio, Video'],
['Evaluare sursa si domeniu', 'Text, URL'],
]
for row_data in items_data:
add_table_row(table, row_data)
doc.add_heading('5.6. Utilizator API dedicat', level=2)
add_para(
'Pentru comunicarea securizata intre website si ERP, a fost creat un utilizator API dedicat '
'cu rol custom ("Website Integration") si permisiuni limitate strict la operatiile necesare:',
size=10
)
add_bullet('Citire si scriere: Client, Lead, Factura, Abonament, Continut Website, Acord Servicii, Log Plati, Articol',
bold_prefix='Permisiuni read/write: ')
add_bullet('Doar citire: Companie, Conturi, Taxe, Template-uri email, Etape vanzari',
bold_prefix='Permisiuni read-only: ')
add_para(
'Autentificarea se face prin API Key + Secret, transmise exclusiv server-side (nu ajung in browser).',
size=10, italic=True
)
doc.add_page_break()
# ═══════════════════════════════════════════════════════
# 6. INTEGRARI
# ═══════════════════════════════════════════════════════
doc.add_heading('6. Integrari realizate si flux de date', level=1)
add_para('Ref. CS: II.6.3 — Integrari', italic=True, size=9, space_after=4)
doc.add_heading('6.1. Autentificare IAM (SSO / OpenID Connect)', level=2)
add_para(
'Website-ul este integrat cu componenta IAM a platformei existente prin protocolul OpenID Connect. '
'Fluxul de autentificare:',
size=10
)
add_bullet('Utilizatorul apasa butonul de login pe website')
add_bullet('Este redirectionat catre serverul IAM (pagina de autentificare centralizata)')
add_bullet('Dupa autentificare, primeste un token JWT (cu roluri din realm)')
add_bullet('Este redirectionat inapoi pe website cu sesiune activa')
add_bullet('Token-ul se reinnoieste automat (refresh token) fara interventie')
add_bullet('Middleware-ul Next.js protejeaza toate rutele din zona client')
add_para(
'Rolurile din IAM (free_tier, paid_tier, enterprise_tier) sunt mapate in sesiunea website '
'si utilizate pentru controlul accesului bazat pe roluri (RBAC).',
size=10
)
doc.add_heading('6.2. Procesor plati (Stripe)', level=2)
add_para(
'Integrarea cu procesorul de plati este realizata prin doua mecanisme complementare:',
size=10
)
add_para('Checkout Sessions', bold=True, size=10, space_after=2)
add_para(
'La initierea unei achizitii, API-ul website-ului creeaza o sesiune de checkout securizata '
'pe serverele procesorului de plati. Utilizatorul este redirectionat catre pagina de plata '
'(gazduita de procesorul de plati — conformitate PCI DSS) si, dupa plata reusita, '
'revine pe website pe pagina de confirmare.',
size=10
)
add_para('Webhook-uri', bold=True, size=10, space_after=2)
add_para(
'La confirmarea platii, procesorul de plati trimite un webhook (notificare HTTP) catre API-ul website-ului. '
'Webhook-ul declanseaza automat:',
size=10
)
add_bullet('Crearea sau identificarea clientului in ERP (pe baza ID-ului din IAM)')
add_bullet('Crearea facturii fiscale (Sales Invoice) cu articolele achizitionate si TVA')
add_bullet('Inregistrarea tranzactiei in Log Plati (Payment Log) pentru audit')
add_bullet('Crearea articolului in catalog daca nu exista deja')
add_para(
'Au fost configurate 14 produse in procesorul de plati, corespunzand celor 14 articole din ERP, '
'cu preturi in RON.',
size=10
)
doc.add_heading('6.3. Website ↔ ERP/CRM (API REST)', level=2)
add_para(
'Comunicarea intre website si ERP se realizeaza prin API REST, cu un proxy server-side '
'implementat in Next.js. Aceasta abordare ofera doua avantaje majore:',
size=10
)
add_bullet('Credentialele API nu sunt niciodata expuse in browserul utilizatorului')
add_bullet('Website-ul poate adauga logica intermediara (validare, transformare date, caching)')
add_para('Operatii implementate:', bold=True, size=10, space_after=2)
add_bullet('Citire continut CMS (Homepage, Servicii, Despre, Privacy, Termeni) → cache 60 secunde')
add_bullet('Creare Lead din formular contact (cu sursa, pagina, UTM)')
add_bullet('Citire facturi client din ERP + download PDF')
add_bullet('Citire/actualizare date profil client')
add_bullet('Creare Acord de Servicii la checkout')
add_bullet('Creare factura si client la confirmare plata')
doc.add_heading('6.4. API Platforma DiDi (Analize)', level=2)
add_para(
'Website-ul este integrat cu API-ul platformei DiDi pentru submisia si preluarea analizelor. '
'Integrarea acopera 4 endpoint-uri corespunzand celor 4 categorii de servicii:',
size=10
)
table = doc.add_table(rows=1, cols=2)
table.style = 'Light Grid Accent 1'
hdr = table.rows[0].cells
hdr[0].text = 'Serviciu'
hdr[1].text = 'Endpoint API'
set_table_header_bg(table)
api_didi = [
['Detectie tehnici de manipulare', '/v3/techniques/analyze'],
['Detectie AI si deepfake', '/v3/ai-tampered/analyze'],
['Verificare afirmatii', '/v3/claims/analyze'],
['Evaluare sursa/domeniu', '/v3/domain/analyze'],
]
for row_data in api_didi:
add_table_row(table, row_data)
add_para(
'Autentificarea catre API-ul platformei se face cu Bearer token (obtinut din sesiunea IAM). '
'Rezultatele analizelor includ: scor de risc, nivel de incredere, tehnici de manipulare detectate, '
'verificarea afirmatiilor (adevarat/fals/neverificat), probabilitate de generare AI, '
'scor de credibilitate domeniu si factori de viralitate.',
size=10
)
doc.add_page_break()
# ═══════════════════════════════════════════════════════
# 7. SECURITATE
# ═══════════════════════════════════════════════════════
doc.add_heading('7. Securitate si protectia datelor (GDPR)', level=1)
add_para('Ref. CS: II.8 — Securitate cibernetica si protectia datelor', italic=True, size=9, space_after=4)
doc.add_heading('7.1. Masuri de securitate implementate', level=2)
table = doc.add_table(rows=1, cols=3)
table.style = 'Light Grid Accent 1'
hdr = table.rows[0].cells
hdr[0].text = 'Categorie'
hdr[1].text = 'Masura'
hdr[2].text = 'Implementare'
set_table_header_bg(table)
sec_data = [
['Autentificare', 'SSO / OpenID Connect', 'Autentificare centralizata prin IAM; token JWT cu expirare si refresh automat'],
['Autorizare', 'RBAC (Role-Based Access Control)', 'Roluri mapate din IAM: free_tier, paid_tier, enterprise_tier; middleware pe rute protejate'],
['Transport', 'HTTPS obligatoriu', 'Certificat SSL; comunicatie criptata TLS 1.2+ pe toate endpoint-urile'],
['API Security', 'Proxy server-side', 'Credentialele ERP nu ajung in browser; validare pe server a tuturor cererilor'],
['Plati', 'PCI DSS compliance', 'Datele cardurilor nu tranziteaza serverele noastre — plata se face pe pagina procesorului de plati'],
['Webhook-uri', 'Validare semnatura', 'Fiecare webhook de la procesorul de plati este validat prin semnatura criptografica'],
['Sesiuni', 'JWT + Refresh Token', 'Token-uri cu expirare scurta, reinnoite automat; sesiune invalidata la logout'],
['API ERP', 'Utilizator dedicat cu permisiuni minime', 'Principiul least privilege: acces doar la DocType-urile necesare, fara acces admin'],
]
for row_data in sec_data:
add_table_row(table, row_data)
doc.add_heading('7.2. Conformitate GDPR', level=2)
add_bullet('Pagina completa de politica de confidentialitate, editabila din CMS',
bold_prefix='Politica confidentialitate: ')
add_bullet('Pagina completa de termeni si conditii, editabila din CMS',
bold_prefix='Termeni si conditii: ')
add_bullet('Banner cookie consent cu 3 categorii: necesare (always on), functionale, analitice; '
'preferintele se salveaza si se respecta',
bold_prefix='Cookie consent: ')
add_bullet('Buton "Exporta datele mele" in pagina de profil din dashboard (format CSV)',
bold_prefix='Drept de portabilitate: ')
add_bullet('Buton "Solicita stergerea contului" in pagina de profil din dashboard',
bold_prefix='Drept la stergere: ')
add_bullet('Checkbox obligatoriu de acceptare a termenilor in fluxul de checkout, '
'cu inregistrare data, ora si versiune termeni',
bold_prefix='Consimtamant explicit: ')
add_bullet('Toate datele sunt stocate pe servere localizate in Uniunea Europeana',
bold_prefix='Stocare exclusiv in EU: ')
doc.add_heading('7.3. Audit si trasabilitate', level=2)
add_para(
'Toate actiunile critice sunt inregistrate si trasabile:',
size=10
)
add_bullet('Fiecare tranzactie financiara este logata in DocType-ul Payment Log cu date brute webhook')
add_bullet('Fiecare acord de servicii inregistreaza data acceptarii, versiunea termenilor')
add_bullet('Lead-urile captate inregistreaza sursa, pagina de origine si parametri UTM')
add_bullet('ERPNext ofera nativ audit trail pe toate modificarile de documente (Version Log)')
doc.add_page_break()
# ═══════════════════════════════════════════════════════
# 8. STADIU GENERAL
# ═══════════════════════════════════════════════════════
doc.add_heading('8. Stadiu general si pasi urmatori', level=1)
doc.add_heading('8.1. Ce este implementat si functional', level=2)
add_bullet('Infrastructura Docker completa (7 containere ERP + website)')
add_bullet('Website cu 7 pagini publice, toate responsive si bilingve (RO/EN)')
add_bullet('Dashboard client cu 8 pagini functionale')
add_bullet('7 API routes server-side')
add_bullet('ERP configurat: contabilitate RO, TVA, serie facturi, print format PDF custom')
add_bullet('CRM configurat: pipeline 4 etape, campuri custom pe Lead si Client')
add_bullet('3 DocTypes custom: Acord Servicii, Log Plati, Continut Website (CMS)')
add_bullet('26 intrari CMS populate (toate paginile publice, RO + EN)')
add_bullet('14 articole servicii in catalog ERP')
add_bullet('Integrare IAM/SSO functionala (OpenID Connect)')
add_bullet('Integrare procesor plati functionala (checkout + webhook)')
add_bullet('Integrare API platforma DiDi pentru analize (4 endpoint-uri)')
add_bullet('Proxy API securizat (credentiale server-side)')
add_bullet('Cookie consent, sitemap.xml, robots.txt, SEO metadata')
add_bullet('i18n complet (romana + engleza)')
doc.add_heading('8.2. In curs de finalizare', level=2)
table = doc.add_table(rows=1, cols=3)
table.style = 'Light Grid Accent 1'
hdr = table.rows[0].cells
hdr[0].text = 'Element'
hdr[1].text = 'Stadiu'
hdr[2].text = 'Detalii'
set_table_header_bg(table)
wip_data = [
['Interfata admin ERP (workspace-uri)', 'In lucru', 'Organizare sidebar ERP cu sectiuni clare: Facturi, Clienti, CRM, Plati, CMS'],
['Email tranzactional (SendGrid)', 'De implementat', 'Trimitere automata factura PDF pe email la emitere; notificari expirare/esec'],
['Rapoarte ERP custom', 'De implementat', 'Dashboard financiar (MRR, churn), rapoarte CRM (conversie, timp mediu)'],
['Sincronizare credite/consum DiDi API', 'Partial', 'Endpoint-uri testate si functionale; necesita configurare acces retea'],
['Design si assets vizuale', 'De rafinat', 'Adaugare imagini, ilustratii, animatii pe paginile publice'],
['Testare WCAG 2.1 AA', 'De realizat', 'Audit automat (axe/Lighthouse) + verificare manuala navigare tastatura'],
['Testare securitate OWASP', 'De realizat', 'Scan vulnerabilitati, verificare CSRF/XSS/SQLi, rate limiting'],
['Testare cross-browser', 'De realizat', 'Chrome, Firefox, Safari, Edge — ultimele 2 versiuni; responsive pe 5 rezolutii'],
['Deployment productie', 'De realizat', 'VPS-uri cloud EU, Nginx, SSL, backup automat zilnic'],
['Documentatie si training', 'De realizat', 'Manual utilizare, documentatie API, ghid admin ERP, 2 sesiuni training'],
]
for row_data in wip_data:
add_table_row(table, row_data)
doc.add_page_break()
# ═══════════════════════════════════════════════════════
# 9. TABEL CONFORMITATE
# ═══════════════════════════════════════════════════════
doc.add_heading('9. Tabel de conformitate — stadiu curent', level=1)
add_para(
'Tabelul de mai jos prezinta stadiul de implementare pentru fiecare cerinta din Caietul de Sarcini '
'(Capitolul II.10). Stadiul "Implementat" indica functionalitatile livrate si testate; '
'"Partial" indica functionalitatile in curs; "Planificat" indica elementele programate.',
size=10
)
table = doc.add_table(rows=1, cols=4)
table.style = 'Light Grid Accent 1'
hdr = table.rows[0].cells
hdr[0].text = 'Nr.'
hdr[1].text = 'Cerinta CS'
hdr[2].text = 'Stadiu'
hdr[3].text = 'Observatii'
set_table_header_bg(table)
conf_data = [
['1', 'Website prezentare firma si servicii', 'Implementat', '7 pagini publice, continut dinamic din CMS'],
['2', 'Design responsive (desktop, tableta, mobil)', 'Implementat', 'Tailwind CSS, layout-uri responsive pe toate paginile'],
['3', 'Accesibilitate WCAG 2.1 nivel AA', 'Partial', 'Structura semantica implementata; audit formal planificat'],
['4', 'Modul e-commerce cu plati recurente', 'Implementat', 'Checkout integrat cu procesor plati; servicii one-time functionale'],
['5', 'Gestiune abonamente/servicii', 'Implementat', 'Planuri configurate in ERP; sincronizare cu IAM'],
['6', 'Facturare automata conform legislatiei RO', 'Implementat', 'Facturi automate la plata; serie, TVA 19%, PDF custom'],
['7', 'Componenta ERP — contabilitate si gestiune', 'Implementat', 'Plan conturi RO, conturi cheltuieli, furnizori, jurnale'],
['8', 'Componenta CRM — clienti si pipeline', 'Implementat', 'Pipeline 4 etape, lead capture din website, campuri custom'],
['9', 'Integrare IAM platforma (SSO)', 'Implementat', 'OpenID Connect functional; sesiune, token refresh, RBAC'],
['10', 'Sincronizare abonamente si credite API', 'Partial', 'Endpoint-uri testate; configurare acces retea in curs'],
['11', 'Integrare procesor de plati', 'Implementat', '14 produse configurate; checkout + webhook functional'],
['12', 'Integrare email tranzactional', 'Planificat', 'Template-uri email create in ERP; integrare SendGrid planificata'],
['13', 'Integrare website — ERP/CRM', 'Implementat', 'API REST proxy; facturare, lead-uri, CMS, facturi PDF'],
['14', 'Conformitate GDPR', 'Implementat', 'Cookie consent, privacy policy, export date, stergere cont'],
['15', 'Hosting in EU', 'Planificat', 'Infrastructura Docker pregatita; deployment pe VPS EU planificat'],
['16', 'Disponibilitate minim 99.5% uptime', 'Planificat', 'Se va valida in productie cu monitorizare'],
['17', 'Backup automat zilnic', 'Planificat', 'Procedura definita; implementare la deployment productie'],
['18', 'Documentatie utilizare si tehnica', 'Planificat', 'Manual utilizare, documentatie API, ghid admin'],
['19', 'Training echipa', 'Planificat', '2 sesiuni planificate (website + ERP), cu inregistrare video'],
['20', 'Garantie si suport minim 36 luni', 'Conform oferta', 'SLA definit: Critica 4h/24h, Majora 8h/3zile, Minora 24h/10zile'],
]
for row_data in conf_data:
add_table_row(table, row_data)
# ── Footer note ──
doc.add_paragraph()
p = doc.add_paragraph()
run = p.add_run(
'Acest document a fost generat ca raport intermediar de progres. '
'Versiunea finala a propunerii tehnice va include toate livrabilele complete, '
'rapoartele de testare si documentatia aferenta.'
)
run.font.size = Pt(9)
run.italic = True
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
# ── Save ──
output_path = r'C:\Users\avedev\Desktop\Achizitii TOP\livrabile\didi\Propunere_Tehnica_Raport_Intermediar.docx'
doc.save(output_path)
print(f'Document salvat: {output_path}')