Poštár

Dokumentace API

Ukázka: send_isdoc_batch.py

Tento skript ukazuje robustní dávkový odesílač dokumentů ISDOC: ověří se pomocí API přihlašovacích údajů, odešle každý soubor ze vstupní složky, zjišťuje stav doručení a úspěšně odeslané soubory přesune do archivní složky.

Co tato ukázka předvádí

  • Tokenová autentizace pomocí klientských přihlašovacích údajů.
  • Dávkové zpracování všech souborů .isdoc v adresáři.
  • Zjišťování stavu s obsluhou časového limitu a kontrolou stavu doručení.
  • Strukturovaný přehled výsledků pro každý soubor a přesun souboru po odeslání.

send_isdoc_batch.py

Naformátovaný a zvýrazněný zdrojový kód Pythonu

Stáhnout soubor
#!/usr/bin/env python3
import json
import os
import shutil
import sys
import urllib.error
import urllib.request
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Optional


API_BASE_URL  = os.getenv("PEPPOS_BASE_URL",              "https://sandbox.pepposh.eu")
CLIENT_ID     = os.getenv("PEPPOS_CLIENT_ID",             "YOUR-API-KEY")
CLIENT_SECRET = os.getenv("PEPPOS_CLIENT_SECRET",         "YOUR-API-SECRET")

INPUT_DIR = Path(os.getenv("ISDOC_INPUT_DIR", "isdoc"))
SENT_DIR = Path(os.getenv("ISDOC_SENT_DIR", "isdoc_sent"))

@dataclass
class SendResult:
    filename: str
    sent: bool
    moved_to: Optional[str]
    document_id: Optional[str]
    final_status: Optional[str]
    queue_status: Optional[str]
    message: str


def http_json(
    method: str,
    url: str,
    headers: Optional[dict[str, str]] = None,
    payload: Optional[str] = None,
) -> tuple[int, Any]:
    req_headers = {"Accept": "application/json"}
    if headers:
        req_headers.update(headers)

    data: Optional[bytes] = None
    if payload is not None:
        if isinstance(payload, str):
            data = payload.encode("utf-8")
            req_headers["Content-Type"] = "application/xml"
        else:
            data = json.dumps(payload).encode("utf-8")
            req_headers["Content-Type"] = "application/json"

    req = urllib.request.Request(url, data=data, method=method, headers=req_headers)
    try:
        with urllib.request.urlopen(req, timeout=30) as resp:
            raw = resp.read().decode("utf-8", errors="replace")
            return resp.getcode(), (json.loads(raw) if raw else {})
    except urllib.error.HTTPError as e:
        body = e.read().decode("utf-8", errors="replace")
        try:
            parsed = json.loads(body) if body else {}
        except json.JSONDecodeError:
            parsed = {"raw": body}
        return e.code, parsed


def get_token() -> str:
    if not CLIENT_ID or not CLIENT_SECRET:
        raise RuntimeError("Missing PEPPOS_CLIENT_ID or PEPPOS_CLIENT_SECRET environment variable.")

    status, body = http_json(
        "POST",
        f"{API_BASE_URL}/api/auth/token",
        payload={
            "client_id": CLIENT_ID,
            "client_secret": CLIENT_SECRET,
            "grant_type": "client_credentials",
        },
    )
    if status != 200 or "access_token" not in body:
        raise RuntimeError(f"Token request failed ({status}): {json.dumps(body, ensure_ascii=False)}")
    return body["access_token"]


def send_isdoc_document(token: str, isdoc_path: Path) -> tuple[Optional[str], dict[str, Any]]:
    content = isdoc_path.read_text(encoding="utf-8")
    status, body = http_json(
        "POST",
        f"{API_BASE_URL}/api/documents/send/as/isdoc?wait-for-result",
        headers={
            "Authorization": f"Bearer {token}",
        },
        payload=content,
    )

    if status not in (200, 201, 202):
        return None, {"http_status": status, "response": body}

    document_id = body.get("data", {}).get("documentId") if isinstance(body, dict) else None
    return document_id, {"http_status": status, "response": body}

def main() -> int:
    if not INPUT_DIR.exists():
        print(f"Input directory not found: {INPUT_DIR}")
        return 1

    SENT_DIR.mkdir(parents=True, exist_ok=True)

    try:
        token = get_token()
    except Exception as e:
        print(f"Token error: {e}")
        return 1

    files = sorted(p for p in INPUT_DIR.glob("*.isdoc") if p.is_file())
    if not files:
        print(f"No .isdoc files found in {INPUT_DIR}")
        return 0

    results: list[SendResult] = []

    for path in files:
        try:
            document_id, send_meta = send_isdoc_document(token, path)
            if not document_id:
                results.append(
                    SendResult(
                        filename=path.name,
                        sent=False,
                        moved_to=None,
                        document_id=None,
                        final_status=None,
                        queue_status=None,
                        message=f"Send failed: {json.dumps(send_meta, ensure_ascii=False)}",
                    )
                )
                continue

            status_body = send_meta.get("response") if isinstance(send_meta, dict) else {}
            final_status = status_body.get("status") if isinstance(status_body, dict) else None
            queue_status = None
            message_status = None
            if isinstance(status_body, dict):
                queue_status = (status_body.get("sendQueueStatus") or {}).get("status")
                message_status = status_body.get("messageStatus")

            is_sent = queue_status in {"sent", "delivered"} or message_status in {"sent", "delivered"}

            if is_sent:
                target = SENT_DIR / path.name
                shutil.move(str(path), str(target))
                results.append(
                    SendResult(
                        filename=path.name,
                        sent=True,
                        moved_to=str(target),
                        document_id=document_id,
                        final_status=final_status,
                        queue_status=queue_status,
                        message="Sent and moved.",
                    )
                )
            else:
                results.append(
                    SendResult(
                        filename=path.name,
                        sent=False,
                        moved_to=None,
                        document_id=document_id,
                        final_status=final_status,
                        queue_status=queue_status,
                        message=f"Not sent or delivery failed: {json.dumps(status_body, ensure_ascii=False)}",
                    )
                )
        except Exception as e:
            results.append(
                SendResult(
                    filename=path.name,
                    sent=False,
                    moved_to=None,
                    document_id=None,
                    final_status=None,
                    queue_status=None,
                    message=f"Error: {e}",
                )
            )

    print("\n=== Batch result ===")
    for r in results:
        print(
            json.dumps(
                {
                    "file": r.filename,
                    "sent": r.sent,
                    "moved_to": r.moved_to,
                    "document_id": r.document_id,
                    "final_status": r.final_status,
                    "queue_status": r.queue_status,
                    "message": r.message,
                },
                ensure_ascii=False,
            )
        )

    sent_count = sum(1 for r in results if r.sent)
    print(f"\nSent successfully: {sent_count}/{len(results)}")
    return 0 if sent_count == len(results) else 2


if __name__ == "__main__":
    sys.exit(main())