#!/usr/bin/env python3 """Generate an A4 French/Arabic vehicle rental contract as a print-ready PDF. Usage: python generate_rental_contract.py Edit the CONTRACT dictionary below, or import generate_contract() in your app. Requires: weasyprint (pip install weasyprint) """ from __future__ import annotations from dataclasses import dataclass, asdict from pathlib import Path from typing import Any from html import escape from weasyprint import HTML OUTPUT_DIR = Path(__file__).resolve().parent CONTRACT: dict[str, Any] = { "company_name": "CAR LOCATION", "company_address": "Adresse de la société, Midelt, Maroc", "delivery_place": "Midelt", "return_place": "Midelt", "issued_at": "Midelt le 06/06/2021 11:35", "driver": { "first_name": "Prénom", "last_name": "Nom", "birth_date": "01/01/1990", "nationality": "Marocain", "address": "Adresse du client", "phone": "+212 6 00 00 00 00", "cin": "AB123456", "passport": "", "license": "P123456", "license_issued": "09/03/2004", }, "second_driver": None, "vehicle": { "make_model": "Dacia Dokker", "registration": "12345-A-6", "departure": "06/06/2021 11:35", "return": "08/06/2021 11:35", "duration": "2 jour(s)", "fuel_type": "Diesel", "extension": False, "extension_return": "", "spare_wheel": True, "radio_cd": False, "fuel_level": "1/4", # 0, 1/4, 1/2, 3/4 or 1 }, "notes": "", } def h(value: Any) -> str: return escape("" if value is None else str(value)) def check(value: bool) -> str: return "☒" if value else "☐" def field(label_fr: str, label_ar: str, value: Any) -> str: return ( '
' f'{h(label_fr)}' f'{h(value)}' f'{h(label_ar)}' '
' ) def driver_block(driver: dict[str, Any] | None, title: str) -> str: if not driver: return f'''
{h(title)}
Prénom: *****    AUCUN    ***** لا أحد
Nom: *****
Date de naissance: *****
N° de C.I.N.: *****
N° de Permis: *****
Délivrée le: *****
''' return f'''
{h(title)}
{field("Prénom:", "الاسم", driver.get("first_name"))} {field("Nom:", "النسب", driver.get("last_name"))} {field("Date de naissance:", "تاريخ الازدياد", driver.get("birth_date"))} {field("Nationalité:", "الجنسية", driver.get("nationality"))} {field("Adresse:", "العنوان", driver.get("address"))} {field("N° téléphone:", "رقم الهاتف", driver.get("phone"))} {field("N° de C.I.N.:", "رقم البطاقة الوطنية", driver.get("cin"))} {field("N° de Passeport:", "رقم جواز السفر", driver.get("passport"))} {field("N° de Permis:", "رقم رخصة السياقة", driver.get("license"))} {field("Délivrée le:", "سلمت بتاريخ", driver.get("license_issued"))}
''' def vehicle_diagram() -> str: return ''' R: RayuresB: Bosses E: ÉclatsC: Cassures ''' def render_html(data: dict[str, Any]) -> str: v = data["vehicle"] levels = ["0", "1/4", "1/2", "3/4", "1"] fuel_marks = "".join( f'
{x}{"X" if v.get("fuel_level") == x else ""}
' for x in levels ) extension_yes = bool(v.get("extension")) return f''' Contrat de location

Contrat de location

{h(data['issued_at'])}
Lieu de livraison :    {h(data['delivery_place'])} Lieu de reprise :    {h(data['return_place'])}
{driver_block(data.get('driver'), 'Conducteur I')} {driver_block(data.get('second_driver'), 'Conducteur II')}
Le client est seul responsable des délits, contraventions et infractions au code de la route.
Véhicule
Marque :{h(v.get('make_model'))}
Matricule :{h(v.get('registration'))}
Date de départ :{h(v.get('departure'))}
Date de retour :{h(v.get('return'))}
Durée de location :{h(v.get('duration'))}
Carburant :{h(v.get('fuel_type'))}
Prolongation :{check(extension_yes)} OUI    {check(not extension_yes)} NON
Retour en cas de prolongation :{h(v.get('extension_return'))}
Roue de secours
{check(bool(v.get('spare_wheel')))} OUI   {check(not bool(v.get('spare_wheel')))} NON
Poste radio et CD
{check(bool(v.get('radio_cd')))} OUI   {check(not bool(v.get('radio_cd')))} NON
Niveau carburant
{fuel_marks}
État général à la réception du client
{vehicle_diagram()}
Signature du client : lu et approuvé des conditions
Cachet et signature de la société
''' def generate_contract(data: dict[str, Any], output_pdf: str | Path, output_html: str | Path | None = None) -> Path: """Render contract data to a print-ready PDF and optionally save the HTML preview.""" output_pdf = Path(output_pdf) output_pdf.parent.mkdir(parents=True, exist_ok=True) html = render_html(data) if output_html: output_html = Path(output_html) output_html.write_text(html, encoding="utf-8") HTML(string=html, base_url=str(OUTPUT_DIR)).write_pdf(str(output_pdf)) return output_pdf if __name__ == "__main__": pdf = generate_contract( CONTRACT, OUTPUT_DIR / "rental_contract.pdf", OUTPUT_DIR / "rental_contract_preview.html", ) print(f"Generated: {pdf}")