PNA-Assistant / pna /export.py
Lincoln Gombedza
Launch PNA Assistant SaaS — Stripe + webhook + Docker
b7e98d4 unverified
"""
Export supervision notes and CPD logs to .docx format.
"""
from datetime import date
from io import BytesIO
HAS_DOCX = False
try:
from docx import Document
from docx.shared import Pt, RGBColor, Inches
from docx.enum.text import WD_ALIGN_PARAGRAPH
HAS_DOCX = True
except ImportError:
pass
def build_supervision_docx(note_text: str, nurse_name: str = "") -> bytes | None:
"""Build a formatted .docx supervision note."""
if not HAS_DOCX:
return None
doc = Document()
# Header
header_para = doc.add_paragraph()
header_para.alignment = WD_ALIGN_PARAGRAPH.CENTER
run = header_para.add_run("Professional Nurse Advocate Assistant")
run.bold = True
run.font.size = Pt(16)
run.font.color.rgb = RGBColor(0x1a, 0x24, 0x60) # brand navy
sub = doc.add_paragraph()
sub.alignment = WD_ALIGN_PARAGRAPH.CENTER
sub.add_run("A-EQUIP Model Supervision Note").italic = True
doc.add_paragraph()
# Metadata
meta = doc.add_paragraph()
meta.add_run(f"Date: ").bold = True
meta.add_run(date.today().strftime("%d %B %Y"))
if nurse_name:
nurse_p = doc.add_paragraph()
nurse_p.add_run("Name: ").bold = True
nurse_p.add_run(nurse_name)
doc.add_paragraph()
# Note content — parse markdown-ish headings
for line in note_text.split("\n"):
line = line.strip()
if not line:
doc.add_paragraph()
continue
if line.startswith("## "):
h = doc.add_heading(line[3:], level=2)
for run in h.runs:
run.font.color.rgb = RGBColor(0x1a, 0x24, 0x60)
elif line.startswith("### "):
h = doc.add_heading(line[4:], level=3)
for run in h.runs:
run.font.color.rgb = RGBColor(0x0d, 0x94, 0x88) # teal
elif line.startswith("**") and line.endswith("**"):
p = doc.add_paragraph()
p.add_run(line.strip("**")).bold = True
elif line.startswith("- "):
doc.add_paragraph(line[2:], style="List Bullet")
else:
doc.add_paragraph(line)
# Footer
doc.add_paragraph()
footer = doc.add_paragraph()
footer.alignment = WD_ALIGN_PARAGRAPH.CENTER
footer_run = footer.add_run(
"Contains public sector information licensed under the Open Government Licence v3.0 — NHS England.\n"
"This tool supports but does not replace clinical judgment or formal supervision documentation."
)
footer_run.font.size = Pt(8)
footer_run.font.color.rgb = RGBColor(0x6b, 0x72, 0x80)
footer_run.italic = True
buf = BytesIO()
doc.save(buf)
return buf.getvalue()
def build_cpd_docx(note_text: str, nurse_name: str = "", hours: float = 1.0) -> bytes | None:
"""Build NMC revalidation CPD record."""
if not HAS_DOCX:
return None
doc = Document()
header_para = doc.add_paragraph()
header_para.alignment = WD_ALIGN_PARAGRAPH.CENTER
run = header_para.add_run("NMC Revalidation — CPD Record")
run.bold = True
run.font.size = Pt(16)
run.font.color.rgb = RGBColor(0x1a, 0x24, 0x60)
doc.add_paragraph()
fields = [
("Date", date.today().strftime("%d %B %Y")),
("Name", nurse_name or "___________________"),
("NMC PIN", "___________________"),
("Activity Type", "Restorative Clinical Supervision (A-EQUIP Model)"),
("Hours", f"{hours:.1f}"),
("Method", "1:1 Supervision with AI-assisted preparation/reflection"),
("NMC Standards",
"Platform 1 (Accountable professional), Platform 6 (Safety & quality)"),
]
for label, value in fields:
p = doc.add_paragraph()
p.add_run(f"{label}: ").bold = True
p.add_run(value)
doc.add_paragraph()
doc.add_heading("Supervision Summary", level=2)
for line in note_text.split("\n"):
line = line.strip()
if not line:
continue
if line.startswith("### "):
doc.add_heading(line[4:], level=3)
elif line.startswith("- "):
doc.add_paragraph(line[2:], style="List Bullet")
elif not line.startswith("## ") and not line.startswith("**Date"):
doc.add_paragraph(line)
doc.add_paragraph()
sig_p = doc.add_paragraph()
sig_p.add_run("Nurse signature: ").bold = True
sig_p.add_run("_________________________")
conf_p = doc.add_paragraph()
conf_p.add_run("Confirming PNA/Supervisor: ").bold = True
conf_p.add_run("_________________________")
doc.add_paragraph()
footer = doc.add_paragraph()
footer.alignment = WD_ALIGN_PARAGRAPH.CENTER
fr = footer.add_run(
"Contains public sector information licensed under the Open Government Licence v3.0 — NHS England."
)
fr.font.size = Pt(8)
fr.italic = True
buf = BytesIO()
doc.save(buf)
return buf.getvalue()