Skip to content

Code-Beispiele: Mit und ohne MCP

Die folgenden Beispiele zeigen denselben Anwendungsfall – einmal mit einer Standard-KI (ohne MCP) und einmal mit unserem MCP. Die Unterschiede in Syntax, Funktionen und Code-Qualität sind deutlich sichtbar.

Promt für einen einfachen Button-Code:

Ich habe in Ninox eine Tabelle "Aufträge" und dazu eine Tabelle "Auftragspositionen" (ein Auftrag hat mehrere Positionen). Auf dem Auftrag soll ein Button sein. Wenn ich draufklicke, soll folgendes passieren:

Es sollen nur die Positionen genommen werden, die den Status "Offen" haben. Für diese offenen Positionen soll die Summe aus Menge mal Stückpreis ausgerechnet werden und das Ergebnis in das Feld "Gesamtsumme" im Auftrag geschrieben werden. Außerdem soll ein Dialog aufgehen, in dem steht, wie viele offene Positionen es sind. Wenn es gar keine offenen Positionen gibt, soll eine Meldung erscheinen "Keine offenen Positionen".

Bitte schreibe mir das Ninox-Skript dafür.

Ergebnis ohne MCP

json
// Ninox-Skript für Button auf dem Auftrag
// Voraussetzung: Tabelle "Auftragspositionen" hat Felder: Auftrag (Referenz auf Aufträge), Status, Menge, Stückpreis
// Auftrag hat Feld: Gesamtsumme

let a := this;
let offenePositionen := select Auftragspositionen where Auftrag = a and text(Status) = "Offen"; 
let anzahl := count(offenePositionen);

if anzahl = 0 then
	set(this, "Gesamtsumme", 0); 
	alert("Keine offenen Positionen")
else
	let gesamtsumme := 0;
	for p in offenePositionen do
		gesamtsumme := gesamtsumme + (p.Menge * p.Stückpreis)
	end;
	set(this, "Gesamtsumme", gesamtsumme); 
	alert(string(anzahl) + " Positionen")
end
json
let offenePositionen := (select Auftragspositionen where Auftrag = this and Status = "Offen");	
let anzahl := count(offenePositionen);
if anzahl > 0 then
	let summe := sum(offenePositionen, Menge * Stückpreis);	
	Gesamtsumme := summe;
	alert(text(anzahl) + " offene Position(en)")
else
	Gesamtsumme := 0;
	alert("Keine offenen Positionen")
end

Fehler:

  • Kommentieren mit // führen zu Syntaxfehlern
  • Nutzt set() statt :=, um Felder zu beschreiben
  • Syntax sum([nid], number) ist falsch
  • Die Auftragspositionen-Rückverknüpfung könnte direkt ausgelesen werden. select ist nicht notwendig und ineffizient.

Ergebnis mit MCP

json
let my := this;
let offene := my.'Auftragspositionen'[text(Status) = "Offen"];
if cnt(offene) > 0 then
    let summe := sum(for i in offene do i.Menge * i.'Stückpreis' end);
    'Gesamtsumme' := summe;
    dialog("Offene Positionen", "Es gibt " + text(cnt(offene)) + " offene Position(en).", ["OK"])
else
    alert("Keine offenen Positionen")
end
json
let offenePos := Auftragspositionen[Status = "Offen"];
let anzahl := cnt(offenePos);
if anzahl > 0 then
    let summe := sum(offenePos.(Menge * 'Stückpreis'));
    Gesamtsumme := summe;
    alert("Es gibt " + text(anzahl) + " offene Position(en).")
else
    alert("Keine offenen Positionen")
end

Promt 2:

Ich habe eine Projektstundenerfassung, von der ich alle offenen Stunden (=noch keine Rechnungsposition verknüpft) in Rechnungen übernehmen möchte. Die Rechnungen muss ich pro Unternehmen erstellen. Die Projekte gehören jeweils zu einem Unternehmen.

