Files
simply_cpq/buildtime/server
2026-09-12 23:09:17 +02:00
..
2026-08-27 15:31:50 +02:00
2026-09-12 23:09:17 +02:00
2026-08-27 15:31:50 +02:00
2026-08-27 15:31:50 +02:00
2026-08-15 16:58:12 +02:00
2026-08-15 16:58:12 +02:00
2026-08-15 16:58:12 +02:00
2026-08-21 19:55:40 +02:00
2026-08-17 20:12:24 +02:00

Simply CPQ Buildtime Server

Dieser Ordner enthält alle relevanten Dateien und Informationen zum Simply CPQ Buildtime Server. Dieser dient der Pflege von Produktdaten, Regeln, Konditionen und Administration der Simply CPQ Anwendung durch die Bereitstellung des Pflege-Servers.

Design-Entscheidungen

  • Jedes Objekt hat eine über die gesamte Datenbank hinweg eindeutige ID.
-- 1. Globale Sequence anlegen
CREATE SEQUENCE global_id_seq
    START 1000000
    INCREMENT 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;

-- 2. Tabelle A mit globaler ID
CREATE TABLE tabelle_a (
    id BIGINT PRIMARY KEY DEFAULT nextval('global_id_seq'),
    name TEXT NOT NULL
);
  • Jedes Objekt hat mindestens eine getById Methode.

  • Ein Objekt enthält keine Unterstrukturen direkt. Strukturen, wie z.B. Listen, werden durch entsprechende Relationen in der Datenbank und auf dem Server abgebildet. Baumstrukturen werden durch ParentIds aufgebaut.

    • Die Clients müssen sich zum Aufbau der Gesamtstruktur die jeweiligen Unter-Objekte an der API abholen. Ggf. sind das rekursive Strukturen (Bäume).
  • Jedes Objekt hat eine ID, ein Label und eine Beschreibung (description)

  • Alle Namen fangen immer mit einem Kleinbuchstaben in der Datenbank an. Danach greift dann das "CamelCase" System. z.B. "propertyTypeId".

  • Wertesystem von Simply CPQ

    • Es gibt einen generellen Merkmalspool, welcher durch Kategorien entsprechend strukturiert werden kann.

    • Eine Merkmalsdefinition hat einen Namen und verweißt auf ein Set von Werten (das definiert die maximale Ausprägung dieses Wertes an Produktgruppen oder Produkten)

    • Als mögliche Werte gibt es nur Listen, die Strings enthalten. Ein terminaler Wert ist eine Liste mit genau einem String als Inhalt.

    • Eine Produktgruppe kann Merkmale enthalten, die sich auf eine Merkmalsdefinition beziehen. Dabei kann die Liste der möglichen Werte (das Set) ggf. nach Bedarf eingeschränkt werden. Sie darf NIE erweitert werden (Monotonie-Bedingung).

    • Eine Unterproduktgruppe "erbt" die Merkmale der Obergruppe und kann diese ggf. weiter einschränken.

    • Ein Produkt "erbt" alle Merkmale der Produktgruppe, in der sie enthalten ist. Ggf. können die Werte eines Merkmals dann entsprechend eingeschränkt werden, aber NIE erweitert (Monotoniebedingung).

    • Folgende Funktionen:

      • createPropertyTypeGroup

      • createPropertyTypeInPropertyTypeGroup

      • createValueForPropertyTypeId

      • deleteValueFromPropertyTypeId

      • getValuesFromPropertyTypeId

      • copyPropertyFromPropertyTypeIdForProductGroupId

      • deletePropertyIdFromProductGroupId (und aus allen Untergruppen und Produkten)

      • (copyPropertiesFromProductGroupIDToProductGroupId) (beim Anlegen einer Untergruppe)

      • (copyPropertiesFromProductGroupIdToProductID) (beim Anlegen eines Produktes in einer Produktgruppe)

      • deleteValueFromProperty

      • getValuesFromProperty

      • updateValueFromValueId

      • addValueToPropertyType

  • Produkte haben zusätzlich zur ID, Label und Beschreibung noch eine externalId.

  • Der Merkmalspool ist eine Baumstruktur, in der sich Merkmalsdefinitionen einordnen lassen. Dabei handelt es sich um eine reine Strukturierungshilfe ohne weitere Bedeutung.

  • Produktgruppen bilden Baumstrukturen und "vererben" ihre Merkmalslisten an ihre Unterstrukturen.

    • Die Unterstrukturen können weitere Merkmale enthalten. "Vererbte" Merkmale können allerdings nur eingeschränkt und nicht erweitert werden (Monotonie)

    • Auf allen Ebenen können Produktgruppen Produkte enthalten. Diese haben dann die Merkmale der Produktgruppe, können aber auch weitere Merkmale enthalten. Die Merkmale der Produktgruppe können nur eingeschränkt werden, nicht erweitert (Monotonie)

    • Produkte können Stücklisten aus anderen Produkten und/oder Strukturknoten enthalten. Bei einem Strukturknoten handelt es sich um eine Liste von Produkten, aus der in der Laufzeit ein Produkt ausgewählt wird.

  • Zu Produkten, Produktgruppen und Merkmalstypen können Mediendaten hinterlegt werden.

  • Der Server liefert und erwartet JSON Daten.

Datenbank aufsetzen:

-- 1. Globale Sequence anlegen
CREATE SEQUENCE global_id_seq
    START 1000000
    INCREMENT 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;

-- 2. Value Table
-- Value Table
CREATE TABLE IF NOT EXISTS values (
    id BIGINT PRIMARY KEY DEFAULT nextval('global_id_seq'),
    Label TEXT,
    description TEXT,
    propertyGroupId BIGINT
);

