diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..1cd214d --- /dev/null +++ b/readme.md @@ -0,0 +1,1708 @@ +# LCC Backend API Documentation + +**API Version:** v1.0 +**Last Updated:** March 16, 2025 + +## Table of Contents + +1. [Overview API](#overview-api) +2. [Authentication](#authentication) +3. [Request and Response Conventions](#request-and-response-conventions) +4. [System Configuration Endpoints](#system-configuration-endpoints) +5. [Transportation Rate Endpoints](#transportation-rate-endpoints) +6. [User Management Endpoints](#user-management-endpoints) +7. [Calculation Endpoints](#calculation-endpoints) +8. [Reporting Endpoints](#reporting-endpoints) +9. [Glossary](#glossary) + +## Overview API + +This document provides a comprehensive description of the LCC Backend API endpoints, their functionality, parameters, and response formats. The API is structured around several core domains: System Configuration, Transportation Rates, User Management, and Calculation. + +## Authentication + +### Authentication Methods + +The LCC API uses two primary authentication methods: + +1. **Pre-Shared Key (PSK)** \- Required for administrative endpoints such as User Management +2. **Session-based Authentication** \- Standard user authentication for most operations + +#### Pre-Shared Key Authentication + +For endpoints that require PSK authentication, include the following header in your request: + +```javascript +Authorization: PSK your_psk_here +``` + +Contact your system administrator to obtain a valid PSK. + +#### Session-based Authentication + +Most API endpoints require a valid session, which can be obtained by authenticating through the organization's identity provider. + +## Request and Response Conventions + +### Common Response Format + +All API responses follow a consistent structure. + +#### Success Response + +- HTTP Status Code: 200 OK +- Response Body: Varies by endpoint (details provided in specific endpoint documentation) + +#### Error Response + +- HTTP Status Code: Varies (400, 401, 403, 404, 500, etc.) +- Response Body: + +```javascript +{ + "error": { + "code": "ERROR_CODE", + "message": "User-friendly message", + "details": { } + } +} +``` + +### Common HTTP Status Codes + +| Status Code | Description | +| :---- | :---- | +| 200 | Success | +| 400 | Bad Request (client error) | +| 401 | Unauthorized (authentication required) | +| 403 | Forbidden (insufficient permissions) | +| 404 | Resource Not Found | +| 409 | Conflict (e.g., resource already exists) | +| 500 | Internal Server Error | + +### Pagination + +Endpoints that return lists of resources support pagination using the following query parameters: + +- `limit`: Maximum number of items to return (default: 20, maximum: 100\) +- `offset`: Number of items to skip for pagination (default: 0\) + +Example: `/api/materials?limit=20&offset=40` will return items 41-60. + +Pagination metadata is included in the response header: + +```javascript +X-Total-Count: 243 +X-Page-Count: 13 +X-Current-Page: 3 +``` + +## System Configuration Endpoints {#system-configuration-endpoints} + +### Bulk Operations + +#### Upload Template Data + +- **URL**: `/api/bulk/upload/{$type}` +- **Method**: POST +- **Description**: Uploads a filled-out template for batch processing +- **Path Parameters**: + - `$type`: The type of data being uploaded (valid values: `container_rate`, `country_matrix`, `material`, `packaging`, `node`) +- **Response**: Returns a processing ID for status tracking + +#### Get Template + +- **URL**: `/api/bulk/templates/{$type}` +- **Method**: GET +- **Description**: Returns a template for the specified data type +- **Path Parameters**: + - `$type`: The template type (valid values: `container_rate`, `country_matrix`, `material`, `packaging`, `node`) + +#### Check Processing Status + +- **URL**: `/api/bulk/status/{$processing_id}` +- **Method**: GET +- **Description**: Returns the processing status of a bulk upload +- **Path Parameters**: + - `$processing_id`: The ID returned from a bulk upload request + +### Materials Management + +#### List Materials + +- **URL**: `/api/materials/` +- **Method**: GET +- **Description**: Returns a list of all materials +- **Query Parameters**: + - `limit`: Maximum number of items to return (default: 20\) + - `offset`: Number of items to skip (for pagination) +- **Response Format**: + +```javascript +[ + { + "id": "string", + "part_number": "string", + "name": "string" + }, + ... +] +``` + +#### Get Material Details + +- **URL**: `/api/materials/{id}` +- **Method**: GET +- **Description**: Returns detailed information about a specific material +- **Path Parameters**: + - `id`: Material ID +- **Response Format**: + +```javascript +{ + "id": "string", + "part_number": "string", + "name": "string", + "hs_code": "string", + "handling_units": [ + { + "id": "string", + "supplier_name": "string", + "parent_id": "string", + "length": "number", + "width": "number", + "height": "number", + "dimension_unit": "string", + "weight": "number", + "weight_unit": "string", + "content_unit_count": "number" + }, + ... + ] +} +``` + +#### Update Material + +- **URL**: `/api/materials/{id}` +- **Method**: PUT +- **Description**: Updates the material with the specified ID +- **Path Parameters**: + - `id`: Material ID + +#### Delete Material + +- **URL**: `/api/materials/{id}` +- **Method**: DELETE +- **Description**: Sets the material to deprecated (soft delete) +- **Path Parameters**: + - `id`: Material ID + +### Packaging Management + +#### List Packagings + +- **URL**: `/api/packaging/` +- **Method**: GET +- **Description**: Returns a list of all packagings (handling units) +- **Query Parameters**: + - `limit`: Maximum number of items to return (default: 20\) + - `offset`: Number of items to skip (for pagination) + - `supplier`: Filter by supplier ID + - `material`: Filter by material ID +- **Response Format**: + +```javascript +[ + { + "id": "string", + "supplier_name": "string", + "part_number": "string", + "material_name": "string", + "length": "number", + "width": "number", + "height": "number", + "dimension_unit": "string", + "weight": "number", + "weight_unit": "string", + "content_unit_count": "number" + }, + ... +] +``` + +#### Get Packaging Details + +- **URL**: `/api/packaging/{id}` +- **Method**: GET +- **Description**: Returns detailed information about a specific packaging +- **Path Parameters**: + - `id`: Packaging ID +- **Response Format**: + +```javascript +{ + "id": "string", + "supplier": { + "id": "string", + "country": { + "id": "string", + "iso_code": "string", + "region_code": "string" + }, + "name": "string", + "address": "string" + }, + "material": { + "id": "string", + "part_number": "string", + "name": "string", + "hs_code": "string" + }, + "handling_unit": { + "length": "number", + "width": "number", + "height": "number", + "dimension_unit": "string", + "weight": "number", + "weight_unit": "string", + "content_unit_count": "number" + }, + "small_handling_unit": { + "length": "number", + "width": "number", + "height": "number", + "dimension_unit": "string", + "weight": "number", + "weight_unit": "string", + "content_unit_count": "number" + } +} +``` + +#### Update Packaging + +- **URL**: `/api/packaging/{id}` +- **Method**: PUT +- **Description**: Updates the packaging with the specified ID +- **Path Parameters**: + - `id`: Packaging ID + +#### Delete Packaging + +- **URL**: `/api/packaging/{id}` +- **Method**: DELETE +- **Description**: Sets the packaging to deprecated (soft delete) +- **Path Parameters**: + - `id`: Packaging ID + +### Country Management + +#### List Countries + +- **URL**: `/api/country/` +- **Method**: GET +- **Description**: Returns a list of all countries +- **Query Parameters**: + - `limit`: Maximum number of items to return (default: 20\) + - `offset`: Number of items to skip (for pagination) +- **Response Format**: + +```javascript +[ + { + "id": "string", + "iso_code": "string", + "name": "string", + "region_code": "string" + }, + ... +] +``` + +#### Get Country Details + +- **URL**: `/api/country/{id}` +- **Method**: GET +- **Description**: Returns detailed information about a specific country +- **Path Parameters**: + - `id`: Country ID +- **Response Format**: + +```javascript +{ + "id": "string", + "iso_code": "string", + "name": "string", + "region_code": "string", + "properties": [ + { + "id": "string", + "mapping_id": "string", + "name": "string", + "datatype": "string", + "current_value": "any", + "draft_value": "any", + "is_required": "boolean" + }, + ... + ] +} +``` + +#### Update Country + +- **URL**: `/api/country/{id}` +- **Method**: PUT +- **Description**: Updates the country with the specified ID +- **Path Parameters**: + - `id`: Country ID + +#### Delete Country + +- **URL**: `/api/country/{id}` +- **Method**: DELETE +- **Description**: Sets the country to deprecated (soft delete) +- **Path Parameters**: + - `id`: Country ID + +### System Properties Management + +#### List System Properties + +- **URL**: `/api/properties/system/` +- **Method**: GET +- **Description**: Returns property set including properties +- **Query Parameters**: + - `limit`: Maximum number of items to return (default: 20\) + - `offset`: Number of items to skip (for pagination) +- **Response Format**: + +```javascript +[ + { + "id": "string", + "mapping_id": "string", + "name": "string", + "data_type": "string", + "current_value": "any", + "draft_value": "any" + }, + ... +] +``` + +#### Get System Property Details + +- **URL**: `/api/properties/system/{id}` +- **Method**: GET +- **Description**: Returns detailed information about a specific system property +- **Path Parameters**: + - `id`: Property ID +- **Response Format**: + +```javascript +{ + "id": "string", + "mapping_id": "string", + "name": "string", + "data_type": "string", + "current_value": "any", + "draft_value": "any" +} +``` + +#### Update System Property + +- **URL**: `/api/properties/system/{id}` +- **Method**: PUT +- **Description**: Updates the system property with the specified ID +- **Path Parameters**: + - `id`: Property ID + +#### List Property Types + +- **URL**: `/api/properties/types/{$system_part}/` +- **Method**: GET +- **Description**: Returns a list of all property types for the specified system part +- **Path Parameters**: + - `$system_part`: The system part to get properties for (valid values: `system`, `packaging`, `country`) +- **Query Parameters**: + - `limit`: Maximum number of items to return (default: 20\) + - `offset`: Number of items to skip (for pagination) +- **Response Format**: + +```javascript +[ + { + "id": "string", + "mapping_id": "string", + "name": "string", + "data_type": "string" + }, + ... +] +``` + +#### Create Property Type + +- **URL**: `/api/properties/types/{$system_part}/` +- **Method**: PUT +- **Description**: Creates a new system property type +- **Path Parameters**: + - `$system_part`: The system part to create a property for (valid values: `system`, `packaging`, `country`) + +#### Get Property Type Details + +- **URL**: `/api/properties/types/{$system_part}/{id}` +- **Method**: GET +- **Description**: Returns detailed information about a specific property type +- **Path Parameters**: + - `$system_part`: System part (valid values: `system`, `packaging`, `country`) + - `id`: Property type ID +- **Response Format**: + +```javascript +{ + "id": "string", + "mapping_id": "string", + "name": "string", + "data_type": "string" +} +``` + +#### Update Property Type + +- **URL**: `/api/properties/types/{$system_part}/{id}` +- **Method**: PUT +- **Description**: Updates the property type with the specified ID +- **Path Parameters**: + - `$system_part`: System part (valid values: `system`, `packaging`, `country`) + - `id`: Property type ID + +#### Check Staged Property Changes + +- **URL**: `/api/properties/staged_changes/` +- **Method**: GET +- **Description**: Returns true if there are any unapproved "drafts" properties, false otherwise + +#### Approve Property Changes + +- **URL**: `/api/properties/staged_changes/` +- **Method**: PUT +- **Description**: Approves drafts and sets current "draft" properties to current valid properties + +### Node Management + +#### List Nodes + +- **URL**: `/api/nodes/` +- **Method**: GET +- **Description**: Returns a list of all active nodes (with deprecated \= false) +- **Query Parameters**: + - `limit`: Maximum number of items to return (default: 20\) + - `offset`: Number of items to skip (for pagination) + - `filter`: Search text to filter nodes +- **Response Format**: + +```javascript +[ + { + "id": "string", + "country": { + "id": "string", + "iso_code": "string", + "region_code": "string", + "name": "string" + }, + "address": "string", + "location": { + "longitude": "number", + "latitude": "number" + }, + "types": ["sink", "source", "intermediate"] + }, + ... +] +``` + +#### Get Node Details + +- **URL**: `/api/nodes/{$id}` +- **Method**: GET +- **Description**: Returns detailed information about a specific node +- **Path Parameters**: + - `$id`: Node ID +- **Response Format**: + +```javascript +{ + "id": "string", + "country": { + "id": "string", + "iso_code": "string", + "region_code": "string", + "name": "string" + }, + "name": "string", + "address": "string", + "location": { + "longitude": "number", + "latitude": "number" + }, + "types": ["sink", "source", "intermediate"], + "predecessors": { + "1": { + "id": "string", + "country": { + "id": "string", + "iso_code": "string", + "region_code": "string", + "name": "string" + }, + "name": "string", + "address": "string", + "location": { + "longitude": "number", + "latitude": "number" + } + }, + "2": { ... } + }, + "outbound_countries": [ + { + "id": "string", + "iso_code": "string", + "region_code": "string", + "name": "string" + }, + ... + ] +} +``` + +#### Update Node + +- **URL**: `/api/nodes/{$id}` +- **Method**: PUT +- **Description**: Updates the node with the specified ID +- **Path Parameters**: + - `$id`: Node ID + +#### Delete Node + +- **URL**: `/api/nodes/{$id}` +- **Method**: DELETE +- **Description**: Sets the node with the specified ID to deprecated (soft delete) +- **Path Parameters**: + - `$id`: Node ID + +#### Search Nodes + +- **URL**: `/api/nodes/search` +- **Method**: GET +- **Description**: Returns a list of nodes matching the search conditions +- **Query Parameters**: + - `filter`: Search string + - `limit`: Maximum number of items to return + - `node_type`: Type filter (valid values: `source`, `sink`, `intermediate`) + - `include_user_nodes`: Boolean to include user-specific nodes +- **Response Format**: + +```javascript +[ + { + "id": "string", + "country": { + "id": "string", + "iso_code": "string", + "region_code": "string", + "name": "string" + }, + "name": "string", + "address": "string", + "location": { + "longitude": "number", + "latitude": "number" + }, + "types": ["sink", "source", "intermediate"], + "predecessors": { ... }, + "outbound_countries": [ ... ], + "is_user_node": "boolean" + }, + ... +] +``` + +## Transportation Rate Endpoints {#transportation-rate-endpoints} + +### Rate Validity Periods + +#### List Validity Periods + +- **URL**: `/api/rates/periods` +- **Method**: GET +- **Description**: Returns a list of validity periods for transportation rates +- **Response Format**: + +```javascript +[ + { + "id": "string", + "start_date": "date", + "end_date": "date", + "state": "string" + }, + ... +] +``` + +- **Note**: State can have the following values: `draft`, `valid`, `invalid`, `expired` + +#### Create Validity Period + +- **URL**: `/api/rates/periods` +- **Method**: PUT +- **Description**: Creates a new validity period (only possible if no validity period with state "draft" exists) + +#### Invalidate Validity Period + +- **URL**: `/api/rates/periods/{$id}` +- **Method**: DELETE +- **Description**: Invalidates the validity period with the specified ID (must be in state "valid" or "expired") +- **Path Parameters**: + - `$id`: Validity period ID + +### Container Rates + +#### List Container Rates + +- **URL**: `/api/rates/container/` +- **Method**: GET +- **Description**: Returns a list of container rates associated with a specific validity period +- **Query Parameters**: + - `limit`: Maximum number of items to return (default: 20\) + - `offset`: Number of items to skip (for pagination) + - `valid`: Validity period filter (values: validity\_period\_id, "current", "draft") + - `validAt`: Timestamp to find rates valid at a specific time +- **Response Format**: + +```javascript +[ + { + "id": "string", + "origin": { + "id": "string", + "country": { ... }, + "address": "string", + "location": { ... }, + "types": ["sink", "source", "intermediate"] + }, + "destination": { + "id": "string", + "country": { ... }, + "address": "string", + "location": { ... }, + "types": ["sink", "source", "intermediate"] + }, + "type": "string", + "rates": { + "40": "number", + "20": "number", + "40_HC": "number" + }, + "lead_time": "number", + "validity_period": { + "id": "string", + "start_date": "date", + "end_date": "date", + "state": "string" + } + }, + ... +] +``` + +- **Note**: Type can have the following values: `rail`, `sea`, `post-run`, `road` + +#### Get Container Rate Details + +- **URL**: `/api/rates/container/{$id}` +- **Method**: GET +- **Description**: Returns detailed information about a specific container rate +- **Path Parameters**: + - `$id`: Container rate ID +- **Response Format**: Same as list container rates + +#### Update Container Rate + +- **URL**: `/api/rates/container/{$id}` +- **Method**: PUT +- **Description**: Updates the container rate with the specified ID (only possible if the validity period is in state "draft") +- **Path Parameters**: + - `$id`: Container rate ID + +#### Delete Container Rate + +- **URL**: `/api/rates/container/{$id}` +- **Method**: DELETE +- **Description**: Deletes the container rate with the specified ID (only possible if the validity period is in state "draft") +- **Path Parameters**: + - `$id`: Container rate ID + +### Country Matrix Rates + +#### List Country Matrix Rates + +- **URL**: `/api/rates/matrix/` +- **Method**: GET +- **Description**: Returns a list of country matrix rates associated with a specific validity period +- **Query Parameters**: + - `limit`: Maximum number of items to return (default: 20\) + - `offset`: Number of items to skip (for pagination) + - `valid`: Validity period filter (values: validity\_period\_id, "current", "draft") + - `validAt`: Timestamp to find rates valid at a specific time +- **Response Format**: + +```javascript +[ + { + "id": "string", + "origin": { + "id": "string", + "country": { ... }, + "address": "string", + "location": { ... }, + "types": ["sink", "source", "intermediate"] + }, + "destination": { + "id": "string", + "country": { ... }, + "address": "string", + "location": { ... }, + "types": ["sink", "source", "intermediate"] + }, + "rate": "number" + }, + ... +] +``` + +#### Get Country Matrix Rate Details + +- **URL**: `/api/rates/matrix/{$id}` +- **Method**: GET +- **Description**: Returns detailed information about a specific country matrix rate +- **Path Parameters**: + - `$id`: Country matrix rate ID +- **Response Format**: Same as list country matrix rates + +#### Update Country Matrix Rate + +- **URL**: `/api/rates/matrix/{$id}` +- **Method**: PUT +- **Description**: Updates the country matrix rate with the specified ID (only possible if the validity period is in state "draft") +- **Path Parameters**: + - `$id`: Country matrix rate ID + +#### Delete Country Matrix Rate + +- **URL**: `/api/rates/matrix/{$id}` +- **Method**: DELETE +- **Description**: Deletes the country matrix rate with the specified ID (only possible if the validity period is in state "draft") +- **Path Parameters**: + - `$id`: Country matrix rate ID + +#### Check Staged Rate Changes + +- **URL**: `/api/rates/staged_changes/` +- **Method**: GET +- **Description**: Returns true if there are any unapproved "draft" rates, false otherwise + +#### Approve Rate Changes + +- **URL**: `/api/rates/staged_changes/` +- **Method**: PUT +- **Description**: Approves drafts and sets current "draft" validity period to current valid validity period + +## User Management Endpoints + +### User Operations {#user-operations} + +#### List Users + +- **URL**: `/api/users/` +- **Method**: GET +- **Description**: Lists all users +- **Query Parameters**: + - `limit`: Maximum number of items to return (default: 20\) + - `offset`: Number of items to skip (for pagination) +- **Authorization**: PSK (Pre-Shared Key) +- **Response Format**: + +```javascript +[ + { + "firstname": "string", + "lastname": "string", + "mail": "string", + "workday_id": "string", + "is_active": "boolean", + "groups": ["string", ...] + }, + ... +] +``` + +#### Create or Update User + +- **URL**: `/api/users/` +- **Method**: PUT +- **Description**: Updates an existing user or creates a new one +- **Authorization**: PSK (Pre-Shared Key) + +### Group Operations + +#### List Groups + +- **URL**: `/api/groups/` +- **Method**: GET +- **Description**: Lists all user groups +- **Query Parameters**: + - `limit`: Maximum number of items to return (default: 20\) + - `offset`: Number of items to skip (for pagination) +- **Authorization**: PSK (Pre-Shared Key) +- **Response Format**: + +```javascript +[ + { + "group_name": "string", + "group_description": "string" + }, + ... +] +``` + +#### Create or Update Group + +- **URL**: `/api/groups/` +- **Method**: PUT +- **Description**: Updates an existing group or creates a new one +- **Authorization**: PSK (Pre-Shared Key) + +## Calculation Endpoints {#calculation-endpoints} + +### Calculation Operations + +#### View Calculation Premises + +- **URL**: `/api/calculation/view` +- **Method**: GET +- **Description**: Lists a preview of all premises for the current user (or another user with elevated rights) +- **Query Parameters**: + - `limit`: Maximum number of items to return (default: 20\) + - `offset`: Number of items to skip (for pagination) + - `filter`: Search string + - `user`: User ID filter + - `deleted`: Boolean to include deleted premises (default: false) + - `archived`: Boolean to include archived premises (default: false) + - `done`: Boolean to include completed premises (default: true) +- **Response Format**: + +```javascript +[ + { + "id": "string", + "material": { + "id": "string", + "part_number": "string", + "name": "string" + }, + "supplier": { + "id": "string", + "country": { + "id": "string", + "iso_code": "string", + "region_code": "string" + }, + "name": "string", + "address": "string" + }, + "state": "string" + }, + ... +] +``` + +- **Note**: State can have the following values: `draft`, `completed`, `archived`, `deleted` + +#### Search for Materials and Suppliers + +- **URL**: `/api/calculation/search` +- **Method**: GET +- **Description**: Parses the given search string and returns the found materials and associated suppliers +- **Query Parameters**: + - `material`: Search string for materials +- **Response Format**: + +```javascript +{ + "materials": [ + { + "id": "string", + "part_number": "string", + "name": "string" + }, + ... + ], + "supplier": [ + { + "id": "string", + "country": { + "id": "string", + "iso_code": "string", + "region_code": "string" + }, + "name": "string", + "address": "string" + }, + ... + ], + "user_supplier": [ + { + "id": "string", + "country": { + "id": "string", + "iso_code": "string", + "region_code": "string" + }, + "name": "string", + "address": "string" + }, + ... + ] +} +``` + +#### Create Calculation Premises + +- **URL**: `/api/calculation/create` +- **Method**: GET +- **Description**: Returns a list of premises based on the provided parameters +- **Query Parameters**: + - `material`: Array of material IDs + - `supplier`: Array of supplier IDs + - `user_supplier`: Array of user supplier IDs + - `from_scratch`: Boolean to create empty premises +- **Response Format**: Detailed premise data including routes and transit nodes + +#### Edit Calculation Premises + +- **URL**: `/api/calculation/edit` +- **Method**: GET +- **Description**: Returns a list of premises based on the provided premise IDs +- **Query Parameters**: + - `premiss_ids`: Array of premise IDs +- **Response Format**: Detailed premise data including routes and transit nodes + +#### Save Calculation Premises + +- **URL**: `/api/calculation/edit` +- **Method**: PUT +- **Description**: Saves the provided premises +- **Request Body**: Array of premise objects with detailed route information + +## Reporting Endpoints + +### Reporting Operations {#reporting-operations} + +#### Download Report + +- **URL**: `/api/reports/download` +- **Method**: GET +- **Description**: Returns an Excel-file based report +- **Query Parameters**: + - `material`: Material ID + - `sources`: Array of source IDs + +#### Search Report Sources + +- **URL**: `/api/reports/search` +- **Method**: GET +- **Description**: Returns a list of source groups based on the given material ID +- **Query Parameters**: + - `material`: Material ID +- **Response Format**: + +```javascript +[ + ["source_id", ...],c + ... +] +``` + +#### View Report + +- **URL**: `/api/reports/view` +- **Method**: GET +- **Description**: Returns a detailed cost and risk report +- **Query Parameters**: + - `material`: Material ID + - `sources`: Array of source IDs +- **Response Format**: + +```javascript +[ + { + "cost": { + "material_cost": { + "total": "number", + "percentage": "number" + }, + "fca_fees": { + "total": "number", + "percentage": "number" + }, + "pre_run_cost": { + "total": "number", + "percentage": "number" + }, + "main_run_cost": { + "total": "number", + "percentage": "number" + }, + "post_run_cost": { + "total": "number", + "percentage": "number" + }, + "repacking_cost": { + "total": "number", + "percentage": "number" + }, + "handling_cost": { + "total": "number", + "percentage": "number" + }, + "storage_cost": { + "total": "number", + "percentage": "number" + }, + "captial_cost": { + "total": "number", + "percentage": "number" + }, + "disposal_cost": { + "total": "number", + "percentage": "number" + }, + "total_cost": { + "total": "number", + "percentage": "number" + } + }, + "risk": { + "air_freight_cost": { + "total": "number", + "percentage": "number" + }, + "best_case_cost": { + "total": "number", + "percentage": "number" + }, + "worst_case_cost": { + "total": "number", + "percentage": "number" + } + }, + "premisses": { + "quantities": [ + { + "destination": "string", + "quantity": "number", + "route": [ + { + "name": "string", + "type": "string", + "cost": { + "total": "number", + "percentage": "number" + } + }, + "..." + ] + } + ], + "hs_code": "string", + "custom_rate": "number", + "container": { + "type": "string", + "rate": "number", + "unit_count": "number", + "weight_exceeded": "boolean", + "utilization": "number", + "mixed": "boolean" + }, + "packaging": { + "width": "number", + "height": "number", + "length": "number", + "weight": "number", + "dimension_unit": "string", + "weight_unit": "string", + "unit_count": "number", + "layers": "number" + }, + "qouta_share": { + "oversea_share": "number", + "air_freight_share": "number", + "transport_time": "number", + "safety_stock": "number" + } + } + }, + "..." +] +``` + +## Glossary {#glossary} + +| Term | Definition | +| :---- | :---- | +| **API** | Application Programming Interface. A set of rules that allows programs to talk to each other. | +| **Calculation Premises** | The foundational data and assumptions used for logistics cost calculations. | +| **Container Rate** | Pricing for transportation of goods via standard shipping containers (20ft, 40ft, 40ft High Cube). | +| **Country Matrix** | A grid representing transportation rates between country pairs. | +| **Draft** | A working state for rates, properties, or other data that is not yet approved or in production. | +| **Handling Unit** | A physical package or container for materials (e.g., pallet, box). | +| **HS Code** | Harmonized System code. An international nomenclature for classifying traded products. | +| **LCC** | Logistics Cost Calculator, the primary system this API supports. | +| **Lead Time** | The time taken from ordering to delivery of materials. | +| **Material** | A product or component that is transported or managed in the system. | +| **Node** | A geographic location in the logistics network (could be source, sink, or intermediate). | +| **Packaging** | The physical container or wrapping for materials during transportation. | +| **Pre-Shared Key (PSK)** | A secret key shared between parties for authentication purposes. | +| **Property Type** | A definition of a characteristic that can be assigned to system entities. | +| **Rate** | The cost associated with transporting goods between locations. | +| **Sink** | A destination node in the logistics network (typically a manufacturing plant). | +| **Source** | An origin node in the logistics network (typically a supplier). | +| **System Property** | A configuration setting that affects the behavior of the LCC system. | +| **Transit Node** | An intermediate point in a transportation route. | +| **User Supplier** | A supplier that is specific to a particular user rather than system-wide. | +| **Validity Period** | A timeframe during which rates or other data are considered active and applicable. | + +# Database Documentation + +## Overview Database + +This document provides a comprehensive description of the LCC Backend Database structure. It handles property management, geographical data, user management, logistics nodes, transportation rates, packaging, materials, and calculation workflows for optimizing logistics operations. + +## Table Categories + +The database is organized into several functional areas: + +1. **Property Management** - Versioned configuration properties +2. **Geographic Data** - Countries and regions +3. **User Management** - Users, groups, and permissions +4. **Logistics Nodes** - Physical locations in the supply chain +5. **Transportation** - Distance matrices and rates +6. **Materials & Packaging** - Product and packaging information +7. **Premiss & Routes** - Supply chain scenarios and route planning +8. **Calculation** - Cost calculation jobs and results + +## Detailed Table Descriptions + +### Property Management + +#### `property_set` +Manages versioned sets of properties with temporal validity. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `start_date` | TIMESTAMP | When this property set becomes valid | +| `end_date` | TIMESTAMP | When this property set expires (NULL = no expiration) | +| `state` | CHAR(8) | Status of property set: DRAFT, VALID, INVALID, EXPIRED | + +#### `system_property_type` +Defines system-wide configuration property types. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `name` | VARCHAR(255) | Property type name | +| `external_mapping_id` | VARCHAR(16) | External system identifier | +| `data_type` | VARCHAR(16) | Data type: INT, PERCENTAGE, BOOLEAN, CURRENCY, ENUMERATION, TEXT | +| `validation_rule` | VARCHAR(64) | Optional validation rules | + +#### `system_property` +Stores system-wide configuration property values. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `property_set_id` | INT | References property_set | +| `system_property_type_id` | INT | References system_property_type | +| `property_value` | VARCHAR(500) | The value of the property | + +### Geographic Data + +#### `country` +Master data table for country information and regional classification. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `iso_code` | CHAR(2) | ISO 3166-1 alpha-2 country code | +| `region_code` | CHAR(5) | Geographic region: EMEA/LATAM/APAC/NAM | +| `name` | VARCHAR(128) | Country name | +| `is_deprecated` | BOOLEAN | Whether the country record is deprecated | + +#### `country_property_type` +Defines property types specific to countries. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `name` | VARCHAR(255) | Property type name | +| `external_mapping_id` | VARCHAR(16) | External system identifier | +| `data_type` | VARCHAR(16) | Data type: INT, PERCENTAGE, BOOLEAN, CURRENCY, ENUMERATION, TEXT | +| `validation_rule` | VARCHAR(64) | Optional validation rules | +| `is_required` | BOOLEAN | Whether the property is required | + +#### `country_property` +Stores country-specific property values with versioning support. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `country_id` | INT | References country | +| `country_property_type_id` | INT | References country_property_type | +| `property_set_id` | INT | References property_set | +| `property_value` | VARCHAR(500) | The value of the property | + +### User Management + +#### `sys_user` +Stores basic information about system users. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `workday_id` | CHAR(32) | External HR system identifier | +| `email` | VARCHAR(254) | User email | +| `firstname` | VARCHAR(100) | User first name | +| `lastname` | VARCHAR(100) | User last name | +| `is_active` | BOOLEAN | Whether the user is active | + +#### `sys_group` +Defines user groups for access management. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `group_name` | VARCHAR(64) | Group name | +| `group_description` | VARCHAR(128) | Group description | + +#### `sys_user_group_mapping` +Links users with their associated groups. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `user_id` | INT | References sys_user | +| `group_id` | INT | References sys_group | + +#### `sys_user_node` +Contains user-generated logistic nodes. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `user_id` | INT | References sys_user | +| `country_id` | INT | References country | +| `name` | VARCHAR(254) | Node name | +| `address` | VARCHAR(500) | Physical address | +| `geo_lat` | DECIMAL(7,4) | Latitude (-90 to 90) | +| `geo_lng` | DECIMAL(7,4) | Longitude (-180 to 180) | +| `is_deprecated` | BOOLEAN | Whether the node is deprecated | + +### Logistics Nodes + +#### `node` +Represents physical locations in the supply chain network. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `country_id` | INT | References country | +| `name` | VARCHAR(255) | Node name | +| `address` | VARCHAR(500) | Physical address | +| `external_mapping_id` | VARCHAR(32) | External system identifier | +| `predecessor_required` | BOOLEAN | Whether this node requires a predecessor | +| `is_sink` | BOOLEAN | Whether this node is a destination/consumption point | +| `is_source` | BOOLEAN | Whether this node is a source/production point | +| `is_intermediate` | BOOLEAN | Whether this node is a transfer point | +| `geo_lat` | DECIMAL(7,4) | Latitude (-90 to 90) | +| `geo_lng` | DECIMAL(7,4) | Longitude (-180 to 180) | +| `updated_at` | TIMESTAMP | Last update timestamp | +| `is_deprecated` | BOOLEAN | Whether the node is deprecated | + +#### `node_predecessor` +Defines predecessor relationships between nodes. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `node_id` | INT | References node | +| `predecessor_node_id` | INT | References node as a predecessor | +| `sequence_number` | INT | Position in the sequence (>0) | + +#### `outbound_country_mapping` +Maps nodes to countries they can serve. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `node_id` | INT | References node | +| `country_id` | INT | References country | + +#### `distance_matrix` +Stores distance information between nodes. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `from_node_id` | INT | References source node | +| `to_node_id` | INT | References destination node | +| `from_geo_lat` | DECIMAL(7,4) | Source latitude | +| `from_geo_lng` | DECIMAL(7,4) | Source longitude | +| `to_geo_lat` | DECIMAL(7,4) | Destination latitude | +| `to_geo_lng` | DECIMAL(7,4) | Destination longitude | +| `distance` | DECIMAL(15,2) | Travel distance in meters | +| `updated_at` | TIMESTAMP | Last update timestamp | +| `state` | CHAR(10) | Status: VALID, STALE | + +### Transportation Rates + +#### `validity_period` +Defines time periods for rate validity. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `start_date` | TIMESTAMP | When the period starts | +| `end_date` | TIMESTAMP | When the period ends (NULL = no end) | +| `state` | CHAR(8) | Status: DRAFT, VALID, INVALID, EXPIRED | + +#### `container_rate` +Stores rates for container transportation between nodes. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `from_node_id` | INT | References source node | +| `to_node_id` | INT | References destination node | +| `container_rate_type` | CHAR(8) | Type: RAIL, SEA, POST-RUN, ROAD | +| `rate_20` | DECIMAL(15,2) | Rate for 20ft container in EUR | +| `rate_40` | DECIMAL(15,2) | Rate for 40ft container in EUR | +| `rate_40_hc` | DECIMAL(15,2) | Rate for 40ft HQ container in EUR | +| `lead_time` | INT UNSIGNED | Lead time in days | +| `validity_period_id` | INT | References validity_period | + +#### `country_matrix_rate` +Stores rates for full truck load based on country pairs. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `from_country_id` | INT | References source country | +| `to_country_id` | INT | References destination country | +| `rate` | DECIMAL(15,2) | Rate for full truck load per kilometer in EUR | +| `validity_period_id` | INT | References validity_period | + +### Materials & Packaging + +#### `material` +Stores information about materials. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `part_number` | CHAR(12) | Material part number | +| `normalized_part_number` | CHAR(12) | Standardized part number (unique) | +| `hs_code` | CHAR(8) | Harmonized System code for customs | +| `name` | VARCHAR(500) | Material name | +| `is_deprecated` | BOOLEAN | Whether the material is deprecated | + +#### `packaging` +Defines packaging specifications. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `supplier_node_id` | INT | References node (supplier) | +| `material_id` | INT | References material | +| `parent_id` | INT | References parent packaging (hierarchical) | +| `type` | CHAR(3) | Type: SHU (small handling unit), HU (handling unit) | +| `length` | INT UNSIGNED | Length in mm | +| `width` | INT UNSIGNED | Width in mm | +| `height` | INT UNSIGNED | Height in mm | +| `displayed_dimension_unit` | CHAR(2) | Display unit: MM, CM, M | +| `weight` | INT UNSIGNED | Weight in g | +| `displayed_weight_unit` | CHAR(2) | Display unit: G, KG | +| `content_unit_count` | INT UNSIGNED | Number of units contained | +| `is_deprecated` | BOOLEAN | Whether the packaging is deprecated | + +#### `packaging_property_type` +Defines property types for packaging. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `name` | VARCHAR(255) | Property type name | +| `data_type` | VARCHAR(16) | Data type | +| `validation_rule` | VARCHAR(64) | Optional validation rules | +| `is_required` | BOOLEAN | Whether the property is required | + +#### `packaging_property` +Stores packaging property values. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `packaging_property_type_id` | INT | References packaging_property_type | +| `packaging_id` | INT | References packaging | +| `property_value` | VARCHAR(500) | The value of the property | + +### Premiss & Routes + +#### `premiss` +Core table for logistics scenario planning. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `material_id` | INT | References material | +| `supplier_node_id` | INT | References node (system supplier) | +| `user_supplier_node_id` | INT | References sys_user_node (user's supplier) | +| `packaging_id` | INT | References packaging | +| `user_id` | INT | References sys_user (creator) | +| `createdAt` | TIMESTAMP | Creation timestamp | +| `updatedAt` | TIMESTAMP | Last update timestamp | +| `material_cost` | DECIMAL(15,2) | Material cost in EUR (MEK_A) | +| `is_fca_enabled` | BOOLEAN | Free Carrier shipping terms enabled | +| `oversea_share` | DECIMAL(7,4) | Percentage of overseas transport | +| `hs_code` | CHAR(8) | Harmonized System code for customs | +| `custom_rate` | DECIMAL(7,4) | Custom duty rate | +| `state` | CHAR(10) | Status: DRAFT, COMPLETED, ARCHIVED, DELETED | +| `individual_hu_length` | INT UNSIGNED | Handling unit length in mm | +| `individual_hu_height` | INT UNSIGNED | Handling unit height in mm | +| `individual_hu_width` | INT UNSIGNED | Handling unit width in mm | +| `individual_hu_weight` | INT UNSIGNED | Handling unit weight in g | +| `hu_displayed_dimension_unit` | CHAR(2) | Display unit for dimensions | +| `hu_displayed_weight_unit` | CHAR(2) | Display unit for weight | +| `hu_unit_count` | INT UNSIGNED | Number of units per handling unit | +| `hu_stackable` | BOOLEAN | Whether the unit is stackable | +| `hu_mixable` | BOOLEAN | Whether the unit can be mixed with others | + +#### `premiss_sink` +Links premiss to destination nodes with volume information. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `premiss_id` | INT | References premiss | +| `annual_amount` | INT UNSIGNED | Annual amount in pieces | +| `sink_node_id` | INT | References node (destination) | + +#### `premiss_route` +Defines possible routes for a premiss_sink. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `premiss_sink_id` | INT | References premiss_sink | +| `is_fastest` | BOOLEAN | Whether this is the fastest route | +| `is_cheapest` | BOOLEAN | Whether this is the cheapest route | +| `is_selected` | BOOLEAN | Whether this route is selected/preferred | + +#### `premiss_route_node` +Defines nodes in a route. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `premiss_route_id` | INT | References premiss_route | +| `node_id` | INT | References node (system node) | +| `user_node_id` | INT | References sys_user_node (user's node) | +| `name` | VARCHAR(255) | Node name | +| `address` | VARCHAR(500) | Node address | +| `is_sink` | BOOLEAN | Whether this is a destination node | +| `is_intermediate` | BOOLEAN | Whether this is a transfer node | +| `is_source` | BOOLEAN | Whether this is a source node | +| `geo_lat` | DECIMAL(7,4) | Latitude | +| `geo_lng` | DECIMAL(7,4) | Longitude | +| `is_outdated` | BOOLEAN | Whether the node data is outdated | + +#### `premiss_route_section` +Defines transportation sections between route nodes. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `premiss_route_id` | INT | References premiss_route | +| `from_route_node_id` | INT | References premiss_route_node (source) | +| `to_route_node_id` | INT | References premiss_route_node (destination) | +| `list_position` | INT | Position in the route sequence | +| `transport_type` | CHAR(16) | Type: RAIL, SEA, ROAD, POST-RUN, MATRIX, D2D | +| `rate_d2d` | DECIMAL(15,2) | Door-to-door rate in EUR | +| `is_pre_run` | BOOLEAN | Whether this is a pre-run section | +| `is_main_run` | BOOLEAN | Whether this is a main-run section | +| `is_post_run` | BOOLEAN | Whether this is a post-run section | +| `is_outdated` | BOOLEAN | Whether the section data is outdated | + +### Calculation System + +#### `calculation_job` +Manages calculation processes. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `premiss_id` | INT | References premiss | +| `calculation_date` | TIMESTAMP | When the calculation was performed | +| `validity_period_id` | INT | References validity_period | +| `property_set_id` | INT | References property_set | +| `job_state` | CHAR(10) | Status: CREATED, SCHEDULED, VALID, INVALID, EXCEPTION | +| `user_id` | INT | References sys_user (creator) | + +#### `calculation_job_sink_result` +Stores calculation results per sink. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `calculation_job_id` | INT | References calculation_job | +| `premiss_sink_id` | INT | References premiss_sink | +| `safety_stock` | INT UNSIGNED | Safety stock in pieces | +| `shipping_frequency` | INT UNSIGNED | Annual shipping frequency | +| `total_cost` | DECIMAL(15,2) | Total cost in EUR (MEK_B) | + +#### `calculation_job_transportation_result` +Stores transportation calculation results. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `calculation_job_sink_result_id` | INT | References calculation_job_sink_result | +| `transportation_type` | CHAR(8) | Type: 20, 40, 40HC, TRUCK | +| `hu_per_layer` | INT UNSIGNED | Handling units per layer | +| `layer_structure` | JSON | Structure of a single layer | +| `layer_count` | INT UNSIGNED | Number of layers per container/truck | +| `transport_weight_exceeded` | BOOLEAN | Weight vs. volume limitation | +| `transports_per_year` | DECIMAL(15,2) | Number of transports per year | +| `annual_cost` | DECIMAL(15,2) | Annual transportation costs in EUR | + +#### `calculation_job_route_section_result` +Detailed calculation results for route sections. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `premiss_route_section_id` | INT | References premiss_route_section | +| `calculation_job_transportation_result_id` | INT | References calculation_job_transportation_result | +| `used_rule` | CHAR(8) | Calculation rule: CONTAINER, MATRIX | +| `is_unmixed_price` | BOOLEAN | Whether an unmixed pricing was used | +| `is_cbm_price` | BOOLEAN | Whether cubic meter pricing was used | +| `is_weight_price` | BOOLEAN | Whether weight-based pricing was used | +| `is_stacked` | BOOLEAN | Whether stacking was considered | +| `is_pre_run` | BOOLEAN | Whether this is a pre-run calculation | +| `is_main_run` | BOOLEAN | Whether this is a main-run calculation | +| `is_post_run` | BOOLEAN | Whether this is a post-run calculation | +| `rate` | DECIMAL(15,2) | Applied rate in EUR | +| `distance` | DECIMAL(15,2) | Section distance in meters | +| `cbm_price` | DECIMAL(15,2) | Price per cubic meter | +| `weight_price` | DECIMAL(15,2) | Price per kilogram | +| `annual_cost` | DECIMAL(15,2) | Annual costs for this section | +| `transit_time` | INT UNSIGNED | Transit time | + +#### `calculation_job_airfreight_result` +Stores air freight calculation results. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `calculation_job_sink_result_id` | INT | References calculation_job_sink_result | +| `air_freight_share_max` | DECIMAL(7,4) | Maximum air freight share | +| `air_freight_share` | DECIMAL(7,4) | Actual air freight share | +| `air_freight_volumetric_weight` | DECIMAL(15,2) | Volumetric weight | +| `air_freight_weight` | DECIMAL(15,2) | Actual weight | +| `annual_cost` | DECIMAL(15,2) | Annual air freight costs | + +#### `calculation_job_custom_result` +Stores customs duty calculation results. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `calculation_job_sink_result_id` | INT | References calculation_job_sink_result | +| `custom_value` | DECIMAL(15,2) | Customs value | +| `custom_duties` | DECIMAL(15,2) | Customs duties | +| `custom_rate` | DECIMAL(7,4) | Applied duty rate | +| `annual_cost` | DECIMAL(15,2) | Annual customs costs | + +#### `calculation_job_inventory_result` +Stores inventory calculation results. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `calculation_job_sink_result_id` | INT | References calculation_job_sink_result | +| `operational_stock` | DECIMAL(15,2) | Operational stock in pieces | +| `safety_stock` | DECIMAL(15,2) | Safety stock in pieces | +| `stocked_inventory` | DECIMAL(15,2) | Total stocked inventory | +| `in_transport_stock` | DECIMAL(15,2) | Stock in transport | +| `stock_before_payment` | DECIMAL(15,2) | Stock before payment | +| `annual_capital_cost` | DECIMAL(15,2) | Annual capital costs | +| `annual_storage_cost` | DECIMAL(15,2) | Annual storage costs | + +#### `calculation_job_handling_result` +Stores handling cost calculation results. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `calculation_job_sink_result_id` | INT | References calculation_job_sink_result | +| `is_small_unit` | BOOLEAN | Whether this is a small unit (< 0.08 cbm) | +| `annual_repacking_cost` | DECIMAL(15,2) | Annual repacking costs | +| `annual_handling_cost` | DECIMAL(15,2) | Annual handling costs | +| `annual_disposal_cost` | DECIMAL(15,2) | Annual disposal costs | + +#### `calculation_job_risk_result` +Stores risk assessment calculation results. + +| Column | Type | Description | +|--------|------|-------------| +| `id` | INT | Primary key | +| `calculation_job_sink_result_id` | INT | References calculation_job_sink_result | +| `annual_risk_cost` | DECIMAL(15,2) | Annual risk costs (worst case) | +| `annual_chance_cost` | DECIMAL(15,2) | Annual opportunity costs (best case) | + +## Entity Relationship Diagram + +The database has several key relationship patterns: + +1. The `property_set` system provides versioned configuration for both system-wide and country-specific properties +2. The `node` system forms the backbone of the logistics network +3. The `premiss` system ties together materials, packaging, suppliers, and destinations +4. The `calculation_job` system captures results of cost calculations with various components + +## Common Data Types and Conventions + +- Monetary values are stored as DECIMAL(15,2) in EUR +- Geographical coordinates are stored as DECIMAL(7,4) +- Dimensions are stored in mm (millimeters) +- Weights are stored in g (grams) +- Most tables include an `is_deprecated` flag for soft-deletion +- State/status fields use CHECK constraints to limit valid values diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 55f9c29..d9c3ae6 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -1,5 +1,3 @@ - - -- Property management tables CREATE TABLE IF NOT EXISTS `property_set` ( @@ -14,28 +12,40 @@ CREATE TABLE IF NOT EXISTS `property_set` INDEX `idx_property_set_id` (id) ) COMMENT 'Manages versioned sets of properties with temporal validity'; +CREATE TABLE IF NOT EXISTS `system_property_type` +( + -- Stores system-wide configuration property types + `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + `name` VARCHAR(255) NOT NULL, + `external_mapping_id` VARCHAR(16), + `data_type` VARCHAR(16) NOT NULL, + `validation_rule` VARCHAR(64), + CONSTRAINT `chk_system_data_type_values` CHECK (`data_type` IN + ('INT', 'PERCENTAGE', 'BOOLEAN', 'CURRENCY', 'ENUMERATION', + 'TEXT')) +) COMMENT 'Stores system-wide configuration property types'; + CREATE TABLE IF NOT EXISTS `system_property` ( -- Stores system-wide configuration properties - `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, - `property_set_id` INT NOT NULL, - `description` VARCHAR(255) NOT NULL, - `short_description` VARCHAR(16), - `data_type` VARCHAR(16) NOT NULL, - `validation_rule` VARCHAR(64), - `property_value` VARCHAR(500), - CONSTRAINT `chk_system_data_type_values` CHECK (`data_type` IN - ('INT', 'PERCENTAGE', 'BOOLEAN', 'CURRENCY', 'ENUMERATION', 'TEXT')), - FOREIGN KEY (`property_set_id`) REFERENCES `property_set` (`id`) + `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + `property_set_id` INT NOT NULL, + `system_property_type_id` INT NOT NULL, + `property_value` VARCHAR(500), + FOREIGN KEY (`property_set_id`) REFERENCES `property_set` (`id`), + FOREIGN KEY (`system_property_type_id`) REFERENCES `system_property_type` (`id`), + INDEX `idx_system_property_type_id` (system_property_type_id), + INDEX `idx_property_set_id` (id) ) COMMENT 'Stores system-wide configuration properties'; -- country CREATE TABLE IF NOT EXISTS `country` ( - `id` INT NOT NULL AUTO_INCREMENT, - `iso_code` CHAR(2) NOT NULL COMMENT 'ISO 3166-1 alpha-2 country code', - `region_code` CHAR(5) NOT NULL COMMENT 'Geographic region code (EMEA/LATAM/APAC/NAM)', - `is_deprecated` BOOLEAN NOT NULL DEFAULT FALSE, + `id` INT NOT NULL AUTO_INCREMENT, + `iso_code` CHAR(2) NOT NULL COMMENT 'ISO 3166-1 alpha-2 country code', + `region_code` CHAR(5) NOT NULL COMMENT 'Geographic region code (EMEA/LATAM/APAC/NAM)', + `name` VARCHAR(128) NOT NULL, + `is_deprecated` BOOLEAN NOT NULL DEFAULT FALSE, PRIMARY KEY (`id`), UNIQUE INDEX `idx_country_iso_code` (`iso_code`), CONSTRAINT `chk_country_region_code` @@ -44,27 +54,28 @@ CREATE TABLE IF NOT EXISTS `country` CREATE TABLE IF NOT EXISTS `country_property_type` ( - `id` INT NOT NULL AUTO_INCREMENT, - `description` VARCHAR(255) NOT NULL, - `short_description` VARCHAR(16), - `data_type` VARCHAR(16) NOT NULL, - `validation_rule` VARCHAR(64), - `is_required` BOOLEAN NOT NULL DEFAULT FALSE, + `id` INT NOT NULL AUTO_INCREMENT, + `name` VARCHAR(255) NOT NULL, + `external_mapping_id` VARCHAR(16), + `data_type` VARCHAR(16) NOT NULL, + `validation_rule` VARCHAR(64), + `is_required` BOOLEAN NOT NULL DEFAULT FALSE, CONSTRAINT `chk_country_data_type_values` CHECK (`data_type` IN - ('INT', 'PERCENTAGE', 'BOOLEAN', 'CURRENCY', 'ENUMERATION', 'TEXT')), + ('INT', 'PERCENTAGE', 'BOOLEAN', 'CURRENCY', 'ENUMERATION', + 'TEXT')), PRIMARY KEY (`id`), INDEX `idx_property_type_data_type` (`data_type`) ) COMMENT 'Defines available property types for country-specific configurations'; CREATE TABLE IF NOT EXISTS `country_property` ( - `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, - `country_id` INT NOT NULL, - `property_type_id` INT NOT NULL, - `property_set_id` INT NOT NULL, - `property_value` VARCHAR(500), + `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + `country_id` INT NOT NULL, + `country_property_type_id` INT NOT NULL, + `property_set_id` INT NOT NULL, + `property_value` VARCHAR(500), FOREIGN KEY (`country_id`) REFERENCES `country` (`id`), - FOREIGN KEY (`property_type_id`) REFERENCES `country_property_type` (`id`), + FOREIGN KEY (`country_property_type_id`) REFERENCES `country_property_type` (`id`), FOREIGN KEY (`property_set_id`) REFERENCES `property_set` (`id`) ) COMMENT 'Stores country-specific property values with versioning support'; @@ -84,8 +95,9 @@ CREATE TABLE IF NOT EXISTS `sys_user` -- Group definitions CREATE TABLE IF NOT EXISTS `sys_group` ( - `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, - `group_name` CHAR(64) NOT NULL, + `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + `group_name` VARCHAR(64) NOT NULL, + `group_description` VARCHAR(128) NOT NULL, UNIQUE INDEX `idx_group_name` (`group_name`) ) COMMENT 'Defines user groups for access management'; @@ -103,13 +115,14 @@ CREATE TABLE IF NOT EXISTS `sys_user_group_mapping` CREATE TABLE IF NOT EXISTS `sys_user_node` ( - `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, - `user_id` INT NOT NULL, - `country_id` INT NOT NULL, - `description` VARCHAR(255) NOT NULL, - `address` VARCHAR(500) NOT NULL, - `geo_lat` DECIMAL(7, 4) CHECK (geo_lat BETWEEN -90 AND 90), - `geo_lng` DECIMAL(7, 4) CHECK (geo_lng BETWEEN -180 AND 180), + `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + `user_id` INT NOT NULL, + `country_id` INT NOT NULL, + `name` VARCHAR(254) NOT NULL, + `address` VARCHAR(500) NOT NULL, + `geo_lat` DECIMAL(7, 4) CHECK (geo_lat BETWEEN -90 AND 90), + `geo_lng` DECIMAL(7, 4) CHECK (geo_lng BETWEEN -180 AND 180), + `is_deprecated` BOOLEAN DEFAULT FALSE, FOREIGN KEY (`user_id`) REFERENCES `sys_user` (`id`), FOREIGN KEY (`country_id`) REFERENCES `country` (`id`) ) COMMENT 'Contains user generated logistic nodes'; @@ -121,7 +134,7 @@ CREATE TABLE node ( id INT PRIMARY KEY, country_id INT NOT NULL, - description VARCHAR(255) NOT NULL, + name VARCHAR(255) NOT NULL, address VARCHAR(500) NOT NULL, external_mapping_id VARCHAR(32), predecessor_required BOOLEAN NOT NULL DEFAULT FALSE, @@ -231,7 +244,7 @@ CREATE TABLE material part_number CHAR(12) NOT NULL, normalized_part_number CHAR(12) NOT NULL, hs_code CHAR(8), - description VARCHAR(500) NOT NULL, + name VARCHAR(500) NOT NULL, is_deprecated BOOLEAN NOT NULL DEFAULT FALSE, CONSTRAINT `chk_normalized_part_number` UNIQUE (`normalized_part_number`) ); @@ -254,9 +267,9 @@ CREATE TABLE packaging CONSTRAINT `chk_type_values` CHECK (`type` IN ('SHU', 'HU')), CONSTRAINT `chk_packaging_displayed_dimension_unit` CHECK (`displayed_dimension_unit` IN - ('MM', 'CM', 'M')), + ('MM', 'CM', 'M')), CONSTRAINT `chk_packaging_displayed_weight_unit` CHECK (`displayed_weight_unit` IN - ('G', 'KG')), + ('G', 'KG')), FOREIGN KEY (supplier_node_id) REFERENCES node (id), FOREIGN KEY (material_id) REFERENCES material (id), FOREIGN KEY (parent_id) REFERENCES packaging (id), @@ -268,12 +281,13 @@ CREATE TABLE packaging CREATE TABLE packaging_property_type ( `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, - `description` VARCHAR(500) NOT NULL, - `data_type` CHAR(16), - `validation_rule` CHAR(64), + `name` VARCHAR(255) NOT NULL, + `data_type` VARCHAR(16), + `validation_rule` VARCHAR(64), `is_required` BOOLEAN NOT NULl DEFAULT FALSE, CONSTRAINT `chk_packaging_data_type_values` CHECK (`data_type` IN - ('INT', 'PERCENTAGE', 'BOOLEAN', 'CURRENCY', 'ENUMERATION', 'TEXT')) + ('INT', 'PERCENTAGE', 'BOOLEAN', 'CURRENCY', 'ENUMERATION', + 'TEXT')) ); CREATE TABLE packaging_property @@ -288,27 +302,18 @@ CREATE TABLE packaging_property INDEX idx_packaging_id (packaging_id) ); -CREATE TABLE calculation -( - id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, - material_id INT NOT NULL, - supplier_node_id INT NOT NULL, - packaging_id INT DEFAULT NULL, - FOREIGN KEY (material_id) REFERENCES material (id), - FOREIGN KEY (supplier_node_id) REFERENCES node (id), - FOREIGN KEY (packaging_id) REFERENCES packaging (id), - INDEX idx_material_id (material_id), - INDEX idx_supplier_node_id (supplier_node_id), - INDEX idx_packaging_id (packaging_id) -); - CREATE TABLE premiss ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, - calculation_id INT NOT NULL, + material_id INT NOT NULL, + supplier_node_id INT, + user_supplier_node_id INT, + packaging_id INT DEFAULT NULL, user_id INT NOT NULL, + createdAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updatedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, material_cost DECIMAL(15, 2) COMMENT 'aka MEK_A in EUR', - is_fca_enabled BOOLEAN DEFAULT FALSE, + is_fca_enabled BOOLEAN DEFAULT FALSE, oversea_share DECIMAL(7, 4), hs_code CHAR(8), custom_rate DECIMAL(7, 4), @@ -317,21 +322,27 @@ CREATE TABLE premiss individual_hu_height INT UNSIGNED NOT NULL COMMENT 'user entered dimensions in mm (if system-wide packaging is used, packaging dimensions are copied here after creation)', individual_hu_width INT UNSIGNED NOT NULL COMMENT 'user entered dimensions in mm (if system-wide packaging is used, packaging dimensions are copied here after creation)', individual_hu_weight INT UNSIGNED NOT NULL COMMENT 'user entered weight in g (if system-wide packaging is used, packaging weight are copied here after creation)', - hu_displayed_dimension_unit CHAR(2) DEFAULT 'MM', - hu_displayed_weight_unit CHAR(2) DEFAULT 'G', - hu_unit_count INT UNSIGNED DEFAULT NULL, - hu_stackable BOOLEAN DEFAULT TRUE, - hu_mixable BOOLEAN DEFAULT TRUE, - FOREIGN KEY (calculation_id) REFERENCES calculation (id), + hu_displayed_dimension_unit CHAR(2) DEFAULT 'MM', + hu_displayed_weight_unit CHAR(2) DEFAULT 'G', + hu_unit_count INT UNSIGNED DEFAULT NULL, + hu_stackable BOOLEAN DEFAULT TRUE, + hu_mixable BOOLEAN DEFAULT TRUE, + FOREIGN KEY (material_id) REFERENCES material (id), + FOREIGN KEY (supplier_node_id) REFERENCES node (id), + FOREIGN KEY (user_supplier_node_id) REFERENCES sys_user_node (id), + FOREIGN KEY (packaging_id) REFERENCES packaging (id), FOREIGN KEY (user_id) REFERENCES sys_user (id), CONSTRAINT `chk_premiss_state_values` CHECK (`state` IN - ('DRAFT', 'COMPLETED', 'ARCHIVED', 'DELETED')), + ('DRAFT', 'COMPLETED', 'ARCHIVED', 'DELETED')), CONSTRAINT `chk_premiss_displayed_dimension_unit` CHECK (`hu_displayed_dimension_unit` IN - ('MM', 'CM', 'M')), + ('MM', 'CM', 'M')), CONSTRAINT `chk_premiss_displayed_weight_unit` CHECK (`hu_displayed_weight_unit` IN - ('G', 'KG')), - INDEX idx_calculation_id (calculation_id), - INDEX idx_user_id (user_id) + ('G', 'KG')), + INDEX idx_material_id (material_id), + INDEX idx_supplier_node_id (supplier_node_id), + INDEX idx_packaging_id (packaging_id), + INDEX idx_user_id (user_id), + INDEX idx_user_supplier_node_id (user_supplier_node_id) ); @@ -349,10 +360,12 @@ CREATE TABLE premiss_sink CREATE TABLE premiss_route ( - id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, - premiss_sink_node_id INT NOT NULL, - is_selected BOOLEAN DEFAULT FALSE, - FOREIGN KEY (premiss_sink_node_id) REFERENCES premiss_sink (id) + id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + premiss_sink_id INT NOT NULL, + is_fastest BOOLEAN DEFAULT FALSE, + is_cheapest BOOLEAN DEFAULT FALSE, + is_selected BOOLEAN DEFAULT FALSE, + FOREIGN KEY (premiss_sink_id) REFERENCES premiss_sink (id) ); CREATE TABLE premiss_route_node @@ -361,7 +374,7 @@ CREATE TABLE premiss_route_node premiss_route_id INT NOT NULL, node_id INT DEFAULT NULL, user_node_id INT DEFAULT NULL, - description VARCHAR(255) NOT NULL, + name VARCHAR(255) NOT NULL, address VARCHAR(500), is_sink BOOLEAN DEFAULT FALSE, is_intermediate BOOLEAN DEFAULT FALSE, @@ -474,6 +487,7 @@ CREATE TABLE calculation_job_route_section_result cbm_price DECIMAL(15, 2) NOT NULL COMMENT 'calculated price per cubic meter', weight_price DECIMAL(15, 2) NOT NULL COMMENT 'calculated price per kilogram', annual_cost DECIMAL(15, 2) NOT NULL COMMENT 'annual costs for this route section, result depends on calculation method (mixed or unmixed, stacked or unstacked, per volume/per weight resp. container rate/price matrix)', + transit_time INT UNSIGNED NOT NULL, FOREIGN KEY (premiss_route_section_id) REFERENCES premiss_route_section (id), FOREIGN KEY (calculation_job_transportation_result_id) REFERENCES calculation_job_transportation_result (id), INDEX idx_premiss_route_section_id (premiss_route_section_id),