Die Projektstunden sollen außerdem noch wie folgt gefiltert werden:

  • Keine als gelöscht markierten Stunden
  • Nur innerhalb von meinem Abrechnungszeitraum ('Startdatum', 'Enddatum')
  • Stunden, wo stornierte Rechnungen verknüpft sind, müssen mit aufgenommen werden
  • Stunden, die zum selben Projekt gehören, müssen in einer Rechnungsposition zusammengerechnet werden. Der Positionstitel soll der Projektname sein

Schreibe mir den Code für Ninox. Das Rechnungsdatum soll automatisch gesetzt und die Rechnung mit dem Unternehmen verknüpft werden.

Ergebnis ohne MCP

json
// =============================================================================
// Ninox: Rechnungen aus offenen Projektstunden erstellen (pro Unternehmen)
// =============================================================================
//
// VORAUSSETZUNG:
// - Skript an einen Button binden (z.B. auf einem Abrechnungszeitraum-Datensatz
//   oder auf einer Seite mit Startdatum/Enddatum).
// - Tabellen- und Feldnamen ggf. an Ihre Datenbank anpassen (siehe Anpassungen unten).
//
// LOGIK:
// - Nur Stunden: nicht gelöscht, im Abrechnungszeitraum, ohne Rechnungsposition
//   ODER mit stornierter Rechnung verknüpft.
// - Pro Unternehmen eine Rechnung (Rechnungsdatum = heute, Unternehmen verknüpft).
// - Pro Projekt eine Rechnungsposition (Titel = Projektname, Menge = Summe der Stunden).
// - Alle betroffenen Stunden werden mit der neuen Rechnungsposition verknüpft.
//
// ANPASSUNGEN (Tabellen- und Feldnamen):
// - Projektstundenerfassung  → Ihre Tabelle für Projektstunden
// - Gelöscht                 → Boolean „als gelöscht markiert“
// - Datum                     → Datum der Stunde
// - Rechnungsposition        → Referenz von Stunde auf Rechnungsposition (optional)
// - Projekt                   → Referenz von Stunde auf Projekt
// - Rechnungen                → Tabelle Rechnungen
// - Rechnungsdatum, Unternehmen → Felder auf Rechnung
// - Rechnungspositionen       → Tabelle Rechnungspositionen
// - Rechnung, Titel, Menge    → Felder auf Rechnungsposition (Menge = Stunden)
// - Rechnung.Storniert        → Boolean auf Rechnung
// - Projekt.Unternehmen       → Referenz Projekt → Unternehmen
// - Projekt.Name (oder Projektname) → Anzeigename des Projekts
// - Stunden (oder Anzahl, etc.)    → Zahlenfeld mit der erfassten Stundenzahl
// =============================================================================

// Abrechnungszeitraum: von einem Datensatz "this" (z.B. Abrechnungszeitraum).
// Alternative ohne "this": feste Werte oder Dialog, z.B.:
//   let startDatum := date(2025, 3, 1);
//   let endDatum := date(2025, 3, 31);
//   let startDatum := dialog("Startdatum (YYYY-MM-DD)");
//   let endDatum := dialog("Enddatum (YYYY-MM-DD)");
let startDatum := this.Startdatum;
let endDatum := this.Enddatum;

// 1) Offene Stunden: nicht gelöscht, im Zeitraum, keine Rechnungsposition ODER Rechnung storniert
// Hinweis: Falls "Rechnungsposition'.'Rechnung'.'Storniert" in where nicht unterstützt wird,
// zuerst nur Zeitraum + Gelöscht filtern, danach in einer Schleife die Storniert-Bedingung prüfen.
let offeneStunden := select 'Projektstundenerfassung' where
  'Gelöscht' != true
  and 'Datum' >= startDatum
  and 'Datum' <= endDatum
  and (
	'Rechnungsposition' = null
	or 'Rechnungsposition'.'Rechnung'.'Storniert' = true
  );

// FALLBACK: Wenn die obige where-Bedingung mit Storniert in Ihrer Ninox-Version
// fehlschlägt, ersetzen Sie den select durch diese zwei Zeilen und filtern danach:
//   let alleImZeitraum := select 'Projektstundenerfassung' where 'Gelöscht' != true and 'Datum' >= startDatum and 'Datum' <= endDatum;
//   let offeneStunden := []; for s in alleImZeitraum do if s.('Rechnungsposition') = null or (s.('Rechnungsposition').('Rechnung').('Storniert') = true) then offeneStunden := concat(offeneStunden, [s]) end end;

