Zum Inhalt

Auftragsverwaltung (Ordermanagement) V1 — Funktionsumfang & V2-Gap-Analyse

Stand: 2026-07-20 · Scope: Auftragsverwaltung („Ordermanagement") in calServer V1 (Yii 1.1, Kerntabelle booking) — vollständiger Funktionsumfang inkl. Kundenrollen (Rechnungs-/Lieferkunde), Preismanagement, Sammelrechnung, Teillieferung/-rechnung und der Auftrags-Reportpipeline (Angebot → Auftrag → Lieferung → Rechnung) — verglichen mit dem aktuellen V2-Stand (Laravel 13 + Nuxt 3).

Kurzfazit: Ein V1-Auftrag trägt über seinen Statusworkflow den gesamten Lebenszyklus von Angebot über Auftragsbestätigung, Lieferschein und Rechnung bis zur Fertigstellung — mit drei getrennten Kundenrollen (Hauptkunde, Lieferkunde, Rechnungskunde) samt eigener Kontakte, Preisfindung über Preisgruppen und einer Jasper-Reportpipeline, die alle vier Dokumenttypen aus demselben Auftrag erzeugt. V2 hat den Kern bereits nachgebaut (CRUD, Statusworkflow, Positionen, Sammelaufträge, Preise, order-document-Report) — deutlich mehr, als die veraltete v1-v2-analysis.md ausweist. Es verbleiben sechs konkrete, belegbare Lücken (Abschnitt 12), u. a. das nicht ausgewertete Kunden-Sichtbarkeitsmodell, fehlende Schnellerfassungswege und ein V2-Ordertemplate, das Liefer-/Rechnungsadresse und W41xx-Felder noch nicht rendert.

Dieses Dokument ergänzt die v2-roadmap.md und ersetzt inhaltlich den Auftrags-Abschnitt (§2.8) der veralteten v1-v2-analysis.md.


Inhaltsverzeichnis

  1. Zweck, Scope und Methodik
  2. Architektur-Überblick V1
  3. Datenmodell
  4. Kundenrollen und Adresslogik
  5. Lebenszyklus und Statusworkflow
  6. Positionen (article)
  7. Preismanagement
  8. Sammelrechnung, Teillieferung und Teilrechnung
  9. Reports und Dokumenttypen
  10. Nebenfunktionen
  11. W41xx-Feldkatalog
  12. Gap-Analyse V1 → V2 und Backlog
  13. Anhang

1. Zweck, Scope und Methodik

Zweck: Referenzdokument für die (Re-)Implementierung der Auftragsverwaltung in V2. Es beantwortet zwei Fragen: Was kann V1 vollständig? und Was davon fehlt in V2 noch? Die Gap-Tabelle in Abschnitt 12 ist als direkt umsetzbarer Backlog formuliert.

Scope:

  • V1-Modul Auftragsverwaltung: Tabelle booking mit Positionen (article), Preismanagement (prices, price_category, standard_article), Sammelrechnungen (collective_invoices), Statusworkflow (status, audit) und der Auftrags-Reportpipeline.
  • V2-Gegenstücke in laravel/ und frontend-v2/ sowie die Report-Templates im Schwester-Repo calServer-reports und die Produktions-Templates unter httpdocs/reports/orders/.

Abgrenzung: Das V1-Modell FrontendArticle in diesem Kontext bezeichnet Auftragspositionen (Tabelle article mit booking_uID-FK). Das davon unabhängige News-/CMS-Modul („Artikel" im Sinne von Beiträgen, FrontendArticleController teilt sich den Namen) ist kein Bestandteil des Ordermanagements und wird hier nur zur Verwechslungsvermeidung erwähnt; sein V2-Gap wird in der v2-roadmap.md separat geführt.

Methodik: Codeanalyse von V1 (httpdocs/protected/), V2 (laravel/, frontend-v2/, report-runner/) und den Report-Templates (calServer-reports: ORDER-SAMPLE, ORDER-JSON-SAMPLE, DELIVERY-JSON-SAMPLE; Produktion: httpdocs/reports/orders/). Alle Aussagen sind mit pfad:zeile belegt. Zeilenangaben beziehen sich auf den Stand dieses Dokuments und können mit der Zeit driften — die Methoden-/Konstantennamen bleiben der stabile Anker.


2. Architektur-Überblick V1

Die Auftragsverwaltung ist im Frontend-Modul implementiert; es gibt kein eigenes Yii-Submodul. Lesepfad für Entwickler:

Baustein Datei Umfang
Fachmodell Auftrag httpdocs/protected/modules/frontend/models/FrontendBooking.php 3316 Zeilen: Relationen, Kundenrollen-Auflösung, Nummernkreise, Reportgenerierung, Statuslogik
Basismodell (generiert) httpdocs/protected/modules/frontend/models/base/BaseFrontendBooking.php Schema-Docblock, Defaults, Feldrechte
Controller httpdocs/protected/modules/frontend/controllers/FrontendBookingController.php 4499 Zeilen, ~70 Aktionen (vollständige Tabelle in Anhang A)
Views httpdocs/protected/modules/frontend/views/frontendBooking/ Grid, Detail (view.php, 76 KB), Assign-Dialoge, Mail, Export
Positionen httpdocs/protected/modules/frontend/models/FrontendArticle.php (+ Base) Tabelle article, drei Positionstypen
Preise FrontendPrices, FrontendPriceCategory, FrontendStandardArticle (+ FrontendPriceController, FrontendArticleController) Preisgruppen-Matrix, Katalogartikel
Sammelrechnung FrontendCollectiveInvoices Pivot collective_invoices
Status FrontendStatus (+ base/BaseFrontendStatus.php) status-Zeilen mit type='booking'
Reports FrontendBooking::exportMasterReport() + Adminpanel (AdminReportSetting, AdminReportVariable) JasperReports (JRXML)

Der Detail-Screen (views/frontendBooking/view.php) gliedert sich in obere Tabs (Auftragsdaten / Kunde / Rechnungsadresse / Lieferadresse / Kategorie, view.php:147-267) und untere Tabs (Übersicht / Geräte / Artikel / Typen / Dokumente / Historie / Aktionen / Weitere Aufträge, view.php:288-434).


3. Datenmodell

3.1 Beteiligte Tabellen

Tabelle Zweck V1-Modell V2-Stand
booking Auftragskopf (eine Zeile = ein Auftrag über den ganzen Lebenszyklus) FrontendBooking Neue Tabelle bookings mit lesbaren Spalten (laravel/database/migrations/2026_02_28_500001_create_booking_table.php)
article Auftragspositionen FrontendArticle V1-Schema beibehalten (laravel/app/Models/Article.php)
prices Preisliste (Gerätetyp × Preisgruppe) FrontendPrices V2-Migration (2026_02_28_600000_create_price_tables.php)
price_category Preisgruppen FrontendPriceCategory V2-Migration (ebd.)
standard_article Katalogartikel FrontendStandardArticle V2-Migration (2026_02_28_500006_create_standard_article_table.php)
collective_invoices Sammelrechnungs-Pivot FrontendCollectiveInvoices V1-Schema beibehalten (laravel/app/Models/CollectiveInvoice.php)
status (type='booking') Statusdefinitionen inkl. Zähler/Automatiken FrontendStatus Status::TYPE_BOOKING
audit Statushistorie, Durchlaufzeiten FrontendAudit Audit-Infrastruktur vorhanden (Booking nutzt Auditable)
booking_type Auftragsvorlagen (vorbelegte Positionslisten) — (Grid-Konfig m170215_102753) kein dediziertes V2-Gegenstück gefunden
customers, contact Kundenstamm + Ansprechpartner FrontendCustomer, FrontendContact Customer (V2-Tabelle), Contact (V1-Schema)

3.2 Auftragskopf booking

Spalten laut Basismodell (base/BaseFrontendBooking.php:18-54) und Install-Migration (httpdocs/protected/migrations/m130220_194523_install.php:33-49):

Spalte Typ Bedeutung
uID varchar(36), PK UUID, vergeben via Uuid::create() (BaseFrontendBooking.php:85)
customer_KTAG varchar(80) Hauptkunde (Besteller)
number varchar Auftragsnummer (Pflichtfeld, BaseFrontendBooking.php:88), aus Nummernkreis (Abschnitt 5.3)
date date Auftragsdatum, Default heute (BaseFrontendBooking.php:92-94)
customer_contact_id varchar(36) Ansprechpartner Hauptkunde (m170630_094135_add_contact_field_for_customer_booking.php)
delivery_contact_id, invoice_contact_id varchar(36) Ansprechpartner Liefer-/Rechnungsempfänger (m170327_092359_add_different_customer_contact_for_booking_table.php)
delivery_customer_KTAG, invoice_customer_KTAG varchar Abweichender Liefer-/Rechnungskunde (m220328_033736_update_customer_fields_for_booking_table.php)
status varchar(100) Statustitel (referenziert status.title mit type='booking')
comment text Freitext
delivery_costs double Versandkosten auf Kopfebene (m160929_092258_add_delivery_costs_field_to_booking_table.php)
delivery_condition varchar Lieferbedingung, Default 'shipping' (BaseFrontendBooking.php:96-98)
modified, modified_by int, varchar Änderungsstempel
W4101W4122 varchar(255) Frei konfigurierbare Zusatzfelder (Abschnitt 11); eingeführt via m150818_031621_insert_batch_column_into_booking_table.php (W4101–W4111 string, W4112–W4122 double), vereinheitlicht auf VARCHAR(255) in m180207_083600_change_W41xx_fields_to_VARCHAR_255.php

V2-Mapping: Die neue Tabelle bookings übernimmt die Struktur mit lesbaren Spaltennamen und UUID-PK; die drei Kontakt- und zwei Zusatzkunden-Spalten existieren 1:1 (customer_contact_id, delivery_contact_id, invoice_contact_id, delivery_customer_id, invoice_customer_id, 2026_02_28_500001_create_booking_table.php:23-27), delivery_costs als decimal(13,2) und delivery_condition ebenfalls (:30-31). Die W41xx-Felder sind in eine JSON-Spalte custom_fields konsolidiert (:34), angebunden über den HasDynamicFields-Trait und die field_definitions-Registry (laravel/app/Services/FieldManagement/FieldDefinitionService.php, TABLE_MAP mappt bookings/bookingtable_name='booking').

3.3 Relationen des Auftrags

FrontendBooking::relations() (FrontendBooking.php:419-599):

  • customer (BELONGS_TO FrontendCustomer via customer_KTAG), deliveryCustomer / invoiceCustomer (via delivery_customer_KTAG / invoice_customer_KTAG, :427-428)
  • contact / delivery_contact / invoice_contact (via die drei *_contact_id, :424-426)
  • articles (HAS_MANY FrontendArticle via booking_uID, eager-load inventory, :429-435); inventories (dasselbe gefiltert auf article_type='inventory', :436-443)
  • statusModel (HAS_ONE FrontendStatus auf title=status AND type='booking' AND active=1, :444-449)
  • otherOrders (HAS_MANY FrontendCollectiveInvoices via invoice_uID) und otherArticles (Positionen der eingebundenen Aufträge, :451-459)
  • categoryItems (Kategorien, :460-463), modifiedUser (:464)
  • Dynamische Dokument-Relationen aus AdminFileSetting::getDocumentRelations("booking") (:471-480) und Status-Zeitstempel-Relationen aus der audit-Tabelle für Durchlaufzeit-Auswertungen (:482-596)

Das V2-Modell laravel/app/Models/Booking.php bildet dieselben Relationen ab (customer, customerContact, deliveryContact, invoiceContact, deliveryCustomer, invoiceCustomer, articles, collectiveInvoices, collectiveArticles, modifiedBy).


4. Kundenrollen und Adresslogik

Das ist der vom Nutzer besonders hervorgehobene Kern: Ein Auftrag kennt drei Kundenrollen mit je eigenem Ansprechpartner.

4.1 Rollen und Fallback-Präzedenz

Rolle Kunde Kontakt Fallback
Besteller (Hauptkunde) customer_KTAG customer_contact_id
Rechnungskunde invoice_customer_KTAG invoice_contact_id Hauptkunde
Lieferkunde delivery_customer_KTAG delivery_contact_id Hauptkunde
  • getBillingCustomer() (FrontendBooking.php:1053-1093) nutzt invoice_customer_KTAG und fällt bei Leere auf customer_KTAG zurück; angezeigt wird der Name (K4602) samt Info-Button, der u. a. die Preisgruppe des Kunden (price_cat_uID, getGroupName()) trägt — Rechnungskunde und Preisfindung sind also gekoppelt (Abschnitt 7).
  • getDeliveryCustomer() (:1101-1141) analog für den Lieferkunden.
  • getActiveContactsByType() (:1149-1205) liefert die Kontaktauswahl je Rolle: für TYPE_INVOICE die activeInvoiceContacts des Rechnungskunden (sonst des Hauptkunden), für TYPE_DELIVERY die activeDeliveryContacts des Lieferkunden, sonst activeContacts.
  • Grid-Pseudofelder: fieldMap (:198-202) mappt billing_customer[invoice_customer_KTAG, customer_KTAG] und delivery_customer[delivery_customer_KTAG, customer_KTAG], sodass Suche/Sortierung im Grid die Fallback-Logik berücksichtigt. Gruppenkopf-Varianten: getBillingCustomerForGroupHeader() / getDeliveryCustomerForGroupHeader() (:653-700).

4.2 Zuweisungs- und Adressaktionen

  • actionAssignCustomer() (FrontendBookingController.php:746-803): Weiche über connectCustomer = FrontendCustomer::MAIN_CUSTOMER (setzt customer_KTAG und nullt alle drei Kontakte), DELIVERY_CUSTOMER (setzt delivery_customer_KTAG), sonst Rechnungskunde.
  • actionAssignDeliveryContact() (:862) / actionAssignInvoiceContact() (:893)
  • Adresspflege direkt aus dem Auftrag: actionGetCompanyAddress() (:2404), actionRefreshAddress() (:2421), actionResetAddress() (:3206), actionAddNewAddress() (:2337), actionSaveContact() (:2266), actionCloneContact() (:2305).
  • Kunden-Popups: actionGetCustomerDetail() (:3249), actionGetCustomerDetailToView() (:3288).
  • Die Adressfelder des Kunden (K4601K4640) sind als externe Spalten am Auftragsmodell deklariert und gelabelt (FrontendBooking.php:24-65,136-221), damit Grid/Report sie direkt anzeigen können (K4602=Name, K4613=Vorname, K4614=Firma, K4615=Abteilung, K4619=E-Mail).

4.3 Empfängerauflösung für Mailversand

getTokenValues() (FrontendBooking.php:2066-2146) wählt für Rechnungs-Statusarten bevorzugt invoice_contact/invoiceCustomer, sonst den Hauptkunden, und erzeugt die Mail-Platzhalter [FIRSTNAME], [LASTNAME], [FULLNAME], [EMAIL], [FIRM], [NUMBER], [STATUS] (+ Kleinschreibvarianten) für die Statusmailvorlagen (Abschnitt 10.4).

4.4 V2-Stand

Schema, Modellrelationen, Validierung und UI sind vorhanden: Die Booking-Detailseite (frontend-v2/pages/booking/[id].vue) zeigt Kontaktkarten für alle drei Rollen inkl. resetContact('delivery'|'invoice'); OrderDocumentDataBuilder löst die drei Adressrollen mit V1-identischer Fallback-Präzedenz für Reports auf. Aber: Die Kundenauswahl selbst hängt am Kundenstamm, dessen V1-Sichtbarkeitsmodell (zuweisungsbasiert via map_user, group_customer, user_group, customer_filter) in V2 nicht ausgewertet wird — jeder Nutzer mit customers_view sieht alle Kunden. Details und Belege: CUSTOMER_HANDLING_V1_V2_REVIEW.md. Für die Auftragsverwaltung heißt das: Liefer-/Rechnungskunden-Picker zeigen aktuell mehr Kunden, als der Nutzer sehen dürfte (Gap G1 in Abschnitt 12).


5. Lebenszyklus und Statusworkflow

5.1 Statuskette

Ein Auftrag durchläuft den Lebenszyklus als Statuswechsel derselben Zeile — Angebot, Auftragsbestätigung, Lieferschein und Rechnung sind keine getrennten Entitäten. Kanonische Statusgruppen (FrontendBooking.php:91-118):

Konstante Werte Dokumenttyp
OFFER_STATUS Offer, Angebot Angebot
ORDER_STATUS Order, Auftrag Auftragsbestätigung
ORDER_IN_HOUSE_STATUS Order_in_house, Auftrag im Haus interner Zwischenstatus (Geräte eingetroffen)
DELIVERY_STATUS Delivery, Lieferung Lieferschein
BILLING_STATUS Billing, Invoice, Rechnung Rechnung
STATUS_PART Billing/Invoice/Rechnung + Delivery/Lieferung Statusarten mit Teil-Logik (Abschnitt 8.2)

Die Übersetzung der Statusnamen ist in FrontendArticle::getTranslatedStatus() (FrontendArticle.php:524-563) bzw. FrontendBooking::getTranslatedStatus() (:1255) hinterlegt (u. a. Normalisierung BillingInvoice). Ein zusätzlicher „NEW"-Status wurde mit m170410_081147_add_NEW_status_for_booking_type.php eingeführt. Die konkreten Statuszeilen sind konfigurierbar (Tabelle status, type='booking') — Installationen können weitere Zwischenstatus definieren; die Konstanten decken die dokumentrelevanten Gruppen ab.

5.2 Status als Automatisierungsträger

Eine Statuszeile (base/BaseFrontendStatus.php:17-40) trägt neben Titel, Kurzzeichen, Farbe/Icon und Sortierung eine Reihe von Automatik-Flags.

Korrektur (2026-08). Eine frühere Fassung dieses Abschnitts hat diese Flags als Auftragsautomatik beschrieben. Das ist am Code widerlegt: beim Auftrags-Statuswechsel wertet V1 von ihnen kein einziges als Aktion aus. actionChangeStatus() (FrontendBookingController.php:3697-3775) liest ausschließlich getMandatoryFields(), getFieldsAreEmptyNow() und getFieldsHaveDefaultValue() — alles aus additional_field, nichts aus status.

Die Zuordnung steht in FrontendStatusController::actionGetStatus (:228-240), dem einzigen Endpunkt, der die Flag-Gruppe ausliefert:

'condition' => "title = '$title' AND `type` = 'inventory'"   // hart verdrahtet

Dass die Flags auch an einer type='booking'-Zeile stehen, ist ein Artefakt der über type geteilten status-Tabelle, kein Feature.

Flag Gilt für Wirkung
counter Auftrag (u. a.) Laufnummer für Nummernkreise (Abschnitt 5.3). Das einzige Flag, das im Auftragspfad wirklich zieht.
mailer_template_id Auftrag, nur Oberfläche Belegt die Mailvorlage im manuellen Versanddialog vor (FrontendBookingController.php:3062). Kein Statuswechsel-Effekt. FrontendBooking::getEmailTemplateId() (:2027) liest es ebenfalls, hat aber keinen Aufrufer.
mailer_report Inventar-Status Zeilenfilter des Fälligkeits-/Kritisch-Mailers: = 0 blendet Geräte mit diesem Inventarstatus aus dem Report aus (MailerSender.php:629,677, emailPrint.php:91-92). Tri-state — NULL verhält sich wie 1, deshalb ein Select statt einer Checkbox.
new_order Inventar-Statusmaske Blendet den Block „Create or Assign to Order" ein; bei gesetztem Schalter entsteht aus der Gerätemaske ein neuer Auftrag mit Status draft samt Positionen (FrontendInventoryController.php:2809-2878, :3076-3109).
set_remember_date Inventar-Statusmaske Legt je Gerät einen notepad-Eintrag (Wiedervorlage) an, sofern Datum, Zeit und Kommentar gefüllt sind (:2977).
set_new_location Inventar-Statusmaske Legt bzw. aktualisiert je Gerät einen location-Datensatz; fehlende Pflichtfelder rollen die Transaktion zurück (:3006, :3041-3048).
check_new_inventory Inventar-Statusmaske Beim Batch-Einlesen gescannter Seriennummern: = 1 bietet unbekannte Nummern zur Neuanlage an, = 0 verwirft sie stillschweigend (:2745).
check_edit_inventory Inventar-Statusmaske Reine Blocksichtbarkeit (apply_status.php:1413), keine Serverlogik.
new_article Inventar-Statusmaske Reine Blocksichtbarkeit (apply_status.php:1415). Das Anlegen der article-Zeilen hängt an bookings_details_edit, nicht an diesem Flag.
new_calibration Inventar-Statusmaske Reine Blocksichtbarkeit (apply_status.php:1414). In BaseFrontendStatus nicht einmal deklariert; der Zugriff funktioniert nur über das AR-Schema.
close_metteam_calibration Kalibrier-Status Schließt nach dem MSSQL-Sync den verknüpften MET/TEAM-Arbeitsauftrag (FrontendCalibrationController.php:592 u. a.). Wird im Booking-Kontext nie ausgewertet.
active, hide alle Sichtbarkeit

5.3 Nummernkreise

Auftrags-/Belegnummern entstehen aus Templates mit Tokens [STATUS_NAME]/[STATUS_SHORT]/[STATUS_COUNT] bzw. [CATEGORY_*] (components/InventoryHelper.php:28-29,1149-1152,1978-1998):

  • actionCreateNewBookingNumber() (FrontendBookingController.php:1119) → getNewBookingNumberFromStatus() / getNewBookingNumberFromCategory() (FrontendBooking.php:1675-1740): löst das Template über InventoryHelper::getDefaultValue('booking','number',…) auf und inkrementiert bei Kollision den status.counter bzw. category.counter mit Retry.
  • Konfliktsichere Zählervergabe: components/CounterService.php + CounterReservation.php.
  • Beispiel-Template aus dem Default-Feldkatalog: [STATUS_SHORT]-[YYYY]-[STATUS_COUNT]AN-2026-0042 (Abschnitt 11).

V2: BookingController::generateNumber + laravel/app/Services/Booking/BookingNumberService.php decken den Status-Nummernkreis ab.

5.4 Statuswechsel-Semantik

actionChangeStatus() (FrontendBookingController.php:3697-3775; Link-Variante actionSetStatus() :1441):

  1. Validiert den Zielstatus und prüft statusModel->getMandatoryFields(); fehlende Pflichtfelder öffnen ein Modal, das über actionSaveAdditionalFields() (:3904) nachträgt.
  2. Speichert und schreibt Änderungshistorie (saveChangesHistory(), FrontendBooking::saveHistory() :2193) in die audit-Tabelle.
  3. Wendet Status-Feldregeln an: getFieldsAreEmptyNow() leert definierte Felder, getFieldsHaveDefaultValue() berechnet Defaults neu (via InventoryHelper::getDefaultValue) — so bekommt z. B. die Rechnung beim Statuswechsel ihre eigene Belegnummer in ein W41xx-Feld (Abschnitt 11).
  4. Implizit über FrontendBooking::afterSave() (:743-752) → assignStatus() (components/Model.php:3400-3428): trägt das Nummern-Template ein [STATUS_COUNT]-Token, reserviert CounterReservation::reserveStatusCounter() die nächste Laufnummer. Das ist der einzige flaggesteuerte Seiteneffekt des Auftrags-Statuswechsels.

Dieselbe Semantik dupliziert der Inline-Edit im Grid (actionUpdateField(), :1679-1734, Zweig $field == 'status') samt reload-Handling für hasStatusInDefaultValue().

actionSetStatus() ist trotz der Bezeichnung „Link-Variante" kein Äquivalent: keine Pflichtfeldprüfung, keine empty_now-/Default-Regeln, dafür ein Property-basierter Mailversand (settings/booking/notification_subject|notification_body) — nicht flaggesteuert.

5.5 Durchlaufzeiten / Fertigstellung

Aus der audit-Historie baut das Modell pro Status Start-/Stopp-Zeitstempel als dynamische Relationen (FrontendBooking.php:482-596) und aggregiert Durchlaufzeiten (getProcessingTime() :2906) — die Grundlage für SLA-/Fertigstellungs-Auswertungen im Grid und Dashboard (Widget ORDER_ENTRIES_BY_STATUS, :88-89).

V2: Booking nutzt HasStatusTransitions + Auditable; BookingController::changeStatus/saveAdditionalFields/audits bilden den Workflow ab (Pflichtfeld-Prüfung inklusive).


6. Positionen (article)

Positionen sind Zeilen der Tabelle article mit FK booking_uID (m130220_194523_install.php:11-23).

6.1 Drei Positionstypen

FrontendArticle (FrontendArticle.php:19-21):

article_type Quelle Verknüpfung
inventory Ein konkretes Gerät (FrontendInventory) article_ID = MTAG des Geräts
article Katalogartikel (FrontendStandardArticle) article_ID = standard_article.uID
type Gerätetyp-Leistung mit Preisliste (FrontendTypes + FrontendPrices) article_ID → Typ, Preis via typePrice-Relation

Polymorphe Relationen und Namensauflösung je Typ: FrontendArticle.php:204-212, getArticleName() :393-435.

6.2 Positionsfelder

base/BaseFrontendArticle.php:17-36: quantity, price (Ablage in Cent!, Kommentar in m130220_194523_install.php:16), discount (%), costs, delivery_costs (positionsbezogen), tax (MwSt.-Satz je Position), unit, pos_number (auto max+1 je Auftrag, beforeSave() FrontendArticle.php:229-241), complexity, calibration_type, comment, delivery_date/billing_date, billing_part/delivery_part (Teil-Zuordnung, Abschnitt 8.2) sowie eigene Zusatzfelder A4301A4320 (BaseFrontendArticle.php:148-167). Währung, Steuer und Einheit kamen mit m160929_031423/m160930_022717 in Feldkonfiguration und Tabelle.

6.3 Erfassungswege im UI

  • Geräte zuordnen: actionAssignInventoryUpdate() (FrontendBookingController.php:655), Mehrfachübernahme actionAddArticles($booking_id,$inventory_ids) (:808), Barcode-Lookup über die Inventarsuche.
  • Katalogartikel: actionAssignStandardArticle() (:2183) bzw. aus dem Artikel-Modul FrontendArticleController::actionAssignStandardArticle (FrontendArticleController.php:447).
  • Typ-Positionen: actionAssignType() (:2221 bzw. FrontendArticleController.php:502).
  • Listen/Lookups: actionListArticles() (:2051), actionListStandardArticles() (:2098), actionListTypes() (:2138).

6.4 Rückverweis am Gerät

calibration.C2314 = „letzte Auftragsnummer" verknüpft Gerätehistorie und Auftrag (m170925_034912_add_last_order_number_C2314_for_inventory_grid.php; Suche/Sortierung FrontendCalibration.php:1153-1163). Das Inventar-Grid bietet last_order_number, last_delivery_customer, last_location_customer (FrontendBookingController.php:661-665).

V2: Article-Modell (V1-Schema inkl. A43xx, polymorph auf Inventory/StandardArticle) + ArticleController (CRUD) + BookingController::assignStandardArticle sind vorhanden.


7. Preismanagement

7.1 Preisliste prices

base/BaseFrontendPrices.php:19-31: Ein Preis gilt je Gerätetyp (type_tID) und Preisgruppe (price_cat_uID) mit price, complexity (Aufwandsstufe), price_min/price_max, zeitlicher Gültigkeit (start_date/end_date), costs, quantity, unit, discount, tax. Validierungen: Preis ≥ 0, min ≤ max, start ≤ end (:73-117). Angelegt mit m170208_040802_add_table_for_price_mamagement.php (Rollen: m170208_071943).

7.2 Preisgruppen price_category

FrontendPriceCategory (uID, name, description): Kundensegmentierung — jeder Kunde referenziert seine Preisgruppe über customers.price_cat_uID. Die Preisfindung einer Typ-Position läuft damit: Rechnungskunde → Preisgruppe → prices-Zeile des Gerätetyps (sichtbar im Info-Button des Rechnungskunden, getBillingCustomer(), Abschnitt 4.1).

7.3 Katalogartikel standard_article

FrontendStandardArticle: article_name (unique), quantity, price, discount, delivery_costs, tax, unit, pos_number, calibration_type, comment — wiederverwendbare Positionen (Dienstleistungen, Pauschalen, Versandartikel).

7.4 Pflege-UI

  • FrontendPriceController: Preislisten-Grid (actionAdmin :209), Preisgruppen (actionCategory :170 + CRUD-Aktionen), Anlegen/Ändern/ Duplizieren (actionCreate/actionUpdate/actionClone :333/:403/:444), Inline-Edit, Lookups (actionAjaxTypeName :721, actionAjaxPriceGroup :745).
  • FrontendArticleController: Katalogartikel-CRUD (actionStandardArticle :268 ff.) und actionActualize (:555): aktualisiert Preise bereits zugeordneter Positionen aus den Stammdaten (Preis-Refresh im Auftrag).
  • Preise für Geräte-Positionen in Aufträgen: m241218_043547_insert_prices_for_inventory_in_orders.php; Zusatzfelder für die Preistabelle: m251002_073125_add_prices_table_for_add_field_configuration.php.

    Korrektur 2026-08-03: Hier standen procedure_provision, quality_provision und quality_provision_detail (m190221_020751, m190221_095402) als „Leistungs-/Qualitätszuschläge auf Verfahrensebene, die in die Preisfindung von Kalibrierleistungen einfließen". Das ist falsch. quality_provision ist ein Katalog von Qualitätsvorgaben, das Detail trägt Messbereich, Modus, Unsicherheit und Auflösung (range_start, range_end, uncertainty, resolution), und procedure_provision ist eine reine n:m-Zuordnung Prozedur ↔ Vorgabe mit genau zwei Spalten (procedure_uID, provision_uID, siehe BaseFrontendProcedureProvision). Kein Betrag, kein Prozentsatz, kein Preisbezug. V1 kennt keine Preiszuschläge. Der Irrtum war nach konzept-preisverwaltung-v2.md §6.3 weitergewandert und ist dort ebenfalls korrigiert.

7.5 V2-Stand

Price/PriceCategory/StandardArticle-Modelle und -Controller (CRUD, duplicate, bulkDestroy; RBAC price_*, price_category_*, article_*) sowie Frontend-Seiten frontend-v2/pages/price/, pages/price-category/ und pages/standard-article/ existieren. Lücke (Stand 2026-07-27): Katalogartikel und Preisgruppen sind inzwischen voll pflegbar (SettingsGrid), die Preisliste selbst hat aber kein Anlegen und kein Bearbeiten — pages/price/index.vue bietet nur Massenlöschen, pages/price/[id].vue ist reine Leseansicht, obwohl POST /prices, PUT /prices/{id} und POST /prices/{id}/duplicate serverseitig existieren. Ausbauplan: konzept-preisverwaltung-v2.md.


8. Sammelrechnung, Teillieferung und Teilrechnung

8.1 Sammelrechnung (collective_invoices)

Pivot-Tabelle (m170929_022104_add_collective_invoices_table.php) mit invoice_uID (der Rechnungs-Auftrag) und other_booking_uID (ein eingebundener Auftrag):

  • Zuordnung: actionAssignOrder() (FrontendBookingController.php:3305) / actionUnAssignOrder() (:3347); UI im Tab „Weitere Aufträge" (views/frontendBooking/assignOrder/, other_order/).
  • Positions-Vereinigung: Die Artikelsuche unioniert Positionen der eingebundenen Aufträge in den Rechnungs-Auftrag (FrontendArticle.php:753-755: … OR t.booking_uID IN (SELECT other_booking_uID FROM {{collective_invoices}} WHERE invoice_uID=…)).
  • Helfer: hasOtherOrder() (FrontendBooking.php:1555).
  • Die Rechnungsnummer ist die booking.number des Rechnungs-Auftrags (bzw. ein W41xx-Belegnummernfeld, Abschnitt 11); Kopf-delivery_costs und delivery_condition fließen in die Summenbildung des Reports ein.

8.2 Teillieferung / Teilrechnung

Für Statusarten in STATUS_PART (Lieferung, Rechnung) lassen sich Positionen in Teile aufspalten:

  • Flags billing_part/delivery_part je Position (m180330_044639_add_part_delivery_and_part_billing_for_article.php); Filterung in FrontendArticle::search() (:758-765).
  • Dialog-Aktionen: actionGetArticlesForPart() (:3390), actionSaveNewPart() (:3443), actionGetParts() (:3468).
  • Modell-Helfer: getMaxOrderPart(), saveNewPart(), getPartsForReport() (FrontendBooking.php:2808-2905).
  • Der Report erhält den Teil als Parameter Report_part (Abschnitt 9.1) und druckt dann nur die Positionen des gewählten Teil-Lieferscheins bzw. der Teilrechnung.

8.3 V2-Stand

CollectiveInvoice-Modell, BookingController::collectiveOrders/assignOrder/ unassignOrder, Frontend-Tab „Sammelaufträge" sowie Teil-Reports über BookingReportController (part=ALL|PARTIAL) sind vorhanden.


9. Reports und Dokumenttypen

Der Auftragsreport ist das zentrale Ausgabeinstrument: ein Template erzeugt je nach Status Angebot, Auftragsbestätigung, Lieferschein oder Rechnung.

9.1 V1-Pipeline

Reportdefinitionen liegen in AdminReportSetting (Adminpanel, Grid-Name booking). Kern: FrontendBooking::exportMasterReport($part,$report) (FrontendBooking.php:1314-1483):

  1. Ermittelt den JRXML-Pfad (getMainReportFilePath, Varianten resolveVariantPath() :1493, getJrxmlFilePath() :1517).
  2. Setzt die Jasper-Parameter (:1350-1420): Reportpath, Auftragsnummer, Auftragsid (uID), Sprache (Deutsch/Englisch), Dokumenttyp (übersetzter Status), Report_part (Teil-Nr. für Teillieferung/-rechnung), Articletype1..3 (Filter der Positionstypen).
  3. Wählt die statusabhängige Beschreibungsvariable (AdminReportVariable::getVariableContent(), :1381-1393):
  4. Offer/Angebot → booking_offer_report_description (Angebot)
  5. Order/Auftrag → booking_order_report_description (Auftragsbestätigung)
  6. Billing/Rechnung → booking_billing_report_description (Rechnung)
  7. Delivery/Lieferung + Order_in_house → booking_delivery_report_description (Lieferschein)
  8. Merged alle Reportvariablen, rendert via Jasper und liefert die Datei.

Aufrufwege im Controller: actionViewMasterReport() (:2708), actionPrintOrderReport() (:2859), actionDetailsPrint() (:1886), actionDeliveryFormPrint() (:1907), Listen-Druck (actionListPrint() :1964), Signatur (actionSign() :3611), DMS-Ablage (actionSaveToDms() :2958), Versand (actionSendReport() :3039, Abschnitt 10.4). REPORT_PARAMETERS (FrontendBooking.php:130-134) mappt Order_View.jrxml → [P_OrderID].

9.2 Templates

  • Produktion (httpdocs/reports/orders/): Angebot_V0.8, Angebot_V0.8_Billing, Angebot_V0.8_Billing_Group, Angebot_V0.8_Delivery, Order_View — jeweils mit Statistics/Statistics_Billing-Subreports. Das ist die maßgebliche Referenz für Layout, Adressrollen-Verwendung und W41xx-Einsatz.
  • Community/V1 (calServer-reports, ORDER-SAMPLE/): genericisierte Kopie — ein Template für alle vier Dokumenttypen, geschaltet über $P{Dokumenttyp}; eingebettetes SQL joint booking, article, collective_invoices, customers dreifach (Haupt-/Rechnungs-/Lieferkunde), contact dreifach, standard_article, prices, types, inventory. Subreport Statistics.jrxml: Netto/Steuergruppen/Rabatt/Brutto, Gesamtrabatt aus W4114.
  • Community/V2 (calServer-reports, ORDER-JSON-SAMPLE/, DELIVERY-JSON-SAMPLE/): SQL-frei, JSON-Datasource, gerendert vom report-runner (Java/JasperReports, report-runner/…/JsonDataSources.java).
  • Abgrenzung: DELIVERY-STANDALONE (calServer-reports) ist eine ältere, inventarbasierte Übergabeliste (Free_Delivery.jrxml) außerhalb des Auftragsflusses; V1 nutzt sie für den Schnellauftrag (Abschnitt 10.1).

9.3 V2-Datenvertrag order-document v1.0

Serverseitig baut laravel/app/Services/Report/OrderDocumentDataBuilder.php (Contract-Konstante order-document, :38) den Datensatz; abrufbar auch als GET /api/v2/bookings/{id}/report-dataset (BookingController::reportDataset). Struktur (Beleg: ORDER-JSON-SAMPLE/main_reports/sample-data.json):

meta        { contract, schema_version, generated_at, locale }
document    { number, date, status, comment, delivery_condition,
              delivery_costs, description, custom_fields{ W41xx… } }
customer    { name, customer_number, street, zip, city, country, contact{…} }
delivery    { … eigene Lieferadresse, optional contact }   ← Fallback: customer
invoice     { … eigene Rechnungsadresse }                  ← Fallback: customer
positions[] { pos_number, name, article_type, quantity, unit,
              price, discount, tax, line_net }
statistics  { tax_groups[{rate, net, vat}], net_total,
              order_discount_percent, discount_amount,
              net_after_discount, vat_total, gross_total }

Die Steuergruppen-Aggregation und Summenbildung geschieht serverseitig (Jasper kann JSON-Arrays nicht gruppieren); der Gesamtrabatt kommt aus dem dynamischen Feld W4114 (OrderDocumentDataBuilder.php:44-45,263-265).

Bekannte Lücke (Gap G5): Das aktuelle V2-Template ORDER-JSON-SAMPLE/main_reports/order-json-sample.jrxml bindet nur document.*, customer.* und statistics.* — die im Contract vorhandenen Blöcke delivery, invoice, document.delivery_condition/delivery_costs und custom_fields werden nicht gerendert. Das V1-Template (ORDER-SAMPLE bzw. Angebot_V0.8_Billing/_Delivery) druckt genau diese Rollen — hier fehlt V2 also sichtbare Funktion, obwohl die Daten fließen. DELIVERY-JSON-SAMPLE nutzt denselben Contract als schlanke Variante (nur delivery-Rolle + Positionen ohne Preise) und belegt die Adressrollen-Trennung mit abweichender Lieferanschrift.

Es existiert kein JSON-Schema für den Payload — der Contract ist nur über READMEs, sample-data.json und die JSONPath-Bindings der JRXMLs dokumentiert (calServer-reports schema/report-parameters.schema.json beschreibt nur die Parameter-Manifeste).


10. Nebenfunktionen

10.1 Alternative Erfassungswege

Neben dem Standardformular (actionCreate() :952, createBooking() :1077) bietet V1 drei Schnellwege:

Weg Aktion Verhalten
Aus Notizzettel actionCreateFromNotepad() (:1225) Erzeugt einen Auftrag aus einer Notepad-Geräteauswahl
Mit Geräten actionCreateWithInventories() (:1299) Auftrag anlegen und Geräte in einem Schritt als Positionen übernehmen
Schnellauftrag actionCreateFastOrder() (:3784) Create-or-Update inkl. sofortigem Free_Delivery.jrxml-Report (Ordner individual_delivery, :3814-3818) und DMS-Ablage (Yii::app()->dms->add(…,'booking',…), :3839); eigenes Recht fast_add_order

Dazu Auftragsvorlagen (booking_type): vordefinierte Positionslisten mit Preisgruppen-Anbindung (m171024_064355), Views booking_type/, templateArticle/.

10.2 DMS-Integration

Generierte Belege werden dem Auftrag als Dokumente zugeordnet (actionSaveToDms() :2958, Dokument-Tab, dynamische Relationen FrontendBooking.php:471-480); der Schnellauftrag legt seinen Lieferschein automatisch ab.

10.3 Digitale Signatur

actionSign() (:3611) signiert Auftragsreports; getSignature()/hasSignature() (FrontendBooking.php:3011-3061); Migrations m181212_020223, m190418_035341. V2: BookingController::sign + ReportSignatureService + Freigabe-Workflow (BookingReportController::release).

10.4 E-Mail-Versand und Mail-Logs

actionSendReport() (:3039-3201): komponiert eine AdminMailerMessage (link_table=BOOKING), zieht die Mailvorlage aus statusModel->mailer_template_id, hängt den generierten Report an, ersetzt die Platzhalter aus getTokenValues() (Abschnitt 4.3), versendet, legt den Anhang optional ins DMS und protokolliert im Aktionen-Tab (actionListMailLogs() :3492 ff.). V2: BookingReportController::send + BookingController::mailLogs.

Korrektur (2026-08). Hier stand „Statusgesteuerte Auto-Mails über status.mailer_report". Das ist falsch: mailer_report kommt im gesamten Booking-Pfad nicht vor, es filtert Gerätezeilen im Fälligkeitsmailer (Abschnitt 5.2). Statusgesteuerte Auto-Mails für Aufträge gibt es in V1 nicht. Der Versand ist immer manuell; status.mailer_template_id belegt im Dialog nur die Vorlage vor.

10.5 Export / Import

CSV/XLS/PDF-Export mit Spaltenauswahl (actionExport() :4072, getDataForExport() :4090, actionUpdateExportColumns() :4028; Spalten-Setup m220607_035616_add_fields_for_export_xls_and_pdf.php). Import über das generische TableImport-Framework (FrontendTableImportSetting/ FrontendTableImportTemplate). V2: BookingController::export.

10.6 Grid, Filter, Statistik, Barcode

Haupt-Grid booking-grid (FrontendBooking::GRID_VIEW_ID :74): Spalten aus FrontendProperty::getGridViewColumns('booking') (views/frontendBooking/_columns.php:6), Spaltendialog EColumnsDialog (_columns.php:75-102), gespeicherte Sichten (FrontendTableViews), Standard-Sortierung (FrontendGridSortDefault), erweiterte Filter (FrontendAdvancedFilter, getBookingForAdvancedFilter() FrontendBooking.php:3212), Dashboard-Widget „Aufträge nach Status" (ORDER_ENTRIES_BY_STATUS, :88-89, getListBookingOfStatistics() :3096). Barcode-Suche kommt aus dem Inventarmodul und wird bei der Gerätezuordnung genutzt.

10.7 Rechte und Konfiguration

Rollen im accessRules() (FrontendBookingController.php:53-199):

Recht Deckt ab
bookings_view Grid, Detail, Reports ansehen, Signieren, DMS, Mailversand, Sammelauftrag-Zuordnung (:111-144)
bookings_edit Anlegen/Ändern, Feld-Inline-Edit, Zuweisungen, Statuswechsel (:66-90)
bookings_delete Löschen/Massenlöschen (:145-153)
bookings_details_view Positions-Zuordnung Geräte/Katalogartikel/Typen (:176-184)
booking_actions_view Mail-Logs (:185-194)
fast_add_order Schnellauftrag (:91-110)
individual_delivery_report Freie Lieferschein-Zuordnung (:91-100)
status_reader Report-Druck/Listenzugriff für Leserollen (:166-175)

Positionsrechte hängen zusätzlich am Typ (inventory_view, article_edit, types_view; FrontendArticle.php:591-616); Feld-Sichtbarkeit/-Pflicht je Rolle über AdminUserRolesField::getLimitColumnNames() (base/BaseFrontendBooking.php:109-123). Konfigurationsschalter u. a.: booking_grid_editable (Seed m150818_035821…:11), complexity_default (:810 im Controller), Auftrags-Kategorien (m220323_071240), Tab-Konfiguration (m170228_072726), Report-Kopfreihenfolge (m160901_022650). V2: RBAC-Operationen bookings_*, article_*, price_*, price_category_* sind registriert.


11. W41xx-Feldkatalog

11.1 Mechanik: konfigurierbar, nicht semantisch fixiert

W4101–W4122 sind frei konfigurierbare Zusatzfelder des Auftragskopfs. Labels, Feldtypen, Sichtbarkeit und Default-Werte kommen aus der Tabelle field_configuration (Seed je Spalte: m150818_035821_booking_column_configuration_field.php); Pflicht/Sichtbarkeit je Rolle aus AdminUserRolesField. Die Sprachdateien liefern nur Durchreich-Defaults — einzige Ausnahme: W4101 = „Posten-Nr" (httpdocs/protected/messages/de/booking.php:27). Die Bedeutung eines W41xx-Felds ist damit installationsspezifisch.

11.2 Belegte Bedeutungen aus zwei Quellen

Zwei Referenz-Konfigurationen im Repo-Bestand widersprechen sich teilweise — ein Beleg dafür, dass Installationen die Felder unterschiedlich belegen:

Feld Default-Feldkatalog (laravel/database/sql/field_configuration.sql, Grid booking) Annahme im Community-Template ORDER-SAMPLE (Report-SQL) Bewertung
W4101 Freifeld (DE-Label „Posten-Nr") Wird im Kopf-Metablock gedruckt, Label unbelegt unklar, nicht raten
W4102 StatusCounter „AN" (Angebotsnummer, Template [STATUS_SHORT]-[YYYY]-[STATUS_COUNT]) selektiert, aber nicht erkennbar gerendert Widerspruch
W4103 StatusCounter „AU" (Auftragsnummer) Angebots-Gültigkeit in Tagen (DATE_ADD(CURDATE(), INTERVAL W4103 DAY) → „Angebot gültig bis") Widerspruch
W4104 StatusCounter „LI" (Lieferscheinnummer) Kundenreferenz/Bestellnummer („Ihre Referenz"/„Ihre Bestellnummer") Widerspruch
W4105 StatusCounter „RE" (Rechnungsnummer) Bestelldatum des Kunden („Ihr Bestelldatum") Widerspruch
W4106 Freifeld Angebotsrevision (Suffix an Angebotsnummer) nur Template-Beleg
W4108 Freifeld Rechnungsnummer ("Rechnung " + W4108, Fallback Auftragsnummer) nur Template-Beleg
W4109 Freifeld Liefer-/Leistungsdatum nur Template-Beleg
W4114 Freifeld Gesamtrabatt in % (treibt Statistics.jrxml; V2 liest ihn identisch: OrderDocumentDataBuilder.php:44-45) konsistent belegt
W4107, W4110–W4113, W4115–W4122 Freifelder in keinem Report verwendet unbelegt

Beide Quellen sind „echt": Der Feldkatalog beschreibt eine Auslieferungskonfiguration mit Belegnummern in W4102–W4105; das Community-Template setzt eine gelebte Kundenkonfiguration mit Referenz-/Datumsfeldern voraus. Zusätzlich pflegt der Katalog eigene Konfigurationszeilen für die Booking-Untergrids customer_booking, inventory_booking, other_booking, assign_other_booking (FrontendBooking.php Konstanten TABLES :124-130).

11.3 Konsequenzen für V2

  1. Nichts hartkodieren. V2 konsolidiert W41xx korrekt in bookings.custom_fields (JSON) über HasDynamicFields + field_definitions-Registry — die Bedeutung muss aus der Felddefinition kommen, nie aus Code oder Template.
  2. Seed fehlt (Gap G4): laravel/database/data/default_field_definitions.json enthält praktisch keine Booking-W41xx-Definitionen; ohne V1-Sync startet eine frische V2-Installation ohne benannte Auftrags-Zusatzfelder.
  3. Template-Rendering generisch machen (Teil von Gap G5): Das V2-Ordertemplate sollte custom_fields als Label/Wert-Paare rendern (Labels aus der Felddefinition in den Payload aufnehmen), statt einzelne W-Felder zu verdrahten.
  4. Doku-Hinweis für Template-Autoren: Community-Templates wie ORDER-SAMPLE setzen eine bestimmte W41xx-Belegung voraus und müssen bei abweichender Installation angepasst werden.

12. Gap-Analyse V1 → V2 und Backlog

12.1 Was V2 bereits abdeckt

Zur Einordnung (Belege: laravel/app/Http/Controllers/Api/V2/BookingController.php, BookingReportController.php, frontend-v2/pages/booking/, v2-roadmap.md §1): CRUD inkl. Duplizieren/Stornieren/ Massenlöschen/Export, Nummernkreis, Statusworkflow mit Pflichtfeldern, drei Kundenrollen + Kontakte im Schema/Modell/UI, Positionen (article inkl. A43xx), Katalogartikel-API, Preislisten + Preisgruppen (API + Preise-Seite), Sammelaufträge, Mail-Logs, Signatur/Freigabe, DMS-Ablage, Auftrags-Reports über den order-document-Contract inkl. Teil-Reports. Die Detailtabelle über alle ~70 V1-Aktionen steht in Anhang A.

12.2 Lücken

# Funktion V1-Verhalten (Beleg) V2-Stand (Beleg) Gap Empfehlung Prio
G1 Kunden-Sichtbarkeit in Auftrags-Pickern Zuweisungsbasierte Sichtbarkeit via map_user/group_customer/customer_filter (InventoryHelper::isAllCustomers) Tabellen migriert, aber kein Lesepfad wertet sie aus — alle Kunden sichtbar (CUSTOMER_HANDLING_V1_V2_REVIEW.md) Funktions- und Datenschutz-Regression; betrifft Haupt-, Liefer- und Rechnungskunden-Auswahl im Auftrag Sichtbarkeitsmodell zentral im CustomerController-Query-Pfad verdrahten; Auftrags-Picker erben es automatisch Hoch
G2 Schnellerfassung actionCreateFastOrder (FrontendBookingController.php:3784, inkl. Sofort-Lieferschein + DMS), actionCreateFromNotepad (:1225), actionCreateWithInventories (:1299) Nur Basis-store im BookingController Drei produktive Erfassungswege fehlen komplett Zuerst createWithInventories (Auftrag + Geräte in einem Call), dann FastOrder (mit Report+DMS), Notepad-Weg nach Notepad-V2-Stand priorisieren Mittel–Hoch
G3 Stammdaten-UI Preise Preislisten-Grid mit Anlegen/Ändern/Duplizieren/Inline-Edit (FrontendPriceController.php:333/403/444/660) pages/price-category/ und pages/standard-article/ sind inzwischen voll-CRUD (SettingsGrid); pages/price/ bleibt lesend + löschend, obwohl POST/PUT /prices und duplicate serverseitig existieren Preise sind über die Oberfläche weder anlegbar noch änderbar Anlegen/Bearbeiten/Duplizieren nach CrudModal-Muster nachziehen, Preisgruppe zum Einstieg der Preisbearbeitung machen (Matrix, Gruppe duplizieren) — Plan: konzept-preisverwaltung-v2.md Hoch
G4 W41xx-Felddefinitionen Seed je Spalte via m150818_035821…; Bedeutungen installationsspezifisch (Abschnitt 11) custom_fields-Mechanik fertig, aber default_field_definitions.json ohne Booking-W41xx-Einträge Frische V2-Installation hat keine benannten Auftrags-Zusatzfelder Default-Felddefinitionen für booking seeden (Basis: laravel/database/sql/field_configuration.sql), Belegnummern-Felder als StatusCounter-Äquivalent kennzeichnen Mittel
G5 Order-Template-Vollständigkeit Produktions-Templates drucken Rechnungs-/Lieferadresse, Lieferbedingung/-kosten und W-Felder (httpdocs/reports/orders/Angebot_V0.8_Billing/_Delivery; ORDER-SAMPLE) Contract order-document liefert alles, aber ORDER-JSON-SAMPLE-Template bindet nur customer + Summen (Abschnitt 9.3) Gedruckte Belege ohne abweichende Liefer-/Rechnungsadresse, Lieferkondition und Zusatzfelder V2-Template erweitern: invoice-Block auf Rechnungen, delivery-Block auf Lieferscheinen, delivery_condition/delivery_costs in der Summenbox, generischer custom_fields-Abschnitt; zusätzlich JSON-Schema für den Contract publizieren Hoch
G6 Abgrenzung News/Artikel-CMS FrontendArticleController mischt Katalogartikel und News-CMS Booking-Positionen und Katalogartikel vorhanden; News-CMS fehlt (separates Thema, v2-roadmap.md) Kein Ordermanagement-Gap — nur Namensverwechslung vermeiden In V2-Doku/Code konsequent „StandardArticle/Katalogartikel" vs. „News" trennen Info

12.3 Backlog-Vorschlag (priorisiert)

  1. G5a — Order-Template: ORDER-JSON-SAMPLE um invoice/delivery-Blöcke, Lieferkondition/-kosten und generisches custom_fields-Rendering erweitern (reine Template-Arbeit, Daten fließen bereits; Wirkung sofort sichtbar).
  2. G1 — Kunden-Sichtbarkeit: Umsetzung gemäß Empfehlung in CUSTOMER_HANDLING_V1_V2_REVIEW.md; danach automatisch wirksam in allen Auftrags-Pickern.
  3. G4 — W41xx-Seed: Booking-Felddefinitionen in default_field_definitions.json aufnehmen; Label-Quelle in den order-document-Payload aufnehmen (für G5a).
  4. G2 — createWithInventories + FastOrder: als BookingController- Endpunkte mit Frontend-Einstieg (Inventar-Grid-Massenaktion „Auftrag erstellen"); Notepad-Variante nachziehen, sobald Notepad-V2 steht.
  5. G3 — Preisliste bearbeitbar machen: Anlegen/Bearbeiten/Duplizieren in pages/price/ (Katalogartikel- und Preisgruppen-Seiten sind erledigt); Ausbau gemäß konzept-preisverwaltung-v2.md.
  6. G5b — Contract-Schema: JSON-Schema für order-document v1.0 in calServer-reports schema/ publizieren (Absicherung für Template-Autoren und den report-runner).

13. Anhang

Anhang A — Referenz: Controller-Aktionen FrontendBookingController

Zeilenangaben: httpdocs/protected/modules/frontend/controllers/FrontendBookingController.php. V2-Spalte: ✔ vorhanden · ◐ teilweise/indirekt · ✖ fehlt (Stand 2026-07-20).

Aktion Zeile Zweck Recht V2
actionAdmin 292 Haupt-Grid bookings_view index
actionView 521 Detailseite bookings_view show
actionViewDetail 3268 Detail-Popup bookings_view ◐ über show
actionAutoComplete 460 Nummern-Suche bookings_view ◐ Grid-Suche
actionAjaxField 576 Feld-Lookup bookings_view
actionAjaxCustomerGrid 1779 Kunden-Lookup-Grid bookings_view ◐ Customer-API
actionLoadColumns 4465 Grid-Spalten laden bookings_view ✔ Grid-Infra
actionCreate 952 Auftrag anlegen bookings_edit store
actionUpdate 1479 Auftrag ändern bookings_edit update
actionUpdateField 1562 Inline-Feld-Edit bookings_edit update
actionDelete 1805 Löschen bookings_delete destroy
actionMultiDelete 1825 Massenlöschen bookings_delete bulkDestroy
actionCancel 926 Stornieren bookings_edit cancel
actionCreateNewBookingNumber 1119 Nummer aus Nummernkreis bookings_edit generateNumber
actionGetDefaultValuesFromStatus 1144 Status-Defaults bookings_edit
actionGetDefaultValuesFromCategory 1186 Kategorie-Defaults bookings_edit
actionCreateFromNotepad 1225 Auftrag aus Notizzettel bookings_edit
actionCreateWithInventories 1299 Auftrag + Geräte in einem Schritt bookings_edit
actionCreateFastOrder 3784 Schnellauftrag + Sofort-Lieferschein fast_add_order
actionSetStatus 1441 Statuswechsel (Link) bookings_edit changeStatus
actionChangeStatus 3697 Statuswechsel (AJAX, Pflichtfelder) bookings_edit changeStatus
actionSaveAdditionalFields 3904 Pflichtfelder nachtragen bookings_edit saveAdditionalFields
actionAssignCustomer 746 Kunde zuordnen (Haupt/Liefer/Rechnung) bookings_edit store/update
actionAssignDeliveryContact 862 Lieferkontakt bookings_edit update
actionAssignInvoiceContact 893 Rechnungskontakt bookings_edit update
actionGetCompanyAddress 2404 Firmenadresse holen bookings_edit ◐ Customer-API
actionRefreshAddress 2421 Adresse aktualisieren bookings_edit
actionResetAddress 3206 Adresse zurücksetzen bookings_edit resetContact (UI)
actionAddNewAddress 2337 Neue Adresse anlegen bookings_edit ◐ Contact-API
actionSaveContact 2266 Kontakt speichern bookings_edit ◐ Contact-API
actionCloneContact 2305 Kontakt duplizieren bookings_edit
actionGetCustomerDetail 3249 Kunden-Popup bookings_view
actionGetCustomerDetailToView 3288 Kunden-Popup (Detail) bookings_view
actionAssignInventoryUpdate 655 Geräte-Zuordnungs-Grid bookings_details_view ArticleController::store
actionAddArticles 808 Geräte als Positionen übernehmen bookings_details_view
actionAssignStandardArticle 2183 Katalogartikel zuordnen bookings_details_view assignStandardArticle
actionAssignType 2221 Typ-Position zuordnen bookings_details_view
actionListAllArticles 482 Positionsliste (alle) bookings_view ✔ Articles-API
actionListArticles 2051 Positionsliste bookings_view ✔ Articles-API
actionListStandardArticles 2098 Katalogartikel-Liste bookings_view ✔ StandardArticle-API
actionListTypes 2138 Typenliste bookings_view ✔ Types-API
actionGetListArticles 2475 Positionsliste (Reader) status_reader
actionGetOrderDetails 2575 Auftragsdetails (FastOrder) fast_add_order
actionGetArticlesForPart 3390 Positionen je Teil bookings_edit ◐ Teil-Reports
actionSaveNewPart 3443 Neuen Teil speichern bookings_edit
actionGetParts 3468 Teile auflisten bookings_view
actionAssignOrder 3305 Auftrag in Sammelrechnung einbinden bookings_view assignOrder
actionUnAssignOrder 3347 Einbindung lösen bookings_view unassignOrder
actionDetailsPrint 1886 Detail-Druck bookings_view ✔ Report-API
actionDeliveryFormPrint 1907 Lieferschein-Druck bookings_view ✔ Report-API
actionListBooking / actionListPrint 1930 / 1964 Listen-Druck bookings_view ◐ Export
actionGetDetailPrint 2033 Druckpfad Detail bookings_view ✔ Report-API
actionViewDetailReport 2653 Detail-Report anzeigen bookings_view preview
actionViewMasterReport 2708 Master-Report (Beleg) anzeigen bookings_view preview/generate
actionPrintOrderReport 2859 Beleg drucken status_reader generate
actionGetReportLabelPath / actionGetReportPrintPath 2777 / 2817 Label-/Druckpfade bookings_view useReports
actionViewFile / actionDownloadFile 2923 / 2620 Reportdatei anzeigen/laden bookings_view ✔ Documents-API
actionSaveToDms 2958 Beleg ins DMS bookings_view saveToDms
actionSign 3611 Beleg signieren bookings_view sign + release
actionSendReport 3039 Beleg per Mail versenden bookings_view send
actionNotification 2006 Benachrichtigung bookings_view
actionListMailLogs 3492 Mail-Log-Liste booking_actions_view mailLogs
actionViewMailLog 3527 Mail-Log ansehen booking_actions_view mailLogs
actionDeleteMailLog / actionMultiDeleteMailLog 3548 / 3571 Mail-Logs löschen booking_actions_view
actionExport 4072 CSV/XLS/PDF-Export bookings_view export
actionUpdateExportColumns 4028 Export-Spaltenauswahl bookings_view

Anhang B — Quellenverzeichnis

V1 (calserver-yii, httpdocs/protected/): modules/frontend/models/FrontendBooking.php, modules/frontend/models/base/BaseFrontendBooking.php, modules/frontend/models/FrontendArticle.php (+ Base), modules/frontend/models/FrontendPrices.php, FrontendPriceCategory.php, FrontendStandardArticle.php, FrontendCollectiveInvoices.php, FrontendStatus.php (+ base/BaseFrontendStatus.php), modules/frontend/controllers/FrontendBookingController.php, FrontendPriceController.php, FrontendArticleController.php, modules/frontend/views/frontendBooking/, components/InventoryHelper.php, components/CounterService.php, messages/de/booking.php, Migrations (m130220_194523_install.php, m150818_031621, m150818_035821, m160929_092258, m170208_040802, m170327_092359, m170929_022104, m180330_044639, m220328_033736 u. a.), Produktions-Templates httpdocs/reports/orders/.

V2 (calserver-yii): laravel/app/Http/Controllers/Api/V2/BookingController.php, BookingReportController.php, ArticleController.php, StandardArticleController.php, PriceController.php, PriceCategoryController.php, laravel/app/Models/Booking.php, Article.php, CollectiveInvoice.php, laravel/app/Services/Report/OrderDocumentDataBuilder.php, laravel/app/Services/Booking/BookingNumberService.php, laravel/app/Models/Concerns/HasDynamicFields.php, laravel/app/Services/FieldManagement/FieldDefinitionService.php, laravel/database/migrations/2026_02_28_500001_create_booking_table.php, laravel/database/sql/field_configuration.sql, laravel/database/data/default_field_definitions.json, frontend-v2/pages/booking/, frontend-v2/composables/useReports.ts, report-runner/.

Report-Templates (calserver-reports): ORDER-SAMPLE/ (+ subreports/Statistics.jrxml), ORDER-JSON-SAMPLE/ (+ main_reports/sample-data.json, parameters.json), DELIVERY-JSON-SAMPLE/, DELIVERY-STANDALONE/, schema/report-parameters.schema.json.

Verwandte Dokumente: v2-roadmap.md (aktueller V2-Stand), CUSTOMER_HANDLING_V1_V2_REVIEW.md (Sichtbarkeitsmodell), v1-v2-analysis.md (veraltete Gesamt-Gap-Analyse, durch dieses Dokument für den Auftrags-Teil ersetzt), evaluierung-jasper-reports-v2.md, konzept-report-parameter-katalog.md.