orchestrator

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 5, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

README

nexgate/orchestrator

the orchestrator module, member of GSF-nexgate ZUGFeRD family.


The orchestrator module is the central control unit and main entry point for Go applications using NexGate. It manages the high-level invoice generation lifecycle, transforms incoming JSON payloads into internal domain models, resolves multi-tenant configurations, and delegates processing to specialized writer engines.


Core Responsibilities

  • Configuration Management: Initializes system parameters (system.yaml) and tenant settings (seller.yaml).
  • Payload Validation & Parsing: Transforms incoming JSON payloads into the strongly typed MasterZugFerd domain structure.
  • Pipeline Execution: Coordinates rendering steps across engines (e.g., XML generation $\rightarrow$ PDF layout $\rightarrow$ ZUGFeRD PDF injection).
  • Engine Delegation: Uses api/writer factory logic to dynamically instantiate and invoke the required engines (native vs. container).

Module Directory Structure

orchestrator/
├── config/                  # Configuration loaders (system.yaml, seller.yaml, environment paths)
├── orchestrator.go          # Core Orchestrator struct, New/NewDefault constructors, and RunJsonJob entry point
├── generateBase.go          # Pipeline step: Pure XML / PAR generation
├── generatePdf.go           # Pipeline step: Layout PDF generation via LibreOffice
├── generateZugferd.go       # Pipeline step: Hybrid ZUGFeRD / Factur-X assembly via Mustang
└── orchestrator_test.go     # Comprehensive integration test suite (the reference example)


Architecture & Data Flow

The orchestrator abstracts the complex multi-step rendering process behind a clean, single-method API (RunJsonJob).

             +---------------------------------------+
             | Application Call: orch.RunJsonJob()  |
             +-------------------+-------------------+
                                 |
                                 v
             +---------------------------------------+
             | 1. Parse JSON -> MasterZugFerd Struct |
             +-------------------+-------------------+
                                 |
                                 v
             +---------------------------------------+
             | 2. Resolve Tenant & System Configs    |
             +-------------------+-------------------+
                                 |
           +---------------------+---------------------+
           |                     |                     |
           v                     v                     v
+--------------------+ +--------------------+ +--------------------+
| generateBase()     | | generatePdf()      | | generateZugferd()  |
| (XML Generation)   | | (LibreOffice PDF)  | | (Mustang Assembly) |
+----------+---------+ +----------+---------+ +----------+---------+
           |                     |                     |
           +---------------------+---------------------+
                                 |
                                 v
             +---------------------------------------+
             | 3. Finalize Output & Return OutputPath |
             +---------------------------------------+


Internal Pipeline Mechanics (generatePdf.go)

Each rendering step in the orchestrator follows a unified, declarative pattern:

  1. Configuration Resolution: Reads provider flags (native, container), timeouts, and engine paths from config.SystemParams.
  2. Writer Instantiation: Requests a concrete writer.Writer from the central registry via writer.CreateWriter().
  3. Environment Path Assembly: Constructs the required RenderInput paths (ArtefactsPath, RootPath, OutputPath) based on tenant settings.
  4. Execution: Calls pdfWriter.Render(), delegating the actual execution to the engine.

Implementation Pattern:

func (o *Orchestrator) generatePdf(rJob *job.RenderJob, finalize bool) (*writer.RenderOutput, error) {
    engine    := config.SystemParams.Engine.PdfEngine        // e.g., loEngine.odt
    provider  := config.SystemParams.Engine.PdfProvider      // "native" | "container"
    kind      := writer.PdfKind
    timeout   := config.SystemParams.Engine.CmdTimeout
    heartbeat := config.SystemParams.Engine.HeartbeatFrequency

    // 1. Obtain registered writer instance
    pdfWriter, err := writer.CreateWriter(kind, provider, engine, timeout, heartbeat)
    if err != nil {
        return nil, err
    }

    // 2. Prepare paths within the nexgate-env structure
    renderInput := writer.RenderInput{
        OttPath:       o.ZugferdMaster.Paths.OTTfile,
        ArtefactsPath: filepath.Join(config.SellerParams.SellerRoot, "data", "artefacts"),
        RootPath:      filepath.Join(config.SellerParams.SellerRoot, "data", "pdfs"),
        OutputPath:    filepath.Join(config.SellerParams.SellerRoot, "outputs", o.ZugferdMaster.Invoice.InvoiceID+".pdf"),
    }

    // 3. Delegate rendering
    return pdfWriter.Render(o.ctx, rJob, &renderInput, finalize)
}


Job Payload Specification (invoice.json)

The orchestrator consumes JSON payloads to generate invoices. The payload consists of three main top-level sections:

  1. mandant (optional): Defines the tenant/seller context. If omitted, the default tenant or environment configuration is used.
  2. options (optional): Controls rendering behavior, target queue, custom template overrides, and file attachments. If queue is omitted, it defaults to full ZUGFeRD processing.
  3. invoice (required): The core business data (buyer, line items, VAT breakdown, totals, and payment terms).

Payload Structure Overview