// Eindeutige Unternehmen aus diesen Stunden (über Projekt)
let companies := [];
for s in offeneStunden do
  let c := s.Projekt.Unternehmen;
  if c != null and not contains(companies, c) then
	companies := concat(companies, [c]) 
  end
end;

// Pro Unternehmen eine Rechnung erstellen
for unternehmen in companies do
  let rechnung := (create Rechnungen);
  rechnung.('Rechnungsdatum') := today();
  rechnung.('Unternehmen') := unternehmen;

  // Stunden dieses Unternehmens (Projekt gehört zum Unternehmen)
  let stundenUnternehmen := [];
  for s in offeneStunden do
	if s.Projekt != null and s.Projekt.Unternehmen = unternehmen then
	  stundenUnternehmen := concat(stundenUnternehmen, [s]) 
	end
  end;

  // Eindeutige Projekte innerhalb dieses Unternehmens
  let projekte := [];
  for s in stundenUnternehmen do
	let p := s.Projekt;
	if p != null and not contains(projekte, p) then
	  projekte := concat(projekte, [p]) 
	end
  end;

  // Pro Projekt eine Rechnungsposition (Titel = Projektname, Menge = Summe Stunden)
  for projekt in projekte do
	let stundenProjekt := [];
	for s in stundenUnternehmen do
	  if s.Projekt = projekt then
		stundenProjekt := concat(stundenProjekt, [s]) 
	  end
	end;

	let position := (create Rechnungspositionen);
	position.('Rechnung') := rechnung;
	position.('Titel') := projekt.('Name');   // oder 'Projektname' – Ihren Feldnamen verwenden
	position.('Menge') := sum(stundenProjekt.('Stunden'));  // Feldname für Stundenzahl anpassen

	// Alle Stunden dieser Position zuordnen (Verknüpfung setzen)
	for stunde in stundenProjekt do
	  stunde.('Rechnungsposition') := position
	end
  end
end
json
let vStart := Startdatum;
let vEnd := Enddatum;
let anzahl := 0;

do as server
	for u in (select Unternehmen) do
		let uStunden := (select Projektstunden where
			not Gelöscht and
			Datum >= vStart and
			Datum <= vEnd and
			Projekt.Unternehmen = u and
			(not Rechnungsposition or
			 Rechnungsposition.Rechnung.Status = "Storniert")
		);

		if count(uStunden) > 0 then
			let rechnung := (create Rechnungen);
			rechnung.(Rechnungsdatum := today());
			rechnung.(Unternehmen := u);

			for p in (select Projekte where Unternehmen = u) do
				let pStunden := for st in uStunden where st.Projekt = p do st end; 

				if count(pStunden) > 0 then
					let summe := sum(for st in pStunden do number(st.Stunden) end); 

					let pos := (create Rechnungspositionen);
					pos.(Rechnung := rechnung);
					pos.(Titel := text(p.Projektname));
					pos.(Stunden := summe);

					for st in pStunden do
						st.(Rechnungsposition := pos)
					end
				end
			end;

			anzahl := anzahl + 1
		end
	end
end;

if anzahl > 0 then
	alert("Es wurden " + text(anzahl) + " Rechnungen erfolgreich erstellt.")
else
	alert("Keine abrechenbaren Stunden im gewählten Zeitraum gefunden.")
end

Fehler:

  • Kommentieren mit // führen zu Syntaxfehlern
  • concat([nid], [nid]) ergibt kein neues Array und führt zu Syntaxfehler
  • where kann nur in Verbindung mit select genutzt werden, nicht um Arrays zu filtern

Ergebnis mit MCP

json
---
Projektstunden in Rechnungen pro Unternehmen übernehmen.
- Abrechnungszeitraum: Startdatum, Enddatum (Variante A: Felder auf aktuellem Record; Variante B: unten eintragen).
- Tabellen-/Feldnamen ggf. an Ihre Datenbank anpassen (Projektstunden, Rechnungen, Rechnungspositionen, Projekte, Unternehmen, etc.).
---;

