Skip to content

Basic Report

This example shows how you can use custom operations to generate a basic report on a document and attach that report to the document.

The example uses python-docx ⧉ to generate a Word file. To install the library in your Function, you need to add it to the requirements.txt:

contactsoftware-functions
python-docx
import os
import tempfile
from datetime import datetime

import requests
from docx import Document as DocxDocument

from csfunctions import MetaData, Service
from csfunctions.events import CustomOperationDocumentEvent
from csfunctions.objects import Document


def simple_report(metadata: MetaData, event: CustomOperationDocumentEvent, service: Service):
    """
    Generates a simple report for each document the custom operation is called on.
    The report contains basic information about the document and is saved as a new file
    named "myreport.docx" within the document.
    """

    for document in event.data.documents:
        # generate a report for each document
        report = _create_report(document, metadata)

        temp_file_path = None
        try:
            # we need to use a tempfile, because the rest of the filesystem is read-only
            with tempfile.NamedTemporaryFile(suffix=".docx", delete=False) as tmp:
                temp_file_path = tmp.name
            report.save(temp_file_path)

            # check if the document already has a report file, so we can overwrite it
            file_name = "myreport.docx"
            existing_file = next((file for file in document.files if file.cdbf_name == file_name), None)

            with open(temp_file_path, "rb") as file_stream:
                if existing_file:
                    # overwrite the existing report file
                    # we set check_access to false to allow attaching reports to released documents
                    service.file_upload.upload_file_content(
                        file_object_id=existing_file.cdb_object_id, stream=file_stream, check_access=False
                    )
                else:
                    # create a new one
                    # we set check_access to false to allow attaching reports to released documents
                    service.file_upload.upload_new_file(
                        parent_object_id=document.cdb_object_id,  # type: ignore
                        filename=file_name,
                        stream=file_stream,
                        check_access=False,
                    )
        finally:
            if temp_file_path:
                # Clean up temp file
                os.unlink(temp_file_path)


def _fetch_person_name(persno: str, metadata: MetaData) -> str | None:
    """Fetches the name of a person given their personnel number via GraphQL."""
    graphql_url = str(metadata.db_service_url).rstrip("/") + "/graphql/v1"
    headers = {"Authorization": f"Bearer {metadata.service_token}"}

    query = f"""
      {{
        persons(personalnummer: \"{persno}\", max_rows: 1) {{
        name
        }}
       }}
    """
    response = requests.post(
        graphql_url,
        headers=headers,
        json={"query": query},
    )
    response.raise_for_status()
    data = response.json()
    persons = data["data"]["persons"]
    if persons:
        return persons[0]["name"]
    return None


def _create_report(document: Document, metadata: MetaData) -> DocxDocument:
    """Creates a simple Word report for the given document."""
    doc = DocxDocument()

    doc.add_heading("Simple Report", 0)

    report_time_string = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    doc.add_paragraph(f"Report generated on: {report_time_string}")

    # add some basic information about the document
    doc.add_heading("Document Information", level=1)
    doc.add_paragraph(f"Document ID: {document.z_nummer}@{document.z_index}")
    doc.add_paragraph(f"Title: {document.titel}")
    doc.add_paragraph(f"Created On: {document.cdb_cdate}")

    # Fetch the name of the person who created the document via GraphQL
    person_name = _fetch_person_name(document.cdb_cpersno, metadata)
    doc.add_paragraph(f"Created By: {person_name or document.cdb_cpersno}")

    return doc