-- Property Table
CREATE TABLE IF NOT EXISTS propertys (
    id BIGINT PRIMARY KEY DEFAULT nextval('global_id_seq'),
    label TEXT,
    description TEXT,
    propertyTypeId BIGINT,
    productId BIGINT,
    productGroupId BIGINT
);

-- PropertyType Table
CREATE TABLE IF NOT EXISTS propertyTypes(
    id BIGINT PRIMARY KEY DEFAULT nextval('global_id_seq'),
    label TEXT,
    description TEXT,
    propertyId BIGINT
);

-- PropertyTypeGroupTable
CREATE TABLE IF NOT EXISTS propertyTypeGroups (
    id BIGINT PRIMARY KEY DEFAULT nextval('global_id_seq'),
    label TEXT,
    description TEXT,
    parentGroupId BIGINT
);

-- 3. Product Tables
-- Product Table
CREATE TABLE IF NOT EXISTS products (
    id BIGINT PRIMARY KEY DEFAULT nextval('global_id_seq'),
    abel TEXT,
    externalId TEXT,
    description TEXT,
    productGroupId BIGINT
);

-- ProductGroup Table
CREATE TABLE IF NOT EXISTS productGroups (
    id BIGINT PRIMARY KEY DEFAULT nextval('global_id_seq'),
    label TEXT,
    description TEXT,
    parentGroupId BIGINT
);

-- Media Table
CREATE TABLE IF NOT EXISTS media (
    id BIGINT PRIMARY KEY DEFAULT nextval('global_id_seq'),
    Label TEXT,
    description TEXT,
    media TEXT,
    mediaType TEXT,
    externalId BIGINT
);

Open Aufsetzen des Source Codes:

go mod init simplycpq

Struktur des Server-Verzeichnisses:

./models                # Enthält die Strukurdefinitionen
./server                # Enthält den Datenbank- und Web-Server
./repositories          # Enthält die Zugriffslayer für die Datenbank
./services              # Enthält die Service-Layer
./controller            # Bilden die Schnittstellen zur RESTFull API
./config                # Code zur Auswertung der Applikationskonfiguration
config.toml             # Einstellungsdatei für den Server
main.go                 # Das Server Hauptprogramm           

Open Source Bibliotheken, die hier genutzt werden

Viper

Viper dient zum Laden uns Auswerten von Config-Dateien. In diesem Case werden die HTTP-Servereinstellungen und die Datenbankverbindung ausgewertet.

go get github.com/spf13/viper

PostgreSQL

Die Datenbank des Systems ist in dem Datenbankmanagementsystem PostgreSQL abgelegt. Zum einen braucht es eine Installation des Systems, auf dem die Software Zugriff hat und zum anderen benötigt das System die entsprechenden PostgreSQL Treiber für Go.

go get github.com/lib/pq

Gin Gonic

Webserver Library zum Routing der API.

go get -u github.com/gin-gonic/gin
go get github.com/gin-contrib/cors

Einrichten des Servers:

Server API

Die Server-API baut auf HTTP und auf REST auf. Antworten werden im JSON Format gesendet,ebenso, wie neu anzulegende Daten oder zu aktualisierende Daten.

Generell werden Daten im JSON Format ausgetauscht. Z.B. wird ein Value Objekt in From von application/json Daten übergeben:

put: http://server:port/updatePropertyType

benötigt folgende Struktur im Anfragekörper:

{
  "id": 1000003,
  "label": "Colour",
  "description": "System wide colors",
  "propertyTypeGroupId": 100002
}

und liefert als Ergebnis (wenn kein Fehler auftritt):

{
  "data": {
    "id": 1000003,
    "label": "Colour",
    "description": "System wide colors",
    "propertyTypeGroupId": 100002
  },
  "message": "PropertyType updated"
}

Wenn Daten zurückkommen, so wie hier im Beispiel, dann werden sie im "data" Tag geschrieben. Meistens kommt auch noch eine Nachricht mit, die in "message" steht.

Im Falle eines Fehler kommt eine entsprechende Nachricht zurück (z.B. wenn es keinen PropertyType mit der entsprechenden ID gibt):

{
  "error": "sql: no rows in result set"
}

Value und Property Funktionen

Datentypen als JSON Beispiele:

// PropertyType
{
    "id": 1000003,                       
    "label": "Colour",
    "description": "System wide colors",
    "propertyTypeGroupId": 100002
}
// Property
{
  "label": "Colour",
  "description": "System wide colors",
  "propertyTypeId": 1000003,
  "productId": 0,
  "productGroupId": 0
}
// Value
{
    "id": 1000003,                       
    "label": "Red",
    "description": "Color Red",
    "propertyId": 100003
}
// ProductGroup
{
    "id": 1000003,                       
    "label": "Red",
    "description": "Color Red",
    "propertyId": 100003
}
// Product
{
    "id": 1000003,                       
    "label": "Red",
    "description": "Color Red",
    "propertyId": 100003
}

Datenimport

Produktdaten:

Produktdaten werden in folgenden JSON-Datenformat entgegen genommen:

// Excample Productgroups

{
    "group": {    
        "label": "HIFI",
        "decription": "Hifi components",
        "products": [ 
        { 
             "label": "Radio 4711",
             "externalId": "ABC0815"
             "description": "modern Radio for Hifi",
             "properties": {
                 "voltage": 240,
                 "Color": "red",
                 "watt": 15
             },
        },
        ]            
        
    }
}

// Example Productdata for new product import
{                       

    
}