diff --git a/NTO/WorkOrder/entities/Activity.ttl b/NTO/WorkOrder/entities/Activity.ttl new file mode 100644 index 0000000000..075b2faa7e --- /dev/null +++ b/NTO/WorkOrder/entities/Activity.ttl @@ -0,0 +1,32 @@ +@prefix ogit: . +@prefix ogit.WorkOrder: . +@prefix owl: . +@prefix rdfs: . +@prefix dcterms: . + +ogit.WorkOrder:Activity + a rdfs:Class; + rdfs:subClassOf ogit:Entity; + rdfs:label "Activity"; + dcterms:description "A logged work activity attached to a WorkOrder. Carries optional device/asset reference (geraet), free-text description, logbook flag (export to driver/work logbook), internal-only flag, and creation timestamp. One Activity per discrete on-site or remote action."; + dcterms:source "AdaWorldAPI/WoA/models.py:Activity"; + dcterms:creator "family-codec-smith"; + ogit:scope "NTO"; + ogit:parent ogit:Node; + ogit:mandatory-attributes ( + ogit:id + ); + ogit:optional-attributes ( + ogit.WorkOrder:geraet + ogit.WorkOrder:beschreibung + ogit.WorkOrder:logbuch + ogit.WorkOrder:intern + ogit:created-at + ); + ogit:indexed-attributes ( + ogit:created-at + ); + ogit:allowed ( + [ ogit:belongs ogit.WorkOrder:Order ] + ); +. diff --git a/NTO/WorkOrder/entities/Article.ttl b/NTO/WorkOrder/entities/Article.ttl new file mode 100644 index 0000000000..294057c936 --- /dev/null +++ b/NTO/WorkOrder/entities/Article.ttl @@ -0,0 +1,77 @@ +@prefix ogit: . +@prefix ogit.WorkOrder: . +@prefix rdfs: . +@prefix dcterms: . + +ogit.WorkOrder:Article + a rdfs:Class; + rdfs:subClassOf ogit:Entity; + rdfs:label "Article"; + dcterms:description "Article master-data record (Artikelstamm / WaWi). Referenced by Position rows on an Order via article_id. Carries selling and purchase prices, VAT rate and supplier reference; derived margin (marge / marge_pct) is computed on demand by the Python model."; + dcterms:source "AdaWorldAPI/WoA/models.py:Article"; + ogit:scope "NTO"; + ogit:parent ogit:Node; + ogit:mandatory-attributes ( + ogit:id + ogit.WorkOrder:beschreibung + ); + ogit:optional-attributes ( + ogit.WorkOrder:artikelnr + ogit.WorkOrder:preisNetto + ogit.WorkOrder:ekPreis + ogit.WorkOrder:mwstSatz + ogit.WorkOrder:lieferant + ogit.WorkOrder:aktiv + ); + ogit:indexed-attributes ( + ogit:id + ogit.WorkOrder:artikelnr + ); + ogit:allowed ( + [ ogit:belongs ogit.WorkOrder:Tenant ] + ); +. + +# ── attributes ─────────────────────────────────────────────────────────── + +ogit.WorkOrder:artikelnr + a rdfs:Property; + rdfs:label "artikelnr"; + dcterms:description "Article number (Artikelnummer). Tenant-local short code used on invoices, lookup forms and inventory listings."; + dcterms:source "AdaWorldAPI/WoA/models.py:Article.artikelnr"; +. + +ogit.WorkOrder:beschreibung + a rdfs:Property; + rdfs:label "beschreibung"; + dcterms:description "Article description (Beschreibung) printed on order positions. Mandatory in the source model."; + dcterms:source "AdaWorldAPI/WoA/models.py:Article.beschreibung"; +. + +ogit.WorkOrder:preisNetto + a rdfs:Property; + rdfs:label "preisNetto"; + dcterms:description "Net selling price (Preis netto) in the tenant's currency. Float, default 0.0."; + dcterms:source "AdaWorldAPI/WoA/models.py:Article.preis_netto"; +. + +ogit.WorkOrder:ekPreis + a rdfs:Property; + rdfs:label "ekPreis"; + dcterms:description "Purchase price (Einkaufspreis) used for margin calculation against preisNetto."; + dcterms:source "AdaWorldAPI/WoA/models.py:Article.ek_preis"; +. + +ogit.WorkOrder:mwstSatz + a rdfs:Property; + rdfs:label "mwstSatz"; + dcterms:description "VAT rate (MwSt-Satz) in percent applied when this article appears as a position. Float, default 19.0."; + dcterms:source "AdaWorldAPI/WoA/models.py:Article.mwst_satz"; +. + +ogit.WorkOrder:lieferant + a rdfs:Property; + rdfs:label "lieferant"; + dcterms:description "Supplier name (Lieferant) the article is normally sourced from. Free-form string; not a relation to a separate Supplier class in the current source."; + dcterms:source "AdaWorldAPI/WoA/models.py:Article.lieferant"; +. diff --git a/NTO/WorkOrder/entities/Customer.ttl b/NTO/WorkOrder/entities/Customer.ttl new file mode 100644 index 0000000000..b97a827c82 --- /dev/null +++ b/NTO/WorkOrder/entities/Customer.ttl @@ -0,0 +1,126 @@ +@prefix ogit: . +@prefix ogit.WorkOrder: . +@prefix rdfs: . +@prefix dcterms: . + +ogit.WorkOrder:Customer + a rdfs:Class; + rdfs:subClassOf ogit:Entity; + rdfs:label "Customer"; + dcterms:description "Customer (Kunde) of a WoA tenant. Holds postal address, billing parameters (Zahlungsziel, Stundensatz) and is the parent of all work orders, time sheets and password-vault entries belonging to that customer."; + dcterms:source "AdaWorldAPI/WoA/models.py:Customer"; + ogit:scope "NTO"; + ogit:parent ogit:Node; + ogit:mandatory-attributes ( + ogit:id + ); + ogit:optional-attributes ( + ogit.WorkOrder:kdnr + ogit.WorkOrder:firma + ogit.WorkOrder:vorname + ogit.WorkOrder:nachname + ogit:email + ogit.WorkOrder:telefon + ogit.WorkOrder:strasse + ogit.WorkOrder:plz + ogit.WorkOrder:ort + ogit.WorkOrder:iban + ogit.WorkOrder:taxId + ogit.WorkOrder:zahlungsziel + ogit.WorkOrder:stundensatz + ); + ogit:indexed-attributes ( + ogit:id + ogit.WorkOrder:kdnr + ogit:email + ); + ogit:allowed ( + [ ogit:belongs ogit.WorkOrder:Tenant ] + ); +. + +# ── attributes ─────────────────────────────────────────────────────────── + +ogit.WorkOrder:kdnr + a rdfs:Property; + rdfs:label "kdnr"; + dcterms:description "Customer number (Kundennummer). Tenant-local short code used on invoices and in correspondence."; + dcterms:source "AdaWorldAPI/WoA/models.py:Customer.kdnr"; +. + +ogit.WorkOrder:firma + a rdfs:Property; + rdfs:label "firma"; + dcterms:description "Company name (Firma). Empty for private customers; in that case display falls back to vorname + nachname."; + dcterms:source "AdaWorldAPI/WoA/models.py:Customer.firma"; +. + +ogit.WorkOrder:vorname + a rdfs:Property; + rdfs:label "vorname"; + dcterms:description "Given name (Vorname) of the contact person."; + dcterms:source "AdaWorldAPI/WoA/models.py:Customer.vorname"; +. + +ogit.WorkOrder:nachname + a rdfs:Property; + rdfs:label "nachname"; + dcterms:description "Family name (Nachname) of the contact person."; + dcterms:source "AdaWorldAPI/WoA/models.py:Customer.nachname"; +. + +ogit.WorkOrder:telefon + a rdfs:Property; + rdfs:label "telefon"; + dcterms:description "Telephone number (Telefon) of the customer. Free-form string; no E.164 normalization is enforced by the source model."; + dcterms:source "AdaWorldAPI/WoA/models.py:Customer.telefon"; +. + +ogit.WorkOrder:strasse + a rdfs:Property; + rdfs:label "strasse"; + dcterms:description "Street and house number (Strasse)."; + dcterms:source "AdaWorldAPI/WoA/models.py:Customer.strasse"; +. + +ogit.WorkOrder:plz + a rdfs:Property; + rdfs:label "plz"; + dcterms:description "Postal code (Postleitzahl)."; + dcterms:source "AdaWorldAPI/WoA/models.py:Customer.plz"; +. + +ogit.WorkOrder:ort + a rdfs:Property; + rdfs:label "ort"; + dcterms:description "City / town (Ort)."; + dcterms:source "AdaWorldAPI/WoA/models.py:Customer.ort"; +. + +ogit.WorkOrder:iban + a rdfs:Property; + rdfs:label "iban"; + dcterms:description "International Bank Account Number for SEPA payments. Optional; not modelled as a column in the current Python source but reserved here for the OGIT projection."; + dcterms:source "AdaWorldAPI/WoA/models.py:Customer"; +. + +ogit.WorkOrder:taxId + a rdfs:Property; + rdfs:label "taxId"; + dcterms:description "Tax identification number (USt-IdNr / Steuernummer). Optional; reserved attribute for the OGIT projection of customer billing data."; + dcterms:source "AdaWorldAPI/WoA/models.py:Customer"; +. + +ogit.WorkOrder:zahlungsziel + a rdfs:Property; + rdfs:label "zahlungsziel"; + dcterms:description "Payment term (Zahlungsziel) in days; default 14. Drives the faellig_am derivation on Order."; + dcterms:source "AdaWorldAPI/WoA/models.py:Customer.zahlungsziel"; +. + +ogit.WorkOrder:stundensatz + a rdfs:Property; + rdfs:label "stundensatz"; + dcterms:description "Hourly rate (Stundensatz) in the tenant's currency, used by labour line items. Float, default 60.0."; + dcterms:source "AdaWorldAPI/WoA/models.py:Customer.stundensatz"; +. diff --git a/NTO/WorkOrder/entities/CustomerPortalUser.ttl b/NTO/WorkOrder/entities/CustomerPortalUser.ttl new file mode 100644 index 0000000000..d86fd7b8e1 --- /dev/null +++ b/NTO/WorkOrder/entities/CustomerPortalUser.ttl @@ -0,0 +1,42 @@ +@prefix ogit: . +@prefix ogit.WorkOrder: . +@prefix owl: . +@prefix rdfs: . +@prefix dcterms: . + +ogit.WorkOrder:CustomerPortalUser + a rdfs:Class; + rdfs:subClassOf ogit:Entity; + rdfs:label "CustomerPortalUser"; + dcterms:description "External self-service portal login bound to exactly one Customer. Authenticates via the same werkzeug pbkdf2:sha256 scheme as the internal User (with legacy SHA256+salt fallback and transparent upgrade), but has NO admin/superadmin scope. Used by customers to view their own work orders, invoices, and pay-status. Tracks last-login for audit, and carries an active-flag for soft-disabling and a forced-password-change marker."; + dcterms:source "AdaWorldAPI/WoA/models.py:CustomerPortalUser"; + dcterms:creator "bus-compiler"; + ogit:scope "NTO"; + ogit:parent ogit:Node; + ogit:mandatory-attributes ( + ogit:id + ); + ogit:optional-attributes ( + ogit.WorkOrder:username + ogit.WorkOrder:passwordHash + ogit.WorkOrder:aktiv + ogit.WorkOrder:mustChangePw + ogit.WorkOrder:lastLogin + ogit.WorkOrder:createdAt + ); + ogit:indexed-attributes ( + ogit.WorkOrder:username + ); + ogit:allowed ( + [ ogit:belongs ogit.WorkOrder:Customer ] + ); +. + +# ── attributes ─────────────────────────────────────────────────────────── + +ogit.WorkOrder:lastLogin + a rdfs:Property; + rdfs:label "lastLogin"; + dcterms:description "ISO-8601 UTC timestamp of the most recent successful portal login. Null on accounts that have never signed in."; + dcterms:source "AdaWorldAPI/WoA/models.py:CustomerPortalUser.last_login"; +. diff --git a/NTO/WorkOrder/entities/HistoryEntry.ttl b/NTO/WorkOrder/entities/HistoryEntry.ttl new file mode 100644 index 0000000000..e578f61f45 --- /dev/null +++ b/NTO/WorkOrder/entities/HistoryEntry.ttl @@ -0,0 +1,32 @@ +@prefix ogit: . +@prefix ogit.WorkOrder: . +@prefix owl: . +@prefix rdfs: . +@prefix dcterms: . + +ogit.WorkOrder:HistoryEntry + a rdfs:Class; + rdfs:subClassOf ogit:Entity; + rdfs:label "HistoryEntry"; + dcterms:description "An immutable audit/log row for a WorkOrder. Records an action label (aktion), free-text details, the User who performed the action, and a creation timestamp. Append-only: every state change to an Order should produce one HistoryEntry."; + dcterms:source "AdaWorldAPI/WoA/models.py:HistoryEntry"; + dcterms:creator "family-codec-smith"; + ogit:scope "NTO"; + ogit:parent ogit:Node; + ogit:mandatory-attributes ( + ogit:id + ); + ogit:optional-attributes ( + ogit.WorkOrder:aktion + ogit.WorkOrder:details + ogit:created-at + ); + ogit:indexed-attributes ( + ogit:created-at + ogit.WorkOrder:aktion + ); + ogit:allowed ( + [ ogit:belongs ogit.WorkOrder:Order ] + [ ogit:relates ogit.WorkOrder:User ] + ); +. diff --git a/NTO/WorkOrder/entities/LogbookEntry.ttl b/NTO/WorkOrder/entities/LogbookEntry.ttl new file mode 100644 index 0000000000..24b0cc1dea --- /dev/null +++ b/NTO/WorkOrder/entities/LogbookEntry.ttl @@ -0,0 +1,120 @@ +@prefix ogit: . +@prefix ogit.WorkOrder: . +@prefix owl: . +@prefix rdfs: . +@prefix dcterms: . + +ogit.WorkOrder:LogbookEntry + a rdfs:Class; + rdfs:subClassOf ogit:Entity; + rdfs:label "LogbookEntry"; + dcterms:description "A driving-logbook (Fahrtenbuch) row capturing one trip: start/end odometer reading, departure/arrival times, route description, business purpose, vehicle, and the private-share kilometers split out for tax purposes. Optionally references a User (driver), Customer (visited), and Order (the work-order driven for)."; + dcterms:source "AdaWorldAPI/WoA/models.py:LogbookEntry"; + dcterms:creator "bus-compiler"; + ogit:scope "NTO"; + ogit:parent ogit:Node; + ogit:mandatory-attributes ( + ogit:id + ); + ogit:optional-attributes ( + ogit.WorkOrder:datum + ogit.WorkOrder:abfahrt + ogit.WorkOrder:ankunft + ogit.WorkOrder:rueckfahrt + ogit.WorkOrder:zurueck + ogit.WorkOrder:startKm + ogit.WorkOrder:endeKm + ogit.WorkOrder:route + ogit.WorkOrder:zweck + ogit.WorkOrder:fahrzeug + ogit.WorkOrder:privatAnteil + ogit.WorkOrder:createdAt + ); + ogit:indexed-attributes ( + ogit.WorkOrder:datum + ); + ogit:allowed ( + [ ogit:relates ogit.WorkOrder:User ] + [ ogit:relates ogit.WorkOrder:Customer ] + [ ogit:relates ogit.WorkOrder:Order ] + ); +. + +# ── attributes ─────────────────────────────────────────────────────────── + +ogit.WorkOrder:datum + a rdfs:Property; + rdfs:label "datum"; + dcterms:description "ISO-8601 calendar date the trip took place (mandatory; defaults to today on insert)."; + dcterms:source "AdaWorldAPI/WoA/models.py:LogbookEntry.datum"; +. + +ogit.WorkOrder:abfahrt + a rdfs:Property; + rdfs:label "abfahrt"; + dcterms:description "Departure time as HH:MM string (max 5 chars)."; + dcterms:source "AdaWorldAPI/WoA/models.py:LogbookEntry.abfahrt"; +. + +ogit.WorkOrder:ankunft + a rdfs:Property; + rdfs:label "ankunft"; + dcterms:description "Arrival time at destination as HH:MM string (max 5 chars)."; + dcterms:source "AdaWorldAPI/WoA/models.py:LogbookEntry.ankunft"; +. + +ogit.WorkOrder:rueckfahrt + a rdfs:Property; + rdfs:label "rueckfahrt"; + dcterms:description "Return-trip departure time as HH:MM string (max 5 chars)."; + dcterms:source "AdaWorldAPI/WoA/models.py:LogbookEntry.rueckfahrt"; +. + +ogit.WorkOrder:zurueck + a rdfs:Property; + rdfs:label "zurueck"; + dcterms:description "Return-trip arrival time as HH:MM string (max 5 chars)."; + dcterms:source "AdaWorldAPI/WoA/models.py:LogbookEntry.zurueck"; +. + +ogit.WorkOrder:startKm + a rdfs:Property; + rdfs:label "startKm"; + dcterms:description "Odometer reading at trip start (kilometers, float)."; + dcterms:source "AdaWorldAPI/WoA/models.py:LogbookEntry.start_km"; +. + +ogit.WorkOrder:endeKm + a rdfs:Property; + rdfs:label "endeKm"; + dcterms:description "Odometer reading at trip end (kilometers, float). The trip's total distance is end_km - start_km."; + dcterms:source "AdaWorldAPI/WoA/models.py:LogbookEntry.ende_km"; +. + +ogit.WorkOrder:route + a rdfs:Property; + rdfs:label "route"; + dcterms:description "Free-text route description (e.g. 'Würzburg - Frankfurt - Würzburg', max 300 chars)."; + dcterms:source "AdaWorldAPI/WoA/models.py:LogbookEntry.route"; +. + +ogit.WorkOrder:zweck + a rdfs:Property; + rdfs:label "zweck"; + dcterms:description "Business purpose of the trip (max 300 chars). Required by German tax law for the Fahrtenbuch."; + dcterms:source "AdaWorldAPI/WoA/models.py:LogbookEntry.zweck"; +. + +ogit.WorkOrder:fahrzeug + a rdfs:Property; + rdfs:label "fahrzeug"; + dcterms:description "Vehicle identifier (license plate or fleet name, max 100 chars)."; + dcterms:source "AdaWorldAPI/WoA/models.py:LogbookEntry.fahrzeug"; +. + +ogit.WorkOrder:privatAnteil + a rdfs:Property; + rdfs:label "privatAnteil"; + dcterms:description "Kilometers attributed to private use within this trip (float). Subtracted from the total to derive km_geschaeftlich."; + dcterms:source "AdaWorldAPI/WoA/models.py:LogbookEntry.privat_anteil"; +. diff --git a/NTO/WorkOrder/entities/NumberSequence.ttl b/NTO/WorkOrder/entities/NumberSequence.ttl new file mode 100644 index 0000000000..56d9c45cf5 --- /dev/null +++ b/NTO/WorkOrder/entities/NumberSequence.ttl @@ -0,0 +1,46 @@ +@prefix ogit: . +@prefix ogit.WorkOrder: . +@prefix owl: . +@prefix rdfs: . +@prefix dcterms: . + +ogit.WorkOrder:NumberSequence + a rdfs:Class; + rdfs:subClassOf ogit:Entity; + rdfs:label "NumberSequence"; + dcterms:description "Per-tenant atomic counter used to mint sequential business document numbers (offer-, order-, invoice-, credit-numbers). Each sequence has a stable name (the sequence kind), an optional prefix, and a monotonically incrementing 'current' integer; next_val() increments the counter and concatenates prefix + current to produce the next document number."; + dcterms:source "AdaWorldAPI/WoA/models.py:NumberSequence"; + dcterms:creator "bus-compiler"; + ogit:scope "NTO"; + ogit:parent ogit:Node; + ogit:mandatory-attributes ( + ogit:id + ); + ogit:optional-attributes ( + ogit:name + ogit.WorkOrder:prefix + ogit.WorkOrder:current + ); + ogit:indexed-attributes ( + ogit:name + ); + ogit:allowed ( + [ ogit:belongs ogit.WorkOrder:Tenant ] + ); +. + +# ── attributes ─────────────────────────────────────────────────────────── + +ogit.WorkOrder:prefix + a rdfs:Property; + rdfs:label "prefix"; + dcterms:description "Static string concatenated in front of the counter when minting a new number (e.g. 'AB-', 'RE-', max 10 chars)."; + dcterms:source "AdaWorldAPI/WoA/models.py:NumberSequence.prefix"; +. + +ogit.WorkOrder:current + a rdfs:Property; + rdfs:label "current"; + dcterms:description "Monotonically increasing integer holding the most-recently-issued counter value. Incremented in-place by next_val() inside a database transaction."; + dcterms:source "AdaWorldAPI/WoA/models.py:NumberSequence.current"; +. diff --git a/NTO/WorkOrder/entities/Order.ttl b/NTO/WorkOrder/entities/Order.ttl new file mode 100644 index 0000000000..9d86a91edb --- /dev/null +++ b/NTO/WorkOrder/entities/Order.ttl @@ -0,0 +1,97 @@ +@prefix ogit: . +@prefix ogit.WorkOrder: . +@prefix rdfs: . +@prefix dcterms: . + +ogit.WorkOrder:Order + a rdfs:Class; + rdfs:subClassOf ogit:Entity; + rdfs:label "Order"; + dcterms:description "Central work-order document of WoA. A single SQLAlchemy table 'workorders' represents five doc_type variants — workorder (Arbeitsauftrag), offer (Angebot), order (Auftrag), invoice (Rechnung), credit (Gutschrift). The doc_type column selects the variant; OGIT consumers should treat 'Order' as the umbrella class and filter by doc_type for variant-specific logic. Holds positions, activities, pictures and history as child collections, and exposes derived totals netto_summe / mwst_betrag / brutto_summe."; + dcterms:source "AdaWorldAPI/WoA/models.py:WorkOrder"; + ogit:scope "NTO"; + ogit:parent ogit:Node; + ogit:mandatory-attributes ( + ogit:id + ogit.WorkOrder:orderId + ); + ogit:optional-attributes ( + ogit:status + ogit.WorkOrder:docType + ogit.WorkOrder:datum + ogit.WorkOrder:betreff + ogit.WorkOrder:nettoSumme + ogit.WorkOrder:mwstBetrag + ogit.WorkOrder:bruttoSumme + ogit.WorkOrder:bezahlt + ); + ogit:indexed-attributes ( + ogit:id + ogit.WorkOrder:orderId + ogit:status + ogit.WorkOrder:datum + ); + ogit:allowed ( + [ ogit:belongs ogit.WorkOrder:Tenant ] + [ ogit:relates ogit.WorkOrder:Customer ] + [ ogit:relates ogit.WorkOrder:Article ] + ); +. + +# ── attributes ─────────────────────────────────────────────────────────── + +ogit.WorkOrder:orderId + a rdfs:Property; + rdfs:label "orderId"; + dcterms:description "Public document number. The Python source carries five parallel slots (angebot_nr, auftrags_nr, workorder_nr, rechnung_nr, gutschrift_nr) plus a derived beleg_nr that picks the active one. orderId is the OGIT-side projection of beleg_nr — the human-facing identifier regardless of doc_type."; + dcterms:source "AdaWorldAPI/WoA/models.py:WorkOrder.beleg_nr"; +. + +ogit.WorkOrder:docType + a rdfs:Property; + rdfs:label "docType"; + dcterms:description "Discriminator for the document variant. One of: workorder, offer, order, invoice, credit. Mirrors WorkOrder.doc_type in the source."; + dcterms:source "AdaWorldAPI/WoA/models.py:WorkOrder.doc_type"; +. + +ogit.WorkOrder:datum + a rdfs:Property; + rdfs:label "datum"; + dcterms:description "Document date (Datum). ISO-8601 date; defaults to creation day. Drives the dunning / due-date derivations."; + dcterms:source "AdaWorldAPI/WoA/models.py:WorkOrder.datum"; +. + +ogit.WorkOrder:betreff + a rdfs:Property; + rdfs:label "betreff"; + dcterms:description "Subject / heading line (Betreff) printed at the top of the document."; + dcterms:source "AdaWorldAPI/WoA/models.py:WorkOrder.betreff"; +. + +ogit.WorkOrder:nettoSumme + a rdfs:Property; + rdfs:label "nettoSumme"; + dcterms:description "Net total (Netto-Summe). Derived in Python as sum(menge × einzelpreis) over all positions; materialised on the OGIT projection."; + dcterms:source "AdaWorldAPI/WoA/models.py:WorkOrder.netto_summe"; +. + +ogit.WorkOrder:mwstBetrag + a rdfs:Property; + rdfs:label "mwstBetrag"; + dcterms:description "VAT amount (MwSt-Betrag). Derived in Python as sum(menge × einzelpreis × mwst_satz / 100) over all positions."; + dcterms:source "AdaWorldAPI/WoA/models.py:WorkOrder.mwst_betrag"; +. + +ogit.WorkOrder:bruttoSumme + a rdfs:Property; + rdfs:label "bruttoSumme"; + dcterms:description "Gross total (Brutto-Summe) = nettoSumme + mwstBetrag."; + dcterms:source "AdaWorldAPI/WoA/models.py:WorkOrder.brutto_summe"; +. + +ogit.WorkOrder:bezahlt + a rdfs:Property; + rdfs:label "bezahlt"; + dcterms:description "Payment-received flag. Boolean; true once the order has been settled by the customer."; + dcterms:source "AdaWorldAPI/WoA/models.py:WorkOrder.bezahlt"; +. diff --git a/NTO/WorkOrder/entities/PasswordEntry.ttl b/NTO/WorkOrder/entities/PasswordEntry.ttl new file mode 100644 index 0000000000..695f8d6179 --- /dev/null +++ b/NTO/WorkOrder/entities/PasswordEntry.ttl @@ -0,0 +1,91 @@ +@prefix ogit: . +@prefix ogit.WorkOrder: . +@prefix owl: . +@prefix rdfs: . +@prefix dcterms: . + +ogit.WorkOrder:PasswordEntry + a rdfs:Class; + rdfs:subClassOf ogit:Entity; + rdfs:label "PasswordEntry"; + dcterms:description "KeePass-style encrypted vault entry stored against a Customer (the resource being accessed) and authored by a User. Sensitive fields (passwort_enc, notizen_enc) are encrypted at rest using Fernet (AES-128-CBC + HMAC-SHA256), with the symmetric key derived from the WOA_SECRET environment variable via SHA-256. WOA_SECRET MUST be set (>= 32 chars); the application refuses to encrypt or decrypt without it. Non-secret metadata (group, title, username, url, icon) is stored in plaintext for searchability."; + dcterms:source "AdaWorldAPI/WoA/models.py:PasswordEntry"; + dcterms:creator "bus-compiler"; + ogit:scope "NTO"; + ogit:parent ogit:Node; + ogit:mandatory-attributes ( + ogit:id + ); + ogit:optional-attributes ( + ogit.WorkOrder:gruppe + ogit.WorkOrder:titel + ogit.WorkOrder:benutzername + ogit.WorkOrder:passwortEnc + ogit.WorkOrder:url + ogit.WorkOrder:notizenEnc + ogit.WorkOrder:icon + ogit.WorkOrder:aktiv + ogit.WorkOrder:createdAt + ogit.WorkOrder:updatedAt + ); + ogit:indexed-attributes ( + ogit.WorkOrder:titel + ogit.WorkOrder:gruppe + ); + ogit:allowed ( + [ ogit:belongs ogit.WorkOrder:Customer ] + [ ogit:belongs ogit.WorkOrder:Tenant ] + [ ogit:relates ogit.WorkOrder:User ] + ); +. + +# ── attributes ─────────────────────────────────────────────────────────── + +ogit.WorkOrder:gruppe + a rdfs:Property; + rdfs:label "gruppe"; + dcterms:description "Vault folder/category (max 100 chars, default 'Allgemein'). Free-form grouping used to organise entries in the UI tree."; + dcterms:source "AdaWorldAPI/WoA/models.py:PasswordEntry.gruppe"; +. + +ogit.WorkOrder:titel + a rdfs:Property; + rdfs:label "titel"; + dcterms:description "Display title for the entry (max 200 chars). Mandatory."; + dcterms:source "AdaWorldAPI/WoA/models.py:PasswordEntry.titel"; +. + +ogit.WorkOrder:benutzername + a rdfs:Property; + rdfs:label "benutzername"; + dcterms:description "Plaintext account-username for the resource (max 200 chars). NOT encrypted — only the password and notes carry sensitive material."; + dcterms:source "AdaWorldAPI/WoA/models.py:PasswordEntry.benutzername"; +. + +ogit.WorkOrder:passwortEnc + a rdfs:Property; + rdfs:label "passwortEnc"; + dcterms:description "Fernet-encrypted ciphertext of the password (base64-urlsafe over AES-128-CBC + HMAC-SHA256). Decryption requires the WOA_SECRET-derived key; failure produces the placeholder '*** Entschluesselung fehlgeschlagen ***'."; + dcterms:source "AdaWorldAPI/WoA/models.py:PasswordEntry.passwort_enc"; +. + +ogit.WorkOrder:url + a rdfs:Property; + rdfs:label "url"; + dcterms:description "URL of the protected resource (max 500 chars), stored in plaintext."; + dcterms:source "AdaWorldAPI/WoA/models.py:PasswordEntry.url"; +. + +ogit.WorkOrder:notizenEnc + a rdfs:Property; + rdfs:label "notizenEnc"; + dcterms:description "Fernet-encrypted ciphertext of free-form notes. Same Fernet construction as passwortEnc."; + dcterms:source "AdaWorldAPI/WoA/models.py:PasswordEntry.notizen_enc"; +. + +ogit.WorkOrder:icon + a rdfs:Property; + rdfs:label "icon"; + dcterms:description "Icon glyph name (max 50 chars, default 'key') used by the UI to render the entry visually."; + dcterms:source "AdaWorldAPI/WoA/models.py:PasswordEntry.icon"; +. diff --git a/NTO/WorkOrder/entities/Picture.ttl b/NTO/WorkOrder/entities/Picture.ttl new file mode 100644 index 0000000000..c54d3781de --- /dev/null +++ b/NTO/WorkOrder/entities/Picture.ttl @@ -0,0 +1,32 @@ +@prefix ogit: . +@prefix ogit.WorkOrder: . +@prefix owl: . +@prefix rdfs: . +@prefix dcterms: . + +ogit.WorkOrder:Picture + a rdfs:Class; + rdfs:subClassOf ogit:Entity; + rdfs:label "Picture"; + dcterms:description "An image/document attachment on a WorkOrder. Carries the stored filename (dateiname), an optional caption (beschreibung), a logbook flag (include in driver/work logbook export), an an_kunde flag (visible to / send to customer), and a creation timestamp."; + dcterms:source "AdaWorldAPI/WoA/models.py:Picture"; + dcterms:creator "family-codec-smith"; + ogit:scope "NTO"; + ogit:parent ogit:Node; + ogit:mandatory-attributes ( + ogit:id + ); + ogit:optional-attributes ( + ogit.WorkOrder:dateiname + ogit.WorkOrder:beschreibung + ogit.WorkOrder:logbuch + ogit.WorkOrder:anKunde + ogit:created-at + ); + ogit:indexed-attributes ( + ogit:created-at + ); + ogit:allowed ( + [ ogit:belongs ogit.WorkOrder:Order ] + ); +. diff --git a/NTO/WorkOrder/entities/Position.ttl b/NTO/WorkOrder/entities/Position.ttl new file mode 100644 index 0000000000..042d12711d --- /dev/null +++ b/NTO/WorkOrder/entities/Position.ttl @@ -0,0 +1,37 @@ +@prefix ogit: . +@prefix ogit.WorkOrder: . +@prefix owl: . +@prefix rdfs: . +@prefix dcterms: . + +ogit.WorkOrder:Position + a rdfs:Class; + rdfs:subClassOf ogit:Entity; + rdfs:label "Position"; + dcterms:description "A line item (Position) on a WorkOrder/Order document. Represents one billable or descriptive row carrying quantity, unit, unit-price, VAT rate, optional Article reference, and ordering. Used across offer/order/invoice/credit doc types."; + dcterms:source "AdaWorldAPI/WoA/models.py:Position"; + dcterms:creator "family-codec-smith"; + ogit:scope "NTO"; + ogit:parent ogit:Node; + ogit:mandatory-attributes ( + ogit:id + ); + ogit:optional-attributes ( + ogit.WorkOrder:sortOrder + ogit.WorkOrder:posTyp + ogit.WorkOrder:beschreibung + ogit.WorkOrder:menge + ogit.WorkOrder:einheit + ogit.WorkOrder:einzelpreis + ogit.WorkOrder:mwstSatz + ogit.WorkOrder:versteckt + ); + ogit:indexed-attributes ( + ogit.WorkOrder:sortOrder + ogit.WorkOrder:posTyp + ); + ogit:allowed ( + [ ogit:belongs ogit.WorkOrder:Order ] + [ ogit:relates ogit.WorkOrder:Article ] + ); +. diff --git a/NTO/WorkOrder/entities/Setting.ttl b/NTO/WorkOrder/entities/Setting.ttl new file mode 100644 index 0000000000..b62d6fc424 --- /dev/null +++ b/NTO/WorkOrder/entities/Setting.ttl @@ -0,0 +1,53 @@ +@prefix ogit: . +@prefix ogit.WorkOrder: . +@prefix owl: . +@prefix rdfs: . +@prefix dcterms: . + +ogit.WorkOrder:Setting + a rdfs:Class; + rdfs:subClassOf ogit:Entity; + rdfs:label "Setting"; + dcterms:description "Per-tenant key/value configuration row. Stores arbitrary string-typed application settings (e.g. company address fields, default VAT rate, PDF footer text) outside of code. The label provides a human-readable caption used in admin UIs; the value is free-form text."; + dcterms:source "AdaWorldAPI/WoA/models.py:Setting"; + dcterms:creator "bus-compiler"; + ogit:scope "NTO"; + ogit:parent ogit:Node; + ogit:mandatory-attributes ( + ogit:id + ); + ogit:optional-attributes ( + ogit.WorkOrder:settingKey + ogit.WorkOrder:settingValue + ogit.WorkOrder:label + ); + ogit:indexed-attributes ( + ogit.WorkOrder:settingKey + ); + ogit:allowed ( + [ ogit:belongs ogit.WorkOrder:Tenant ] + ); +. + +# ── attributes ─────────────────────────────────────────────────────────── + +ogit.WorkOrder:settingKey + a rdfs:Property; + rdfs:label "settingKey"; + dcterms:description "Setting identifier (max 100 chars), unique per tenant. Conventionally dot-namespaced (e.g. 'company.address', 'pdf.footer')."; + dcterms:source "AdaWorldAPI/WoA/models.py:Setting.key"; +. + +ogit.WorkOrder:settingValue + a rdfs:Property; + rdfs:label "settingValue"; + dcterms:description "Free-form text value associated with the key. Application-side code is responsible for any type coercion (int/bool/json)."; + dcterms:source "AdaWorldAPI/WoA/models.py:Setting.value"; +. + +ogit.WorkOrder:label + a rdfs:Property; + rdfs:label "label"; + dcterms:description "Human-readable caption (max 200 chars) shown next to the key in admin UIs."; + dcterms:source "AdaWorldAPI/WoA/models.py:Setting.label"; +. diff --git a/NTO/WorkOrder/entities/Tenant.ttl b/NTO/WorkOrder/entities/Tenant.ttl new file mode 100644 index 0000000000..cc20f07ba5 --- /dev/null +++ b/NTO/WorkOrder/entities/Tenant.ttl @@ -0,0 +1,58 @@ +@prefix ogit: . +@prefix ogit.WorkOrder: . +@prefix rdfs: . +@prefix dcterms: . + +ogit.WorkOrder:Tenant + a rdfs:Class; + rdfs:subClassOf ogit:Entity; + rdfs:label "Tenant"; + dcterms:description "Multi-tenancy root for the WoA application. Every tenant-scoped business entity (Customer, Order, Article, etc.) carries a tenant_id foreign key referring to this class. Backed by SQLAlchemy table 'tenants'."; + dcterms:source "AdaWorldAPI/WoA/models.py:Tenant"; + ogit:scope "NTO"; + ogit:parent ogit:Node; + ogit:mandatory-attributes ( + ogit:id + ogit:name + ogit.WorkOrder:slug + ); + ogit:optional-attributes ( + ogit.WorkOrder:aktiv + ogit.WorkOrder:logoPath + ogit.WorkOrder:createdAt + ); + ogit:indexed-attributes ( + ogit:id + ogit.WorkOrder:slug + ); +. + +# ── attributes ─────────────────────────────────────────────────────────── + +ogit.WorkOrder:slug + a rdfs:Property; + rdfs:label "slug"; + dcterms:description "Unique URL-safe short identifier for the tenant (max 50 chars). Used in routing and as a stable handle independent of the numeric id."; + dcterms:source "AdaWorldAPI/WoA/models.py:Tenant.slug"; +. + +ogit.WorkOrder:aktiv + a rdfs:Property; + rdfs:label "aktiv"; + dcterms:description "Boolean active-flag. Inactive tenants are soft-disabled rather than deleted."; + dcterms:source "AdaWorldAPI/WoA/models.py:Tenant.aktiv"; +. + +ogit.WorkOrder:logoPath + a rdfs:Property; + rdfs:label "logoPath"; + dcterms:description "Filesystem or URL path to the tenant's logo image used in PDF/HTML rendering of work orders."; + dcterms:source "AdaWorldAPI/WoA/models.py:Tenant.logo_path"; +. + +ogit.WorkOrder:createdAt + a rdfs:Property; + rdfs:label "createdAt"; + dcterms:description "ISO-8601 UTC timestamp recording when the entity was first persisted."; + dcterms:source "AdaWorldAPI/WoA/models.py"; +. diff --git a/NTO/WorkOrder/entities/TimeSheet.ttl b/NTO/WorkOrder/entities/TimeSheet.ttl new file mode 100644 index 0000000000..d51ac6ef85 --- /dev/null +++ b/NTO/WorkOrder/entities/TimeSheet.ttl @@ -0,0 +1,74 @@ +@prefix ogit: . +@prefix ogit.WorkOrder: . +@prefix owl: . +@prefix rdfs: . +@prefix dcterms: . + +ogit.WorkOrder:TimeSheet + a rdfs:Class; + rdfs:subClassOf ogit:Entity; + rdfs:label "TimeSheet"; + dcterms:description "Stundenzettel — a time-tracking record booked against a Customer (mandatory) and authored by a User (optional). Stores duration in minutes, a free-text description, and an 'abgerechnet' flag indicating whether the entry has been billed onto a downstream invoice. Provides 15-minute-rounded display values and decimal-hour conversion via instance methods."; + dcterms:source "AdaWorldAPI/WoA/models.py:TimeSheet"; + dcterms:creator "bus-compiler"; + ogit:scope "NTO"; + ogit:parent ogit:Node; + ogit:mandatory-attributes ( + ogit:id + ); + ogit:optional-attributes ( + ogit.WorkOrder:datum + ogit.WorkOrder:minuten + ogit.WorkOrder:beschreibung + ogit.WorkOrder:timerStart + ogit.WorkOrder:abgerechnet + ogit.WorkOrder:createdAt + ogit.WorkOrder:updatedAt + ); + ogit:indexed-attributes ( + ogit.WorkOrder:datum + ogit.WorkOrder:abgerechnet + ); + ogit:allowed ( + [ ogit:belongs ogit.WorkOrder:Customer ] + [ ogit:belongs ogit.WorkOrder:Tenant ] + [ ogit:relates ogit.WorkOrder:User ] + ); +. + +# ── attributes ─────────────────────────────────────────────────────────── + +ogit.WorkOrder:minuten + a rdfs:Property; + rdfs:label "minuten"; + dcterms:description "Duration of the recorded work in minutes (integer). Display helpers round up to the nearest 15-minute increment for billing."; + dcterms:source "AdaWorldAPI/WoA/models.py:TimeSheet.minuten"; +. + +ogit.WorkOrder:timerStart + a rdfs:Property; + rdfs:label "timerStart"; + dcterms:description "ISO-8601 UTC timestamp marking when a live timer was started for this entry. Null when not currently running."; + dcterms:source "AdaWorldAPI/WoA/models.py:TimeSheet.timer_start"; +. + +ogit.WorkOrder:abgerechnet + a rdfs:Property; + rdfs:label "abgerechnet"; + dcterms:description "Boolean billed-flag. True once the time entry has been transferred onto an invoice document, preventing double-billing."; + dcterms:source "AdaWorldAPI/WoA/models.py:TimeSheet.abgerechnet"; +. + +ogit.WorkOrder:beschreibung + a rdfs:Property; + rdfs:label "beschreibung"; + dcterms:description "Free-text description of the work performed during this time entry."; + dcterms:source "AdaWorldAPI/WoA/models.py:TimeSheet.beschreibung"; +. + +ogit.WorkOrder:updatedAt + a rdfs:Property; + rdfs:label "updatedAt"; + dcterms:description "ISO-8601 UTC timestamp of the most recent persisted update to the row."; + dcterms:source "AdaWorldAPI/WoA/models.py"; +. diff --git a/NTO/WorkOrder/entities/User.ttl b/NTO/WorkOrder/entities/User.ttl new file mode 100644 index 0000000000..aed69a1908 --- /dev/null +++ b/NTO/WorkOrder/entities/User.ttl @@ -0,0 +1,102 @@ +@prefix ogit: . +@prefix ogit.WorkOrder: . +@prefix owl: . +@prefix rdfs: . +@prefix dcterms: . + +ogit.WorkOrder:User + a rdfs:Class; + rdfs:subClassOf ogit:Entity; + rdfs:label "User"; + dcterms:description "Internal WoA user / operator. Authenticates against pbkdf2:sha256 password hashes (werkzeug, 600k iterations, salted) with transparent migration from a legacy SHA256+salt format. Carries optional contact metadata (firstname, lastname, email, phone), the admin/superadmin flags that gate Flask routes, and a forced-password-change marker. Each User belongs to exactly one Tenant via tenant_id."; + dcterms:source "AdaWorldAPI/WoA/models.py:User"; + dcterms:creator "bus-compiler"; + ogit:scope "NTO"; + ogit:parent ogit:Node; + ogit:mandatory-attributes ( + ogit:id + ); + ogit:optional-attributes ( + ogit.WorkOrder:username + ogit.WorkOrder:passwordHash + ogit.WorkOrder:firstname + ogit.WorkOrder:lastname + ogit.WorkOrder:email + ogit.WorkOrder:phone + ogit.WorkOrder:isAdmin + ogit.WorkOrder:isSuperadmin + ogit.WorkOrder:mustChangePw + ogit.WorkOrder:createdAt + ); + ogit:indexed-attributes ( + ogit.WorkOrder:username + ); + ogit:allowed ( + [ ogit:belongs ogit.WorkOrder:Tenant ] + ); +. + +# ── attributes ─────────────────────────────────────────────────────────── + +ogit.WorkOrder:username + a rdfs:Property; + rdfs:label "username"; + dcterms:description "Globally unique login handle (max 120 chars). Primary credential identifier used for password authentication."; + dcterms:source "AdaWorldAPI/WoA/models.py:User.username"; +. + +ogit.WorkOrder:passwordHash + a rdfs:Property; + rdfs:label "passwordHash"; + dcterms:description "Werkzeug-formatted password hash (pbkdf2:sha256:$$, max 256 chars). Legacy two-part SHA256+salt hashes are accepted on first login and transparently upgraded to pbkdf2."; + dcterms:source "AdaWorldAPI/WoA/models.py:User.password_hash"; +. + +ogit.WorkOrder:firstname + a rdfs:Property; + rdfs:label "firstname"; + dcterms:description "User's given name (max 120 chars)."; + dcterms:source "AdaWorldAPI/WoA/models.py:User.firstname"; +. + +ogit.WorkOrder:lastname + a rdfs:Property; + rdfs:label "lastname"; + dcterms:description "User's family name (max 120 chars)."; + dcterms:source "AdaWorldAPI/WoA/models.py:User.lastname"; +. + +ogit.WorkOrder:email + a rdfs:Property; + rdfs:label "email"; + dcterms:description "User's primary email address (max 200 chars). Used for notifications and password resets."; + dcterms:source "AdaWorldAPI/WoA/models.py:User.email"; +. + +ogit.WorkOrder:phone + a rdfs:Property; + rdfs:label "phone"; + dcterms:description "User's contact telephone number (max 100 chars)."; + dcterms:source "AdaWorldAPI/WoA/models.py:User.phone"; +. + +ogit.WorkOrder:isAdmin + a rdfs:Property; + rdfs:label "isAdmin"; + dcterms:description "Boolean flag granting admin-level access within the User's tenant scope (manage customers, articles, settings)."; + dcterms:source "AdaWorldAPI/WoA/models.py:User.is_admin"; +. + +ogit.WorkOrder:isSuperadmin + a rdfs:Property; + rdfs:label "isSuperadmin"; + dcterms:description "Boolean flag granting cross-tenant superadmin access (manage tenants, system-wide configuration)."; + dcterms:source "AdaWorldAPI/WoA/models.py:User.is_superadmin"; +. + +ogit.WorkOrder:mustChangePw + a rdfs:Property; + rdfs:label "mustChangePw"; + dcterms:description "Boolean forced-password-change marker. When true, the next successful login redirects the user to the password-reset flow."; + dcterms:source "AdaWorldAPI/WoA/models.py:User.must_change_pw"; +. diff --git a/NTO/WorkOrder/verbs/AccessesPortal.ttl b/NTO/WorkOrder/verbs/AccessesPortal.ttl new file mode 100644 index 0000000000..1b8b2aa0da --- /dev/null +++ b/NTO/WorkOrder/verbs/AccessesPortal.ttl @@ -0,0 +1,16 @@ +@prefix ogit: . +@prefix ogit.WorkOrder: . +@prefix rdfs: . +@prefix dcterms: . + +ogit.WorkOrder:accessesPortal + a rdfs:Class; + rdfs:subClassOf ogit:Verb; + rdfs:label "accessesPortal"; + dcterms:description "CustomerPortalUser accesses-portal as a specific Customer (login binding). Each portal login row binds exactly one credential to one Customer (one-to-one)." ; + dcterms:source "AdaWorldAPI/WoA/models.py:CustomerPortalUser.customer_id -> Customer.id" ; + ogit:scope "NTO"; + ogit:from-to ( + [ ogit:from ogit.WorkOrder:CustomerPortalUser ; ogit:to ogit.WorkOrder:Customer ] + ) ; +. diff --git a/NTO/WorkOrder/verbs/Assigned.ttl b/NTO/WorkOrder/verbs/Assigned.ttl new file mode 100644 index 0000000000..c126eab7f9 --- /dev/null +++ b/NTO/WorkOrder/verbs/Assigned.ttl @@ -0,0 +1,16 @@ +@prefix ogit: . +@prefix ogit.WorkOrder: . +@prefix rdfs: . +@prefix dcterms: . + +ogit.WorkOrder:assigned + a rdfs:Class; + rdfs:subClassOf ogit:Verb; + rdfs:label "assigned"; + dcterms:description "User assigned to Order (work assignment). A User may be assigned to many Orders, and an Order may have many assigned Users over time via creation and history (many-to-many)." ; + dcterms:source "AdaWorldAPI/WoA/models.py:WorkOrder.created_by -> User.id; HistoryEntry.user_id -> User.id" ; + ogit:scope "NTO"; + ogit:from-to ( + [ ogit:from ogit.WorkOrder:User ; ogit:to ogit.WorkOrder:Order ] + ) ; +. diff --git a/NTO/WorkOrder/verbs/BelongsToTenant.ttl b/NTO/WorkOrder/verbs/BelongsToTenant.ttl new file mode 100644 index 0000000000..a9080a38d0 --- /dev/null +++ b/NTO/WorkOrder/verbs/BelongsToTenant.ttl @@ -0,0 +1,21 @@ +@prefix ogit: . +@prefix ogit.WorkOrder: . +@prefix rdfs: . +@prefix dcterms: . + +ogit.WorkOrder:belongsToTenant + a rdfs:Class; + rdfs:subClassOf ogit:Verb; + rdfs:label "belongsToTenant"; + dcterms:description "Every multi-tenant business entity belongs-to-tenant (mandatory partition for row-level isolation). Many entities of any business class belong to one Tenant (many-to-one)." ; + dcterms:source "AdaWorldAPI/WoA/models.py: tenant_id FK on User, Customer, Article, WorkOrder, PasswordEntry, TimeSheet, NumberSequence, Setting -> Tenant.id" ; + ogit:scope "NTO"; + ogit:from-to ( + [ ogit:from ogit.WorkOrder:User ; ogit:to ogit.WorkOrder:Tenant ] + [ ogit:from ogit.WorkOrder:Customer ; ogit:to ogit.WorkOrder:Tenant ] + [ ogit:from ogit.WorkOrder:Article ; ogit:to ogit.WorkOrder:Tenant ] + [ ogit:from ogit.WorkOrder:Order ; ogit:to ogit.WorkOrder:Tenant ] + [ ogit:from ogit.WorkOrder:PasswordEntry ; ogit:to ogit.WorkOrder:Tenant ] + [ ogit:from ogit.WorkOrder:TimeSheet ; ogit:to ogit.WorkOrder:Tenant ] + ) ; +. diff --git a/NTO/WorkOrder/verbs/Drives.ttl b/NTO/WorkOrder/verbs/Drives.ttl new file mode 100644 index 0000000000..29b2469c5b --- /dev/null +++ b/NTO/WorkOrder/verbs/Drives.ttl @@ -0,0 +1,16 @@ +@prefix ogit: . +@prefix ogit.WorkOrder: . +@prefix rdfs: . +@prefix dcterms: . + +ogit.WorkOrder:drives + a rdfs:Class; + rdfs:subClassOf ogit:Verb; + rdfs:label "drives"; + dcterms:description "User drives (records) a LogbookEntry (Fahrtenbuch trip with km, route, vehicle, business/private split). One User can drive many LogbookEntries (one-to-many)." ; + dcterms:source "AdaWorldAPI/WoA/models.py:LogbookEntry.user_id -> User.id" ; + ogit:scope "NTO"; + ogit:from-to ( + [ ogit:from ogit.WorkOrder:User ; ogit:to ogit.WorkOrder:LogbookEntry ] + ) ; +. diff --git a/NTO/WorkOrder/verbs/HasActivity.ttl b/NTO/WorkOrder/verbs/HasActivity.ttl new file mode 100644 index 0000000000..5a228c428e --- /dev/null +++ b/NTO/WorkOrder/verbs/HasActivity.ttl @@ -0,0 +1,16 @@ +@prefix ogit: . +@prefix ogit.WorkOrder: . +@prefix rdfs: . +@prefix dcterms: . + +ogit.WorkOrder:hasActivity + a rdfs:Class; + rdfs:subClassOf ogit:Verb; + rdfs:label "hasActivity"; + dcterms:description "Order has-many Activity records (work performed on devices). One Order can record many Activities (one-to-many, cascade-delete)." ; + dcterms:source "AdaWorldAPI/WoA/models.py:WorkOrder.activities -> Activity.workorder_id" ; + ogit:scope "NTO"; + ogit:from-to ( + [ ogit:from ogit.WorkOrder:Order ; ogit:to ogit.WorkOrder:Activity ] + ) ; +. diff --git a/NTO/WorkOrder/verbs/HasHistory.ttl b/NTO/WorkOrder/verbs/HasHistory.ttl new file mode 100644 index 0000000000..eb6062734d --- /dev/null +++ b/NTO/WorkOrder/verbs/HasHistory.ttl @@ -0,0 +1,16 @@ +@prefix ogit: . +@prefix ogit.WorkOrder: . +@prefix rdfs: . +@prefix dcterms: . + +ogit.WorkOrder:hasHistory + a rdfs:Class; + rdfs:subClassOf ogit:Verb; + rdfs:label "hasHistory"; + dcterms:description "Order has-many HistoryEntry audit records (status transitions, edits). One Order accumulates many HistoryEntries (one-to-many, cascade-delete, ordered by created_at desc)." ; + dcterms:source "AdaWorldAPI/WoA/models.py:WorkOrder.history -> HistoryEntry.workorder_id" ; + ogit:scope "NTO"; + ogit:from-to ( + [ ogit:from ogit.WorkOrder:Order ; ogit:to ogit.WorkOrder:HistoryEntry ] + ) ; +. diff --git a/NTO/WorkOrder/verbs/HasPicture.ttl b/NTO/WorkOrder/verbs/HasPicture.ttl new file mode 100644 index 0000000000..9f0571bec8 --- /dev/null +++ b/NTO/WorkOrder/verbs/HasPicture.ttl @@ -0,0 +1,16 @@ +@prefix ogit: . +@prefix ogit.WorkOrder: . +@prefix rdfs: . +@prefix dcterms: . + +ogit.WorkOrder:hasPicture + a rdfs:Class; + rdfs:subClassOf ogit:Verb; + rdfs:label "hasPicture"; + dcterms:description "Order has-many Picture attachments (photos for documentation, logbook, or customer-facing). One Order can attach many Pictures (one-to-many, cascade-delete)." ; + dcterms:source "AdaWorldAPI/WoA/models.py:WorkOrder.pictures -> Picture.workorder_id" ; + ogit:scope "NTO"; + ogit:from-to ( + [ ogit:from ogit.WorkOrder:Order ; ogit:to ogit.WorkOrder:Picture ] + ) ; +. diff --git a/NTO/WorkOrder/verbs/HasPosition.ttl b/NTO/WorkOrder/verbs/HasPosition.ttl new file mode 100644 index 0000000000..3225a0d6f4 --- /dev/null +++ b/NTO/WorkOrder/verbs/HasPosition.ttl @@ -0,0 +1,16 @@ +@prefix ogit: . +@prefix ogit.WorkOrder: . +@prefix rdfs: . +@prefix dcterms: . + +ogit.WorkOrder:hasPosition + a rdfs:Class; + rdfs:subClassOf ogit:Verb; + rdfs:label "hasPosition"; + dcterms:description "Order has-many Position line items. One Order can carry many Positions (one-to-many, cascade-delete)." ; + dcterms:source "AdaWorldAPI/WoA/models.py:WorkOrder.positionen -> Position.workorder_id" ; + ogit:scope "NTO"; + ogit:from-to ( + [ ogit:from ogit.WorkOrder:Order ; ogit:to ogit.WorkOrder:Position ] + ) ; +. diff --git a/NTO/WorkOrder/verbs/Issued.ttl b/NTO/WorkOrder/verbs/Issued.ttl new file mode 100644 index 0000000000..0124d9b3e1 --- /dev/null +++ b/NTO/WorkOrder/verbs/Issued.ttl @@ -0,0 +1,16 @@ +@prefix ogit: . +@prefix ogit.WorkOrder: . +@prefix rdfs: . +@prefix dcterms: . + +ogit.WorkOrder:issued + a rdfs:Class; + rdfs:subClassOf ogit:Verb; + rdfs:label "issued"; + dcterms:description "Customer issued an Order. One Customer can issue many Orders (one-to-many)." ; + dcterms:source "AdaWorldAPI/WoA/models.py:WorkOrder.customer_id -> Customer.id" ; + ogit:scope "NTO"; + ogit:from-to ( + [ ogit:from ogit.WorkOrder:Customer ; ogit:to ogit.WorkOrder:Order ] + ) ; +. diff --git a/NTO/WorkOrder/verbs/LogsTime.ttl b/NTO/WorkOrder/verbs/LogsTime.ttl new file mode 100644 index 0000000000..0ad2cda18a --- /dev/null +++ b/NTO/WorkOrder/verbs/LogsTime.ttl @@ -0,0 +1,16 @@ +@prefix ogit: . +@prefix ogit.WorkOrder: . +@prefix rdfs: . +@prefix dcterms: . + +ogit.WorkOrder:logsTime + a rdfs:Class; + rdfs:subClassOf ogit:Verb; + rdfs:label "logsTime"; + dcterms:description "User logs-time on a TimeSheet entry (billable minutes per Customer/day). One User can log many TimeSheet rows (one-to-many)." ; + dcterms:source "AdaWorldAPI/WoA/models.py:TimeSheet.user_id -> User.id" ; + ogit:scope "NTO"; + ogit:from-to ( + [ ogit:from ogit.WorkOrder:User ; ogit:to ogit.WorkOrder:TimeSheet ] + ) ; +. diff --git a/NTO/WorkOrder/verbs/OwnsPasswords.ttl b/NTO/WorkOrder/verbs/OwnsPasswords.ttl new file mode 100644 index 0000000000..01dcf4350c --- /dev/null +++ b/NTO/WorkOrder/verbs/OwnsPasswords.ttl @@ -0,0 +1,16 @@ +@prefix ogit: . +@prefix ogit.WorkOrder: . +@prefix rdfs: . +@prefix dcterms: . + +ogit.WorkOrder:ownsPasswords + a rdfs:Class; + rdfs:subClassOf ogit:Verb; + rdfs:label "ownsPasswords"; + dcterms:description "Customer owns-passwords (Fernet-encrypted vault entries). One Customer can own many PasswordEntry records in their KeePass-style vault (one-to-many)." ; + dcterms:source "AdaWorldAPI/WoA/models.py:PasswordEntry.customer_id -> Customer.id" ; + ogit:scope "NTO"; + ogit:from-to ( + [ ogit:from ogit.WorkOrder:Customer ; ogit:to ogit.WorkOrder:PasswordEntry ] + ) ; +. diff --git a/NTO/WorkOrder/verbs/RefersToArticle.ttl b/NTO/WorkOrder/verbs/RefersToArticle.ttl new file mode 100644 index 0000000000..e3b5499f61 --- /dev/null +++ b/NTO/WorkOrder/verbs/RefersToArticle.ttl @@ -0,0 +1,16 @@ +@prefix ogit: . +@prefix ogit.WorkOrder: . +@prefix rdfs: . +@prefix dcterms: . + +ogit.WorkOrder:refersToArticle + a rdfs:Class; + rdfs:subClassOf ogit:Verb; + rdfs:label "refersToArticle"; + dcterms:description "Position refers-to an Article in the catalogue (price, description source). Many Positions may reference the same Article (many-to-one, optional)." ; + dcterms:source "AdaWorldAPI/WoA/models.py:Position.article_id -> Article.id" ; + ogit:scope "NTO"; + ogit:from-to ( + [ ogit:from ogit.WorkOrder:Position ; ogit:to ogit.WorkOrder:Article ] + ) ; +.