Section Mandatory? Description
mandant.seller No Overrides the target tenant folder (e.g., "testSeller" $\rightarrow$ env/sellers/testSeller).
options.queue No Target pipeline queue ("pdf", "facturx", "base"). Defaults to "zugferd".
options.template No Path to a custom LibreOffice template (.ott). Overrides seller default.
options.attachments No Array of file paths to be embedded into the hybrid ZUGFeRD PDF.
invoice.currency Yes ISO 4217 currency code (e.g., "EUR").
invoice.buyer Yes Buyer address and metadata.
invoice.items Yes Array of line items (quantity, net price, tax rates).
invoice.vats Yes Grouped VAT totals required for tax compliance.
invoice.totals Yes Calculated totals (line_total_amount, tax_total_amount, grand_total_amount).

Examples

Minimal Payload (min-invoice.json)

Demonstrates the bare minimum required to generate a valid invoice. Uses default seller settings and default ZUGFeRD pipeline:

{
  "invoice": {
    "currency": "EUR",
    "invoice_id": "RE-0814-min",
    "issue_date": "20260105",
    "service_date": "20260104",
    "buyer": {
      "id": "471115",
      "name1": "Franz Fröhlich AG",
      "street": "Musterstrasse 64",
      "zip": "01221",
      "city": "Musterdorf",
      "country": "Deutschland"
    },
    "items": [
      {
        "pos": 1,
        "description": "Go Entwicklungsservice",
        "quantity": 10.5,
        "unit": "Stunde",
        "net_price": 95.00,
        "line_total": 997.5,
        "tax_rate": 19
      }
    ],
    "vats": [
      {
        "pos": 1,
        "id": "S",
        "description": "USt",
        "vat_base": 997.50,
        "vat_amount": 189.53,
        "tax_rate": 19
      }
    ],
    "totals": {
      "line_total_amount": 997.50,
      "tax_total_amount": 189.53,
      "grand_total_amount": 1187.03
    }
  }
}

Advanced Payload (max-invoice.json)

Demonstrates multi-tenant override (mandant), custom template & PDF attachments (options), extended header notes, payment terms, and multi-VAT breakdowns:

{
  "mandant": {
    "seller": "testSeller"
  },
  "options": {
    "queue": "facturx",
    "template": "testdata/data/test_generate_max_template.ott",
    "attachments": [
      "testdata/data/test_attachment.png",
      "testdata/data/test_attachment.pdf"
    ]
  },
  "invoice": {
    "currency": "EUR",
    "invoice_id": "RE-0815-max",
    "issue_date": "20260105",
    "service_start": "20250104",
    "service_end": "20251231",
    "buyer_reference": "991-12345-76",
    "buyer": {
      "id": "471115",
      "name1": "Franz Fröhlich AG",
      "street": "Musterstrasse 64",
      "zip": "01221",
      "city": "Musterdorf",
      "country": "Österreich",
      "email": "bernd.buyer@email.com"
    },
    "payment_terms": {
      "due_description": "innerhalb von 3 Tagen mit 3% Skonto.",
      "due_date": "20260302"
    },
    "items": [ ... ],
    "vats": [ ... ],
    "totals": { ... }
  }
}

Further Variants: Additional JSON test fixtures covering edge cases (e.g. credit notes, foreign currencies, zero-tax exports) can be found in testdata/resources/.


API Entry Points

// 1. Initialize Orchestrator with default environment resolution
orch, err := orchestrator.NewDefault()

// 2. Execute a complete invoice rendering pipeline from a JSON byte stream
result, err := orch.RunJsonJob(jsonBytes)


Integration Testing

The orchestrator includes a comprehensive integration test suite designed to verify complex, real-world execution pipelines (including PDF/A conversion, document merging, attachment processing, and environment management).

Depending on your local system setup and requirements, you can choose between Native Engine Execution and full Containerized Pipeline Testing.


Test Suites Overview

Test Suite File Engine Modes Prerequisite Primary Use Case
orchestrator_test-suite_native_test.go NATIVE only Standard Go toolchain (No Docker/Podman required) Quick local development, lightweight test runs, initial onboarding
orchestrator_suite_test.go NATIVE & CONTAINER Active Container Runtime (Docker / Podman) Production parity tests, CI/CD pipelines, full container isolation testing

If you do not have Docker or Podman installed—or simply want a lightweight, fast local test run—use the native test suite.

# Run only the native integration test suite
go test -v -run TestOrchestratorSuiteNative ./...

Documentation

Index

Constants

View Source
const EnvRootKey = "NEXGATE_ENVROOT"

Variables

This section is empty.

Functions

This section is empty.

Types

type Orchestrator

type Orchestrator struct {
	ZugferdMaster *invoice.ZUGFeRDmaster
	// contains filtered or unexported fields
}

func New

func New(envRoot string) (*Orchestrator, error)

func NewDefault

func NewDefault() (*Orchestrator, error)

func (*Orchestrator) RunJsonJob

func (o *Orchestrator) RunJsonJob(json []byte) (renderOutput *writer.RenderOutput, err error)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL