Files
roleplay-contract/api/rpk-api/firm/contract/print/__init__.py

157 lines
5.4 KiB
Python

import datetime
import os
import base64
from uuid import UUID
from fastapi import APIRouter, HTTPException, Request, Depends
from fastapi.responses import HTMLResponse, FileResponse
from fastapi.templating import Jinja2Templates
from weasyprint import HTML, CSS
from weasyprint.text.fonts import FontConfiguration
from pathlib import Path
from firm.core.depends import get_tenant_registry
from firm.entity.models import Entity
from firm.template.models import ProvisionTemplate
from firm.contract.models import ContractDraft, Contract, ContractStatus, replace_variables_in_value
async def build_model(model):
parties = []
for p in model.parties:
party = {
"entity": await Entity.get(p.entity_id),
"part": p.part
}
if p.representative_id:
party['representative'] = await Entity.get(p.representative_id)
parties.append(party)
model.parties = parties
provisions = []
for p in model.provisions:
if p.provision.type == "template":
provision = await ProvisionTemplate.get(p.provision.provision_template_id)
else:
provision = p.provision
provision.title = replace_variables_in_value(model.variables, provision.title)
provision.body = replace_variables_in_value(model.variables, provision.body)
provisions.append(provision)
model.provisions = provisions
model = model.dict()
model['location'] = "Los Santos, SA"
model['date'] = datetime.date(1970, 1, 1)
model['lawyer'] = {'entity_data': {
"firstname": "prénom avocat",
"lastname": "nom avocat",
}}
return model
BASE_PATH = Path(__file__).resolve().parent
templates = Jinja2Templates(directory=str(BASE_PATH / "templates"))
async def render_print(root_url, contract):
template = templates.get_template("print.html")
return template.render({
"contract": contract,
"root_url": root_url
})
async def render_css(root_url, contract):
template = templates.get_template("styles.css")
return template.render({
"contract": contract,
"root_url": root_url
})
def retrieve_signature_png(filepath):
with open(filepath, "rb") as f:
b_content = f.read()
base64_utf8_str = base64.b64encode(b_content).decode('utf-8')
ext = filepath.split('.')[-1]
return f'data:image/{ext};base64,{base64_utf8_str}'
preview_router = APIRouter()
@preview_router.get("/draft/{draft_id}", response_class=HTMLResponse, tags=["Contract Draft"])
async def preview_draft(draft_id: str, reg=Depends(get_tenant_registry)) -> str:
draft = await build_model(await ContractDraft.get(reg.db, draft_id))
return await render_print('', draft)
@preview_router.get("/signature/{signature_id}", response_class=HTMLResponse, tags=["Signature"])
async def preview_contract_by_signature(signature_id: UUID, reg=Depends(get_tenant_registry)) -> str:
contract = await Contract.find_by_signature_id(reg.db, signature_id)
for p in contract.parties:
if p.signature_affixed:
p.signature_png = retrieve_signature_png(f'media/signatures/{p.signature_uuid}.png')
return await render_print('', contract)
@preview_router.get("/{contract_id}", response_class=HTMLResponse, tags=["Contract"])
async def preview_contract(contract_id: str, reg=Depends(get_tenant_registry)) -> str:
contract = await Contract.get(reg.db, contract_id)
for p in contract.parties:
if p.signature_affixed:
p.signature_png = retrieve_signature_png(f'media/signatures/{p.signature_uuid}.png')
return await render_print('', contract)
print_router = APIRouter()
@print_router.get("/pdf/{contract_id}", response_class=FileResponse, tags=["Contract"])
async def create_pdf(contract_id: str, reg=Depends(get_tenant_registry)) -> str:
contract = await Contract.get(reg.db, contract_id)
contract_path = "media/contracts/{}.pdf".format(contract_id)
if not os.path.isfile(contract_path):
if contract.status != ContractStatus.signed:
raise HTTPException(status_code=400, detail="Contract is not in a printable state")
for p in contract.parties:
signature_path = f'media/signatures/{p.signature_uuid}.png'
p.signature_png = retrieve_signature_png(signature_path)
# os.remove(signature_path)
font_config = FontConfiguration()
html = HTML(string=await render_print('http://nginx', contract))
css = CSS(string=await render_css('http://nginx', contract), font_config=font_config)
html.write_pdf(contract_path, stylesheets=[css], font_config=font_config)
await contract.update_status(reg.db, 'printed')
return FileResponse(
contract_path,
media_type="application/pdf",
filename=contract.label)
@print_router.get("/opengraph/{signature_id}", response_class=HTMLResponse, tags=["Signature"])
async def get_signature_opengraph(signature_id: str, request: Request, reg=Depends(get_tenant_registry)) -> str:
contract = await Contract.find_by_signature_id(reg.db, signature_id)
signature = contract.get_signature(signature_id)
template = templates.get_template("opengraph.html")
signatory = signature.representative.label if signature.representative else signature.entity.label
return template.render({
"signatory": signatory,
"title": contract.label,
"origin_url": f"{request.url.scheme}://{request.url.hostname}"
})