106 lines
3.8 KiB
Python
106 lines
3.8 KiB
Python
from __future__ import annotations
|
|
|
|
from io import BytesIO
|
|
|
|
from docx import Document
|
|
from docx.shared import Pt, RGBColor
|
|
from docx.oxml import OxmlElement
|
|
from docx.oxml.ns import qn
|
|
|
|
from cv.services.dowload.pdf import ProfileSerializer
|
|
|
|
|
|
class DocxRenderer:
|
|
def __init__(self, ):
|
|
self.serializer = ProfileSerializer()
|
|
|
|
@staticmethod
|
|
def _add_divider(document: Document) -> None:
|
|
p = document.add_paragraph()
|
|
fmt = p.paragraph_format
|
|
fmt.space_before = Pt(6)
|
|
fmt.space_after = Pt(6)
|
|
p_elm = p._p
|
|
pPr = p_elm.get_or_add_pPr()
|
|
pBdr = OxmlElement("w:pBdr")
|
|
bottom = OxmlElement("w:bottom")
|
|
bottom.set(qn("w:val"), "single")
|
|
bottom.set(qn("w:sz"), "6")
|
|
bottom.set(qn("w:space"), "1")
|
|
bottom.set(qn("w:color"), "2a3347")
|
|
pBdr.append(bottom)
|
|
pPr.append(pBdr)
|
|
|
|
@staticmethod
|
|
def _month_year(dt) -> str:
|
|
ru_months = {
|
|
1: "январь", 2: "февраль", 3: "март", 4: "апрель",
|
|
5: "май", 6: "июнь", 7: "июль", 8: "август",
|
|
9: "сентябрь", 10: "октябрь", 11: "ноябрь", 12: "декабрь",
|
|
}
|
|
return f"{ru_months.get(dt.month, dt.strftime('%B')).capitalize()} {dt.year}"
|
|
|
|
def render(self, profile) -> BytesIO:
|
|
data = self.serializer.serialize(profile)
|
|
buf = BytesIO()
|
|
doc = Document()
|
|
# Заголовок
|
|
doc.core_properties.title = data["full_name"]
|
|
if data["role"]:
|
|
doc.core_properties.subject = data["role"]
|
|
doc.add_heading(data["full_name"], level=0)
|
|
if data["role"]:
|
|
doc.add_paragraph(data["role"])
|
|
if data["summary"]:
|
|
doc.add_paragraph(data["summary"])
|
|
meta_parts: list[str] = []
|
|
if data["location"]:
|
|
meta_parts.append(data["location"])
|
|
if data["languages"]:
|
|
meta_parts.append("Языки: " + ", ".join(data["languages"]))
|
|
if meta_parts:
|
|
doc.add_paragraph(" • ".join(meta_parts))
|
|
|
|
# Контакты
|
|
doc.add_heading("Контакты", level=1)
|
|
contacts = data["contacts"]
|
|
if contacts.get("email"):
|
|
doc.add_paragraph(f"Email: {contacts['email']}")
|
|
if contacts.get("phone"):
|
|
doc.add_paragraph(f"Телефон: {contacts['phone']}")
|
|
if contacts.get("telegram"):
|
|
doc.add_paragraph(f"Telegram: {contacts['telegram']}")
|
|
|
|
# Опыт
|
|
doc.add_heading("Опыт работы", level=1)
|
|
for i, e in enumerate(data["experience"]):
|
|
if i:
|
|
self._add_divider(doc)
|
|
period = f"{self._month_year(e.start_date)} — {(self._month_year(e.end_date) if e.end_date else 'настоящее время')}"
|
|
p_company = doc.add_paragraph()
|
|
run_company = p_company.add_run(e.company)
|
|
run_company.bold = True
|
|
run_company.font.underline = True
|
|
run_company.font.color.rgb = RGBColor(0x2A, 0x33, 0x47)
|
|
p_period = doc.add_paragraph(period)
|
|
for r in p_period.runs:
|
|
r.font.color.rgb = RGBColor(0x99, 0xA2, 0xB2)
|
|
if e.summary:
|
|
doc.add_paragraph(e.summary)
|
|
for a in (e.achievements or []):
|
|
if a:
|
|
doc.add_paragraph(a, style="List Bullet")
|
|
if e.tech:
|
|
doc.add_paragraph("Технологии: " + ", ".join([t for t in e.tech if t]))
|
|
|
|
# Навыки
|
|
doc.add_heading("Навыки", level=1)
|
|
for g in data["skills_map"]:
|
|
if g.items:
|
|
doc.add_paragraph(f"{g.group}: " + ", ".join([i for i in g.items if i]))
|
|
|
|
doc.save(buf)
|
|
buf.seek(0)
|
|
return buf
|
|
|