" Abrechnungszeitraum: Bei Button auf Abrechnungszeitraum-Record: let startDatum := this.'Startdatum'; let endDatum := this.'Enddatum'; ";
" Sonst z. B. aus Konfigurationstabelle oder fest: date(Jahr, Monat, Tag) ";
let startDatum := Startdatum;
let endDatum := Enddatum;

" Alle offenen Stunden: nicht gelöscht, im Zeitraum, keine Rechnungsposition ODER stornierte Rechnung verknüpft ";
let offeneStunden := select Projektstunden where not Gelöscht and Datum >= startDatum and Datum <= endDatum and (not Rechnungsposition or Rechnungsposition.Rechnung.Storniert = true);

if cnt(offeneStunden) = 0 then
	dialog("Hinweis", "Keine offenen Stunden im Abrechnungszeitraum.", ["OK"])
else
	do as transaction
		" Eindeutige Unternehmen aus den Stunden (über Projekt) ";
		let unternehmenListe := unique(offeneStunden.Projekt.Unternehmen);
		for unternehmen in unternehmenListe do
			if unternehmen then
				" Rechnung pro Unternehmen anlegen ";
				let neueRechnung := create Rechnungen;
				neueRechnung.(
					Unternehmen := unternehmen;
					Rechnungsdatum := today()
				);
				" Eindeutige Projekte dieses Unternehmens mit offenen Stunden ";
				let projekteDesUnternehmens := unique(offeneStunden[Projekt.Unternehmen = unternehmen].Projekt);
				for projekt in projekteDesUnternehmens do
					if projekt then
						let stundenFuerProjekt := offeneStunden[Projekt = projekt];
						let summeStunden := sum(stundenFuerProjekt.Stunden);
						if summeStunden and summeStunden > 0 then
							" Eine Rechnungsposition pro Projekt (Titel = Projektname) ";
							let neuePosition := create Rechnungspositionen;
							neuePosition.(
								Rechnung := neueRechnung;
								Positionstitel := projekt.Name;
								Stunden := summeStunden
							);
							" Alle zugehörigen Stunden mit dieser Position verknüpfen ";
							stundenFuerProjekt.(
								Rechnungsposition := neuePosition
							)
						end
					end
				end
			end
		end
	end;
	dialog("Fertig", "Rechnungen wurden erstellt.", ["OK"])
end
json
let my := this;
let startDate := my.Startdatum;
let endDate := my.Enddatum;

let offeneStunden := select Projektstunden where
    not Gelöscht and
    Datum >= startDate and
    Datum <= endDate and
    (cnt(Rechnungsposition) = 0 or Rechnungsposition.Rechnung.Storniert);

if cnt(offeneStunden) = 0 then
    alert("Keine offenen Stunden im Abrechnungszeitraum gefunden.")
else
    "Eindeutige Projekte und Unternehmen ermitteln (Pre-Fetch)";
    let projekte := unique(offeneStunden.Projekt);
    let unternehmenListe := unique(projekte.Unternehmen);

    for unt in unternehmenListe do
        "Rechnung erstellen und mit Unternehmen verknüpfen";
        let rechnung := create Rechnungen;
        rechnung.(
            Rechnungsdatum := today();
            Unternehmen := unt
        );

        "Projekte dieses Unternehmens filtern";
        let untProjekte := projekte[Unternehmen = unt];

        for proj in untProjekte do
            "Stunden dieses Projekts zusammenrechnen";
            let projektStunden := offeneStunden[Projekt = proj];
            let gesamtStunden := sum(projektStunden.Stunden);

            "Rechnungsposition mit Projektname als Titel erstellen";
            let position := create Rechnungspositionen;
            position.(
                Bezeichnung := proj.Projektname;
                Menge := gesamtStunden;
                Rechnung := rechnung
            );

            "Stunden mit der neuen Rechnungsposition verknüpfen";
            for stunde in projektStunden do
                stunde.(Rechnungsposition := position)
            end
        end
    end
end