openapi: 3.0.3
info:
  title: Copenhagen Truck Wash API
  description: |
    This API provides access to the Copenhagen Truck Wash system, managing orders, bookings, 
    departments, products, customers, and various integrations including e-conomic, Stripe, 
    XLVask, and more.
    
    ## Authentication
    Most endpoints require authentication using a Bearer token obtained from the `/auth/login` 
    or `/auth/employee/login` endpoints.
    
    ## Permissions
    Many endpoints require specific permissions that are assigned to user groups/roles.
  version: 1.0.0
  contact:
    name: Copenhagen Truck Wash
    email: support@truckwash.dk
servers:
  - url: https://api.truckwash.dk
    description: Production server
  - url: http://localhost
    description: Local development server

security:
  - BearerAuth: []

tags:
  - name: Authentication
    description: User and employee authentication endpoints
  - name: Users
    description: User management and customer operations
  - name: Orders
    description: Order creation, management, and retrieval
  - name: Order Items
    description: Managing items within orders
  - name: Bookings
    description: Booking management for wash services
  - name: Departments
    description: Department and location management
  - name: Products
    description: Product catalog and pricing
  - name: Categories
    description: Product category management
  - name: Invoices
    description: Invoice generation and management
  - name: Payments
    description: Payment processing and collection
  - name: Vehicles
    description: Vehicle registration and management
  - name: Notifications
    description: System notifications and alerts
  - name: Statistics
    description: Business analytics and reporting
  - name: Modules
    description: Third-party integrations and modules
  - name: Attachments
    description: File upload and attachment management
  - name: Forms
    description: Form submissions and management
  - name: Worker
    description: System worker status and maintenance
  - name: Plate Scans
    description: License plate scanning operations
  - name: Config
    description: Module configuration management
  - name: Branding
    description: Branding options management
  - name: Roles
    description: Role and permission management
  - name: Self-Serve
    description: Self-serve lane operations and questions

paths:
  # Authentication Endpoints
  /auth/login:
    post:
      tags:
        - Authentication
      summary: Customer login
      description: Authenticate a customer using customer number and password
      operationId: customerLogin
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - customer_number
                - password
              properties:
                customer_number:
                  type: integer
                  description: Customer's e-conomic customer number
                  example: 12345
                password:
                  type: string
                  format: password
                  description: Customer password
                  minLength: 1
      responses:
        '200':
          description: Login successful
          content:
            application/json:
              schema:
                type: object
                properties:
                  token:
                    type: string
                    description: Bearer authentication token
                    example: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /auth/employee/login:
    post:
      tags:
        - Authentication
      summary: Employee login
      description: Authenticate an employee using user ID and password
      operationId: employeeLogin
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - user_id
                - password
              properties:
                user_id:
                  type: integer
                  description: Employee user ID
                  example: 1
                password:
                  type: string
                  format: password
                  description: Employee password
      responses:
        '200':
          description: Login successful
          content:
            application/json:
              schema:
                type: object
                properties:
                  token:
                    type: string
                    description: Bearer authentication token
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /auth/logout:
    get:
      tags:
        - Authentication
      summary: Logout
      description: Invalidate the current authentication token
      operationId: logout
      responses:
        '200':
          description: Logout successful
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "Logged out"
        '401':
          $ref: '#/components/responses/Unauthorized'

  /auth/session:
    get:
      tags:
        - Authentication
      summary: Get current session
      description: Retrieve information about the current authenticated user session
      operationId: getSession
      responses:
        '200':
          description: Session information retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /auth/reCAPTCHA/public:
    get:
      tags:
        - Authentication
      summary: Get reCAPTCHA configuration
      description: Retrieve public reCAPTCHA configuration for login forms
      operationId: getRecaptchaConfig
      security: []
      responses:
        '200':
          description: reCAPTCHA configuration retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  rate_limit:
                    type: object
                    properties:
                      enabled:
                        type: boolean
                      limit:
                        type: integer
                      remaining:
                        type: integer
                      reset:
                        type: integer
                      warning:
                        type: string
                        nullable: true
                  recaptcha:
                    type: object

  /auth/register/cvr:
    post:
      tags:
        - Authentication
      summary: Register new customer by CVR
      description: Register a new customer account using Danish CVR number
      operationId: registerCustomerByCvr
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - cvr
                - companyPhone
                - invoiceEmail
                - contactEmail
                - contactPhone
                - contactName
              properties:
                cvr:
                  type: string
                  description: Danish CVR number
                  minLength: 8
                  maxLength: 20
                  example: "44794780"
                companyPhone:
                  type: integer
                  description: Company phone number
                  minimum: 10000000
                  maximum: 9999999999
                  example: 21754690
                invoiceEmail:
                  type: string
                  format: email
                  description: Email for invoices
                  minLength: 5
                  maxLength: 255
                  example: "invoice@company.dk"
                contactEmail:
                  type: string
                  format: email
                  description: Contact email
                  minLength: 5
                  maxLength: 255
                  example: "contact@company.dk"
                contactPhone:
                  type: integer
                  description: Contact phone number
                  minimum: 10000000
                  maximum: 9999999999
                  example: 21754690
                contactName:
                  type: string
                  description: Contact person name
                  example: "Mikkel"
      responses:
        '201':
          description: Customer registered successfully
        '400':
          $ref: '#/components/responses/BadRequest'

  /su/intimidate:
    post:
      tags:
        - Authentication
      summary: Intimidate a user
      description: Create an authentication token for another user (Superuser only)
      operationId: suIntimidate
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [user_id]
              properties:
                user_id: {type: integer}
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: object
                properties:
                  token: {type: string}

  # User Endpoints
  /users:
    get:
      tags:
        - Users
      summary: List users
      description: Retrieve a paginated list of users
      operationId: listUsers
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
        - $ref: '#/components/parameters/SearchParam'
      responses:
        '200':
          description: Users retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      tags:
        - Users
      summary: Create new user
      description: Create a new user account
      operationId: createUser
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserCreate'
      responses:
        '201':
          description: User created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
    put:
      tags:
        - Users
      summary: Update user
      description: Update an existing user
      operationId: updateUser
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserUpdate'
      responses:
        '200':
          description: User updated successfully
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /users/customer:
    get:
      tags:
        - Users
      summary: Get customer details
      description: Get details about a specific customer
      operationId: getCustomer
      parameters:
        - name: customer_number
          in: query
          schema:
            type: integer
      responses:
        '200':
          description: Customer retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '404':
          $ref: '#/components/responses/NotFound'

  /superuser/user:
    get:
      tags:
        - Users
      summary: Get user by ID (superuser)
      description: Get detailed user information by user ID
      operationId: getSuperuserUser
      parameters:
        - name: user_id
          in: query
          schema:
            type: integer
      responses:
        '200':
          description: User retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '404':
          $ref: '#/components/responses/NotFound'

  /admin/customer/code:
    get:
      tags:
        - Users
      summary: Get customer code
      operationId: getCustomerCode
      parameters:
        - name: customer_number
          in: query
          schema: {type: integer}
        - name: user_id
          in: query
          schema: {type: integer}
      responses:
        '200':
          description: Success
    post:
      tags:
        - Users
      summary: Add customer code
      operationId: addCustomerCode
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                customer_number: {type: integer}
                user_id: {type: integer}
                code: {type: string}
      responses:
        '200':
          description: Success

  /customer/department/default:
    get:
      tags:
        - Users
      summary: Get customer default department
      operationId: getCustomerDefaultDepartment
      parameters:
        - name: customer_number
          in: query
          schema: {type: integer}
      responses:
        '200':
          description: Success
    post:
      tags:
        - Users
      summary: Add customer default department
      operationId: addCustomerDefaultDepartment
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [department]
              properties:
                customer_number: {type: integer}
                department: {type: integer}
      responses:
        '200':
          description: Success
    delete:
      tags:
        - Users
      summary: Delete customer default department
      operationId: deleteCustomerDefaultDepartment
      parameters:
        - name: customer_number
          in: query
          schema: {type: integer}
      responses:
        '200':
          description: Success

  /customer/pricing/fixed:
    get:
      tags:
        - Users
      summary: Get customer fixed pricing
      operationId: getCustomerFixedPricing
      parameters:
        - name: customer_number
          in: query
          required: true
          schema: {type: integer}
      responses:
        '200':
          description: Success
    post:
      tags:
        - Users
      summary: Add customer fixed pricing
      operationId: addCustomerFixedPricing
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [customer_number, price, description]
              properties:
                customer_number: {type: integer}
                price: {type: integer}
                description: {type: string}
      responses:
        '200':
          description: Success
    delete:
      tags:
        - Users
      summary: Delete customer fixed pricing
      operationId: deleteCustomerFixedPricing
      parameters:
        - name: customer_number
          in: query
          required: true
          schema: {type: integer}
      responses:
        '200':
          description: Success

  /account/notifications:
    put:
      tags:
        - Users
      summary: Update user notification settings
      operationId: updateUserNotifications
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                wash_certificate_email: {type: string}
                sms_notifications_enabled: {type: boolean}
                email_notifications_enabled: {type: boolean}
      responses:
        '200':
          description: Success

  /user/permissions:
    get:
      tags:
        - Users
      summary: Get user permissions
      operationId: getUserPermissions
      responses:
        '200':
          description: Success

  /customers:
    get:
      tags:
        - Users
      summary: List customers
      operationId: listCustomers
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
        - $ref: '#/components/parameters/SearchParam'
      responses:
        '200':
          description: Success

  /superuser/user/discounts:
    get:
      tags:
        - Users
      summary: Get user discounts
      operationId: getUserDiscounts
      parameters:
        - name: user_id
          in: query
          required: true
          schema: {type: integer}
      responses:
        '200':
          description: Success
    post:
      tags:
        - Users
      summary: Set user discount
      operationId: setUserDiscount
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [discount, object_id, is_category]
              properties:
                user_id: {type: integer}
                discount: {type: integer}
                object_id: {type: string}
                is_category: {type: boolean}
      responses:
        '200':
          description: Success

  /superuser/user/keys:
    get:
      tags:
        - Users
      summary: Get user keys
      operationId: getUserKeys
      parameters:
        - name: user_id
          in: query
          required: true
          schema: {type: integer}
        - name: key
          in: query
          schema: {type: string}
      responses:
        '200':
          description: Success
    post:
      tags:
        - Users
      summary: Set user key
      operationId: setUserKey
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [key, value]
              properties:
                user_id: {type: integer}
                key: {type: string}
                value: {type: string}
      responses:
        '200':
          description: Success

  /superuser/user/password:
    post:
      tags:
        - Users
      summary: Set user password
      operationId: setUserPassword
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [password]
              properties:
                user_id: {type: integer}
                password: {type: string}
      responses:
        '200':
          description: Success

  /admin/customer/getUserId:
    get:
      tags:
        - Users
      summary: Get user ID from customer number
      description: Convert e-conomic customer number to internal user ID
      operationId: getUserIdFromCustomerNumber
      parameters:
        - name: customer_number
          in: query
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: User ID retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  user_id:
                    type: integer

  /admin/customer/name:
    get:
      tags:
        - Users
      summary: Get customer name
      description: Get the full name of a customer
      operationId: getCustomerName
      parameters:
        - name: user_id
          in: query
          schema:
            type: integer
      responses:
        '200':
          description: Customer name retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  name:
                    type: string

  # Orders Endpoints
  /orders:
    get:
      tags:
        - Orders
      summary: List orders
      description: Retrieve a paginated list of orders
      operationId: listOrders
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
        - $ref: '#/components/parameters/SearchParam'
        - name: show_wash_subscription
          in: query
          schema:
            type: string
            enum: [true, false]
      responses:
        '200':
          description: Orders retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Order'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
    post:
      tags:
        - Orders
      summary: Create new order
      description: Create a new wash order
      operationId: createOrder
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OrderCreate'
      responses:
        '201':
          description: Order created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
    delete:
      tags:
        - Orders
      summary: Delete order
      description: Delete an existing order
      operationId: deleteOrder
      parameters:
        - name: id
          in: query
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Order deleted successfully
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    put:
      tags:
        - Orders
      summary: Update order (alias)
      description: Update an existing order
      operationId: updateOrders
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OrderUpdate'
      responses:
        '200':
          description: Order updated successfully
        '400':
          $ref: '#/components/responses/BadRequest'

  /order:
    get:
      tags:
        - Orders
      summary: Get order details
      description: Get detailed information about a specific order
      operationId: getOrder
      parameters:
        - name: id
          in: query
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Order retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'
        '404':
          $ref: '#/components/responses/NotFound'
    put:
      tags:
        - Orders
      summary: Update order
      description: Update an existing order
      operationId: updateOrder
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OrderUpdate'
      responses:
        '200':
          description: Order updated successfully
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /user/orders:
    get:
      tags:
        - Orders
      summary: Get current user's orders
      description: Retrieve orders for the authenticated user
      operationId: getUserOrders
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
      responses:
        '200':
          description: Orders retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Order'

  /user/order:
    get:
      tags:
        - Orders
      summary: Get user's specific order
      description: Get details of a specific order for the authenticated user
      operationId: getUserOrder
      parameters:
        - name: id
          in: query
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Order retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'

  /orders/mark_as_completed:
    post:
      tags:
        - Orders
      summary: Mark order as completed
      description: Mark an order as completed
      operationId: markOrderCompleted
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - id
              properties:
                id:
                  type: integer
      responses:
        '200':
          description: Order marked as completed successfully
        '400':
          $ref: '#/components/responses/BadRequest'

  /order/wash-certificate:
    post:
      tags:
        - Orders
      summary: Generate wash certificate
      description: Generate a wash certificate for an order
      operationId: generateWashCertificate
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                order_id:
                  type: integer
      responses:
        '200':
          description: Wash certificate generated successfully
        '400':
          $ref: '#/components/responses/BadRequest'

  # Order Items Endpoints
  /order/items:
    get:
      tags:
        - Order Items
      summary: List order items
      description: Get all items for a specific order
      operationId: listOrderItems
      parameters:
        - name: order_id
          in: query
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Order items retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/OrderItem'
    post:
      tags:
        - Order Items
      summary: Add item to order
      description: Add a new item to an existing order
      operationId: addOrderItem
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OrderItemCreate'
      responses:
        '201':
          description: Order item added successfully
        '400':
          $ref: '#/components/responses/BadRequest'
    put:
      tags:
        - Order Items
      summary: Update order item
      description: Update an existing order item
      operationId: updateOrderItem
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OrderItemUpdate'
      responses:
        '200':
          description: Order item updated successfully
        '400':
          $ref: '#/components/responses/BadRequest'
    delete:
      tags:
        - Order Items
      summary: Delete order item
      description: Remove an item from an order
      operationId: deleteOrderItem
      parameters:
        - name: id
          in: query
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Order item deleted successfully
        '404':
          $ref: '#/components/responses/NotFound'

  # Departments Endpoints
  /departments:
    get:
      tags:
        - Departments
      summary: List departments
      description: Retrieve a list of all visible departments
      operationId: listDepartments
      parameters:
        - name: id
          in: query
          schema:
            type: integer
          description: Filter by specific department ID
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
        - $ref: '#/components/parameters/SearchParam'
      responses:
        '200':
          description: Departments retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Department'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      tags:
        - Departments
      summary: Create department
      description: Create a new department
      operationId: createDepartment
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DepartmentCreate'
      responses:
        '201':
          description: Department created successfully
        '400':
          $ref: '#/components/responses/BadRequest'
    put:
      tags:
        - Departments
      summary: Update department
      description: Update an existing department
      operationId: updateDepartment
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DepartmentUpdate'
      responses:
        '200':
          description: Department updated successfully
        '400':
          $ref: '#/components/responses/BadRequest'

  /departments/categories:
    get:
      tags:
        - Departments
      summary: Get department categories
      description: Get product categories available in a department
      operationId: getDepartmentCategories
      parameters:
        - name: department_id
          in: query
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Department categories retrieved successfully
    post:
      tags:
        - Departments
      summary: Add category to department
      description: Associate a product category with a department
      operationId: addDepartmentCategory
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                department_id:
                  type: integer
                category_id:
                  type: integer
      responses:
        '201':
          description: Category added to department successfully
    delete:
      tags:
        - Departments
      summary: Remove category from department
      operationId: removeDepartmentCategory
      parameters:
        - name: department_id
          in: query
          required: true
          schema: {type: integer}
        - name: category_id
          in: query
          required: true
          schema: {type: integer}
      responses:
        '200': {description: Success}

  /departments/order/recommended:
    get:
      tags:
        - Departments
      summary: Get recommended order for department
      operationId: getDepartmentRecommendedOrder
      parameters:
        - name: department_id
          in: query
          required: true
          schema: {type: integer}
      responses:
        '200': {description: Success}

  /department/lanes:
    get:
      tags:
        - Departments
      summary: List department lanes
      description: Retrieve a list of all department lanes
      operationId: listDepartmentLanes
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
        - $ref: '#/components/parameters/SearchParam'
      responses:
        '200':
          description: Department lanes retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/DepartmentLane'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      tags:
        - Departments
      summary: Create department lane
      description: Create a new department lane
      operationId: createDepartmentLane
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DepartmentLaneCreate'
      responses:
        '201':
          description: Department lane created successfully
        '400':
          $ref: '#/components/responses/BadRequest'
    put:
      tags:
        - Departments
      summary: Update department lane
      description: Update an existing department lane
      operationId: updateDepartmentLane
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DepartmentLaneUpdate'
      responses:
        '200':
          description: Department lane updated successfully
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'

  /guest/validation/customer-number:
    post:
      tags:
        - Users
      summary: Validate customer number
      description: Check if a customer number is valid and exists
      operationId: validateCustomerNumber
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - customer_number
              properties:
                customer_number:
                  type: integer
      responses:
        '200':
          description: Customer number validation successful
        '400':
          $ref: '#/components/responses/BadRequest'

  /guest/departments:
    get:
      tags:
        - Departments
      summary: List public departments
      description: Get list of departments without authentication
      operationId: listGuestDepartments
      security: []
      responses:
        '200':
          description: Departments retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Department'

  /department/selfserve/questions:
    get:
      tags:
        - Self-Serve
      summary: List self-serve questions
      description: Retrieve a list of self-serve questions for a department, lane, or product.
      operationId: listSelfserveQuestions
      parameters:
        - name: id
          in: query
          description: Filter by question ID
          schema:
            type: integer
        - name: department
          in: query
          description: Filter by department ID
          schema:
            type: integer
        - name: lane
          in: query
          description: Filter by lane ID
          schema:
            type: integer
        - name: product
          in: query
          description: Filter by product ID
          schema:
            type: integer
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
        - $ref: '#/components/parameters/SearchParam'
        - $ref: '#/components/parameters/FiltersParam'
      responses:
        '200':
          description: Successfully retrieved questions
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/DepartmentSelfserveQuestion'
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'

    post:
      tags:
        - Self-Serve
      summary: Add self-serve question
      description: Add a new self-serve question.
      operationId: addSelfserveQuestion
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - department
                - lane
                - product
                - question
                - description
              properties:
                department:
                  type: integer
                lane:
                  type: integer
                product:
                  type: integer
                question:
                  type: string
                description:
                  type: string
                question_condition:
                  type: integer
                  nullable: true
                order_priority:
                  type: integer
                  default: 0
      responses:
        '200':
          description: Successfully added question
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DepartmentSelfserveQuestion'
        '400':
          $ref: '#/components/responses/BadRequest'
        '500':
          $ref: '#/components/responses/InternalServerError'

    put:
      tags:
        - Self-Serve
      summary: Update self-serve question
      description: Update an existing self-serve question.
      operationId: updateSelfserveQuestion
      parameters:
        - name: id
          in: query
          required: true
          description: Question ID
          schema:
            type: integer
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                department:
                  type: integer
                lane:
                  type: integer
                product:
                  type: integer
                question:
                  type: string
                description:
                  type: string
                question_condition:
                  type: integer
                  nullable: true
                order_priority:
                  type: integer
      responses:
        '200':
          description: Successfully updated question
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DepartmentSelfserveQuestion'
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'

    delete:
      tags:
        - Self-Serve
      summary: Delete self-serve question
      description: Delete a self-serve question by ID.
      operationId: deleteSelfserveQuestion
      parameters:
        - name: id
          in: query
          required: true
          description: Question ID
          schema:
            type: integer
      responses:
        '200':
          description: Successfully deleted question
          content:
            application/json:
              schema:
                type: string
                example: Question deleted
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'

  /department/selfserve/conditions:
    get:
      tags:
        - Self-Serve
      summary: List self-serve conditions
      description: Retrieve a list of self-serve conditions for a department, lane, or product.
      operationId: listSelfserveConditions
      parameters:
        - name: id
          in: query
          description: Filter by condition ID
          schema:
            type: integer
        - name: department
          in: query
          description: Filter by department ID
          schema:
            type: integer
        - name: lane
          in: query
          description: Filter by lane ID
          schema:
            type: integer
        - name: product
          in: query
          description: Filter by product ID
          schema:
            type: integer
        - name: condition_id
          in: query
          description: Filter by condition ID
          schema:
            type: integer
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
        - $ref: '#/components/parameters/SearchParam'
        - $ref: '#/components/parameters/FiltersParam'
      responses:
        '200':
          description: Successfully retrieved conditions
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/DepartmentSelfserveCondition'
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'

    post:
      tags:
        - Self-Serve
      summary: Add self-serve condition
      description: Add a new self-serve condition.
      operationId: addSelfserveCondition
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - department
                - lane
                - product
                - name
                - description
              properties:
                department:
                  type: integer
                lane:
                  type: integer
                product:
                  type: integer
                condition_id:
                  type: integer
                  nullable: true
                name:
                  type: string
                description:
                  type: string
      responses:
        '200':
          description: Successfully added condition
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DepartmentSelfserveCondition'
        '400':
          $ref: '#/components/responses/BadRequest'
        '500':
          $ref: '#/components/responses/InternalServerError'

    put:
      tags:
        - Self-Serve
      summary: Update self-serve condition
      description: Update an existing self-serve condition.
      operationId: updateSelfserveCondition
      parameters:
        - name: id
          in: query
          required: true
          description: Condition ID
          schema:
            type: integer
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                department:
                  type: integer
                lane:
                  type: integer
                product:
                  type: integer
                condition_id:
                  type: integer
                  nullable: true
                name:
                  type: string
                description:
                  type: string
      responses:
        '200':
          description: Successfully updated condition
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DepartmentSelfserveCondition'
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'

    delete:
      tags:
        - Self-Serve
      summary: Delete self-serve condition
      description: Delete a self-serve condition.
      operationId: deleteSelfserveCondition
      parameters:
        - name: id
          in: query
          required: true
          description: Condition ID
          schema:
            type: integer
      responses:
        '200':
          description: Successfully deleted condition
          content:
            application/json:
              schema:
                type: string
                example: Condition deleted
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'

  /department/selfserve/condition/rules:
    get:
      tags:
        - Self-Serve
      summary: List self-serve condition rules
      description: Retrieve a list of self-serve condition rules.
      operationId: listSelfserveConditionRules
      parameters:
        - name: id
          in: query
          description: Filter by rule ID
          schema:
            type: integer
        - name: condition_id
          in: query
          description: Filter by condition ID
          schema:
            type: integer
        - name: type
          in: query
          description: Filter by rule type
          schema:
            type: string
        - name: object_type
          in: query
          description: Filter by object type
          schema:
            type: string
        - name: object_id
          in: query
          description: Filter by object ID
          schema:
            type: integer
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
        - $ref: '#/components/parameters/SearchParam'
        - $ref: '#/components/parameters/FiltersParam'
      responses:
        '200':
          description: Successfully retrieved condition rules
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/DepartmentSelfserveConditionRule'
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'

    post:
      tags:
        - Self-Serve
      summary: Add self-serve condition rule
      description: Add a new self-serve condition rule.
      operationId: addSelfserveConditionRule
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - condition_id
                - type
                - object_type
                - object_id
                - name
                - description
              properties:
                condition_id:
                  type: integer
                type:
                  type: string
                object_type:
                  type: string
                object_id:
                  type: integer
                name:
                  type: string
                description:
                  type: string
      responses:
        '200':
          description: Successfully added condition rule
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DepartmentSelfserveConditionRule'
        '400':
          $ref: '#/components/responses/BadRequest'
        '500':
          $ref: '#/components/responses/InternalServerError'

    put:
      tags:
        - Self-Serve
      summary: Update self-serve condition rule
      description: Update an existing self-serve condition rule.
      operationId: updateSelfserveConditionRule
      parameters:
        - name: id
          in: query
          required: true
          description: Rule ID
          schema:
            type: integer
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                condition_id:
                  type: integer
                type:
                  type: string
                object_type:
                  type: string
                object_id:
                  type: integer
                name:
                  type: string
                description:
                  type: string
      responses:
        '200':
          description: Successfully updated condition rule
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DepartmentSelfserveConditionRule'
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'

    delete:
      tags:
        - Self-Serve
      summary: Delete self-serve condition rule
      description: Delete a self-serve condition rule.
      operationId: deleteSelfserveConditionRule
      parameters:
        - name: id
          in: query
          required: true
          description: Rule ID
          schema:
            type: integer
      responses:
        '200':
          description: Successfully deleted condition rule
          content:
            application/json:
              schema:
                type: string
                example: Rule deleted
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'

  /department/selfserve/tasks:
    get:
      tags:
        - Self-Serve
      summary: List self-serve tasks
      description: Retrieve a list of self-serve tasks for a department, lane, product, or question.
      operationId: listSelfserveTasks
      parameters:
        - name: id
          in: query
          description: Filter by task ID
          schema:
            type: integer
        - name: department
          in: query
          description: Filter by department ID
          schema:
            type: integer
        - name: lane
          in: query
          description: Filter by lane ID
          schema:
            type: integer
        - name: product
          in: query
          description: Filter by product ID
          schema:
            type: integer
        - name: question
          in: query
          description: Filter by question ID
          schema:
            type: integer
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
        - $ref: '#/components/parameters/SearchParam'
        - $ref: '#/components/parameters/FiltersParam'
      responses:
        '200':
          description: Successfully retrieved tasks
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/DepartmentSelfserveTask'
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'

    post:
      tags:
        - Self-Serve
      summary: Add self-serve task
      description: Add a new self-serve task.
      operationId: addSelfserveTask
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - department
                - lane
                - product
                - task
                - description
              properties:
                department:
                  type: integer
                lane:
                  type: integer
                product:
                  type: integer
                question:
                  type: integer
                  nullable: true
                task:
                  type: string
                description:
                  type: string
                order_priority:
                  type: integer
                  default: 0
      responses:
        '200':
          description: Successfully added task
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DepartmentSelfserveTask'
        '400':
          $ref: '#/components/responses/BadRequest'
        '500':
          $ref: '#/components/responses/InternalServerError'

    put:
      tags:
        - Self-Serve
      summary: Update self-serve task
      description: Update an existing self-serve task.
      operationId: updateSelfserveTask
      parameters:
        - name: id
          in: query
          required: true
          description: Task ID
          schema:
            type: integer
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                department:
                  type: integer
                lane:
                  type: integer
                product:
                  type: integer
                question:
                  type: integer
                  nullable: true
                task:
                  type: string
                description:
                  type: string
                order_priority:
                  type: integer
      responses:
        '200':
          description: Successfully updated task
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DepartmentSelfserveTask'
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'

    delete:
      tags:
        - Self-Serve
      summary: Delete self-serve task
      description: Delete a self-serve task by ID.
      operationId: deleteSelfserveTask
      parameters:
        - name: id
          in: query
          required: true
          description: Task ID
          schema:
            type: integer
      responses:
        '200':
          description: Successfully deleted task
          content:
            application/json:
              schema:
                type: string
                example: Task deleted
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'

  /department/selfserve/tasks/attachments:
    get:
      tags:
        - Self-Serve
      summary: List task attachments
      description: Retrieve a list of attachments for a specific self-serve task.
      operationId: listSelfserveTaskAttachments
      parameters:
        - name: id
          in: query
          required: true
          description: Task ID
          schema:
            type: integer
      responses:
        '200':
          description: Successfully retrieved task attachments
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'

    delete:
      tags:
        - Self-Serve
      summary: Delete task attachment
      description: Remove an attachment from a specific self-serve task.
      operationId: deleteSelfserveTaskAttachment
      parameters:
        - name: task_id
          in: query
          required: true
          description: Task ID
          schema:
            type: integer
        - name: attachment_id
          in: query
          required: true
          description: Attachment ID
          schema:
            type: integer
      responses:
        '200':
          description: Attachment deleted successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: Attachment deleted successfully
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'

  /department/selfserve/tasks/attachments/upload:
    post:
      tags:
        - Self-Serve
      summary: Upload task attachment
      description: Upload a new attachment to a specific self-serve task using base64 encoding.
      operationId: uploadSelfserveTaskAttachment
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - task_id
                - base64_file
                - file_name
              properties:
                task_id:
                  type: integer
                base64_file:
                  type: string
                  description: Base64 encoded file content
                file_name:
                  type: string
                  description: Name of the file including extension
      responses:
        '200':
          description: Attachment uploaded successfully
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /department/selfserve/tasks/attachments/download:
    get:
      tags:
        - Self-Serve
      summary: Download task attachment
      description: Generate a download link for a specific self-serve task attachment.
      operationId: downloadSelfserveTaskAttachment
      parameters:
        - name: task_id
          in: query
          required: true
          description: Task ID
          schema:
            type: integer
        - name: attachment_id
          in: query
          required: true
          description: Attachment ID
          schema:
            type: integer
      responses:
        '200':
          description: Successfully generated download link
          content:
            application/json:
              schema:
                type: object
                properties:
                  download_link:
                    type: string
                    format: uri
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'

  # Products Endpoints
  /products:
    get:
      tags:
        - Products
      summary: List products
      description: Retrieve a list of products with optional filters for customer pricing and department
      operationId: listProducts
      parameters:
        - name: customer_id
          in: query
          schema:
            type: integer
          description: Customer ID for custom pricing
        - name: department_id
          in: query
          schema:
            type: integer
          description: Department ID for department-specific pricing
        - name: category
          in: query
          schema:
            type: integer
          description: Filter by category ID
        - name: id
          in: query
          schema:
            type: integer
          description: Get specific product by ID
        - name: final_price
          in: query
          schema:
            type: boolean
          description: Whether to return final prices including discounts
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
      responses:
        '200':
          description: Products retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Product'
    post:
      tags:
        - Products
      summary: Create product
      description: Create a new product
      operationId: createProduct
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ProductCreate'
      responses:
        '201':
          description: Product created successfully
        '400':
          $ref: '#/components/responses/BadRequest'
    put:
      tags:
        - Products
      summary: Update product
      description: Update an existing product
      operationId: updateProduct
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ProductUpdate'
      responses:
        '200':
          description: Product updated successfully
        '400':
          $ref: '#/components/responses/BadRequest'

  # Categories Endpoints
  /categories:
    get:
      tags:
        - Categories
      summary: List categories
      description: Retrieve a list of product categories
      operationId: listCategories
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
      responses:
        '200':
          description: Categories retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Category'
    post:
      tags:
        - Categories
      summary: Create category
      description: Create a new product category
      operationId: createCategory
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CategoryCreate'
      responses:
        '201':
          description: Category created successfully
    put:
      tags:
        - Categories
      summary: Update category
      description: Update an existing category
      operationId: updateCategory
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CategoryUpdate'
      responses:
        '200':
          description: Category updated successfully

  # Bookings Endpoints
  /bookings:
    get:
      tags:
        - Bookings
      summary: List bookings
      description: Retrieve a list of bookings
      operationId: listBookings
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
      responses:
        '200':
          description: Bookings retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Booking'
    put:
      tags:
        - Bookings
      summary: Update booking
      description: Update an existing booking
      operationId: updateBooking
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BookingUpdate'
      responses:
        '200':
          description: Booking updated successfully

  /user/bookings:
    get:
      tags:
        - Bookings
      summary: Get user bookings
      description: Retrieve bookings for the authenticated user
      operationId: getUserBookings
      responses:
        '200':
          description: User bookings retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Booking'

  /order-bookings:
    get:
      tags:
        - Bookings
      summary: List order bookings
      operationId: listOrderBookings
      parameters:
        - name: id
          in: query
          required: false
          schema: {type: integer}
      responses:
        '200':
          description: Success
    post:
      tags:
        - Bookings
      summary: Create order booking
      operationId: createOrderBooking
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [department, reg_1, datetime, items]
              properties:
                customer_number: {type: integer}
                department: {type: integer}
                reg_1: {type: string}
                reg_2: {type: string}
                reg_3: {type: string}
                datetime: {type: string, format: date-time}
                note: {type: string}
                reference: {type: string}
                po: {type: string}
                pickup: {type: boolean}
                items:
                  type: array
                  items:
                    type: object
                    required: [id, quantity]
                    properties:
                      id: {type: integer}
                      quantity: {type: integer}
      responses:
        '200':
          description: Success
    put:
      tags:
        - Bookings
      summary: Update order booking
      operationId: updateOrderBooking
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [id]
              properties:
                id: {type: integer}
                customer_number: {type: integer}
                department: {type: integer}
                reg_1: {type: string}
                reg_2: {type: string}
                reg_3: {type: string}
                datetime: {type: string, format: date-time}
                note: {type: string}
                reference: {type: string}
                po: {type: string}
                pickup: {type: boolean}
                order_id: {type: integer}
                items:
                  type: array
                  items:
                    type: object
                    required: [id, quantity]
                    properties:
                      id: {type: integer}
                      quantity: {type: integer}
      responses:
        '200':
          description: Success
    delete:
      tags:
        - Bookings
      summary: Delete order booking
      operationId: deleteOrderBooking
      parameters:
        - name: id
          in: query
          required: true
          schema: {type: integer}
      responses:
        '200':
          description: Success

  /order-bookings/complete:
    post:
      tags:
        - Bookings
      summary: Complete order booking
      operationId: completeOrderBooking
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [id]
              properties:
                id: {type: integer}
                safety_seal: {type: integer}
      responses:
        '200':
          description: Success

  /admin/bookings/sync:
    post:
      tags:
        - Bookings
      summary: Sync booking from external system
      operationId: syncBooking
      responses:
        '200':
          description: Success

  /admin/bookings/department/count:
    get:
      tags:
        - Bookings
      summary: Get department unfulfilled bookings count
      operationId: getDepartmentBookingCount
      parameters:
        - name: department_id
          in: query
          required: true
          schema: {type: integer}
      responses:
        '200':
          description: Success

  /user/bookings/washcertificate/download:
    post:
      tags:
        - Bookings
      summary: Get download link for own wash certificate
      operationId: downloadOwnWashCertificate
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [id]
              properties:
                id: {type: integer}
      responses:
        '200':
          description: Success

  /bookings/download_pdf:
    get:
      tags:
        - Bookings
      summary: Download booking PDF
      operationId: downloadBookingPdf
      parameters:
        - name: id
          in: query
          required: true
          schema: {type: integer}
      responses:
        '200':
          description: Success

  /admin/bookings/delete:
    post:
      tags:
        - Bookings
      summary: Delete booking (admin)
      operationId: adminDeleteBooking
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [id]
              properties:
                id: {type: integer}
      responses:
        '200':
          description: Success

  /superuser/bookings/sync/all:
    post:
      tags:
        - Bookings
      summary: Sync all bookings from external system
      operationId: syncAllBookings
      responses:
        '200':
          description: Success

  /admin/bookings/completeWashWithoutWashCertificate:
    post:
      tags:
        - Bookings
      summary: Complete wash without wash certificate
      operationId: completeWashWithoutWashCertificate
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [id]
              properties:
                id: {type: integer}
      responses:
        '200':
          description: Success

  /user/bookings/delete:
    post:
      tags:
        - Bookings
      summary: Delete own booking
      operationId: deleteOwnBooking
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [id]
              properties:
                id: {type: integer}
      responses:
        '200':
          description: Success

  # Invoices Endpoints
  /invoices/draft:
    get:
      tags:
        - Invoices
      summary: List draft invoices
      description: Retrieve a list of draft invoices
      operationId: listDraftInvoices
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
      responses:
        '200':
          description: Draft invoices retrieved successfully

  /invoices/draft/close:
    post:
      tags:
        - Invoices
      summary: Close draft invoice
      description: Close a draft invoice
      operationId: closeDraftInvoice
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                id:
                  type: integer
      responses:
        '200':
          description: Draft invoice closed successfully

  /invoices/pdf:
    get:
      tags:
        - Invoices
      summary: Get invoice PDF
      description: Download an invoice as PDF
      operationId: getInvoicePdf
      parameters:
        - name: id
          in: query
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: PDF retrieved successfully
          content:
            application/pdf:
              schema:
                type: string
                format: binary

  /user/invoices:
    get:
      tags:
        - Invoices
      summary: Get user invoices
      description: Retrieve invoices for the authenticated user
      operationId: getUserInvoices
      responses:
        '200':
          description: User invoices retrieved successfully

  /collected-invoices:
    get:
      tags:
        - Invoices
      summary: List collected invoices
      description: Get list of collected invoices
      operationId: listCollectedInvoices
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
      responses:
        '200':
          description: Collected invoices retrieved successfully
    post:
      tags:
        - Invoices
      summary: Create collected invoice
      description: Create a new collected invoice
      operationId: createCollectedInvoice
      responses:
        '201':
          description: Collected invoice created successfully
    put:
      tags:
        - Invoices
      summary: Update collected invoice
      description: Update a collected invoice
      operationId: updateCollectedInvoice
      responses:
        '200':
          description: Collected invoice updated successfully

  /collected-invoices/ready-to-invoice:
    get:
      tags:
        - Invoices
      summary: Get invoices ready to process
      description: Get collected invoices that are ready to be processed
      operationId: getReadyToInvoice
      responses:
        '200':
          description: Ready invoices retrieved successfully

  /superuser/invoicing/period:
    get:
      tags:
        - Invoices
      summary: Get invoicing periods
      description: Retrieve invoicing periods for superusers
      operationId: getInvoicingPeriods
      parameters:
        - name: dateFrom
          in: query
          required: true
          schema: {type: string, format: date}
        - name: dateTo
          in: query
          required: true
          schema: {type: string, format: date}
      responses:
        '200':
          description: Invoicing periods retrieved successfully

  /superuser/invoicing/period/distribution/fixed-pricing:
    get:
      tags:
        - Invoices
      summary: Get fixed pricing distribution
      description: Get invoicing distribution for fixed pricing items
      operationId: getInvoicingFixedPricingDistribution
      parameters:
        - name: dateFrom
          in: query
          required: true
          schema: {type: string, format: date}
        - name: dateTo
          in: query
          required: true
          schema: {type: string, format: date}
      responses:
        '200':
          description: Fixed pricing distribution retrieved successfully

  /superuser/invoicing/period/distribution/wash-subscriptions:
    get:
      tags:
        - Invoices
      summary: Get wash subscriptions distribution
      description: Get invoicing distribution for wash subscriptions
      operationId: getInvoicingWashSubscriptionsDistribution
      parameters:
        - name: dateFrom
          in: query
          required: true
          schema: {type: string, format: date}
        - name: dateTo
          in: query
          required: true
          schema: {type: string, format: date}
      responses:
        '200':
          description: Wash subscriptions distribution retrieved successfully

  # Vehicles Endpoints
  /vehicles:
    get:
      tags:
        - Vehicles
      summary: List vehicles
      description: Get list of vehicles
      operationId: listVehicles
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
        - name: id
          in: query
          schema: {type: integer}
        - name: reg
          in: query
          schema: {type: string}
        - name: customer_id
          in: query
          schema: {type: integer}
      responses:
        '200':
          description: Vehicles retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Vehicle'
    post:
      tags:
        - Vehicles
      summary: Add vehicle
      operationId: addVehicle
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [reg, customer_id]
              properties:
                reg: {type: string}
                customer_id: {type: integer}
                type: {type: integer}
                reference: {type: string}
      responses:
        '200': {description: Success}
    put:
      tags:
        - Vehicles
      summary: Edit vehicle
      operationId: editVehicle
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [id]
              properties:
                id: {type: integer}
                reg: {type: string}
                customer_id: {type: integer}
                type: {type: integer}
                reference: {type: string}
      responses:
        '200': {description: Success}
    delete:
      tags:
        - Vehicles
      summary: Delete vehicle
      operationId: deleteVehicle
      parameters:
        - name: id
          in: query
          required: true
          schema: {type: integer}
      responses:
        '200': {description: Success}

  /vehicles/addons/available:
    get:
      tags:
        - Vehicles
      summary: Get available vehicle addons
      description: Get list of available addons for a vehicle
      operationId: getAvailableVehicleAddons
      parameters:
        - name: vehicle_id
          in: query
          schema:
            type: integer
      responses:
        '200':
          description: Available addons retrieved successfully

  /vehicles/addons/toggle:
    post:
      tags:
        - Vehicles
      summary: Toggle vehicle addon
      description: Enable or disable a vehicle addon
      operationId: toggleVehicleAddon
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                vehicle_id:
                  type: integer
                addon_id:
                  type: integer
                enabled:
                  type: boolean
      responses:
        '200':
          description: Vehicle addon toggled successfully

  /department/vehicles/unknown-customer:
    get:
      tags:
        - Vehicles
      summary: Get unknown customer vehicles in department
      operationId: getUnknownCustomerVehicles
      responses:
        '200': {description: Success}

  /department/vehicle/customer-suggestions:
    get:
      tags:
        - Vehicles
      summary: Get vehicle customer suggestions
      operationId: getVehicleCustomerSuggestions
      parameters:
        - name: reg
          in: query
          required: true
          schema: {type: string}
      responses:
        '200': {description: Success}

  /vehicles/set-auto-start-on-lpr:
    post:
      tags:
        - Vehicles
      summary: Set auto start on LPR
      operationId: setVehicleAutoStartOnLpr
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [reg, auto_start_on_lpr]
              properties:
                reg: {type: string}
                auto_start_on_lpr: {type: boolean}
      responses:
        '200': {description: Success}

  /vehicles/set-vehicle-type-id:
    post:
      tags:
        - Vehicles
      summary: Set vehicle type ID
      operationId: setVehicleTypeId
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [reg, vehicle_type_id]
              properties:
                reg: {type: string}
                vehicle_type_id: {type: integer}
      responses:
        '200': {description: Success}

  /superuser/users-with-vehicle-subscriptions:
    get:
      tags:
        - Vehicles
      summary: Get users with vehicle subscriptions
      operationId: getUsersWithVehicleSubscriptions
      responses:
        '200': {description: Success}

  /vehicles/status:
    get:
      tags:
        - Vehicles
      summary: Get vehicle status
      operationId: getVehicleStatus
      parameters:
        - name: reg
          in: query
          required: true
          schema: {type: string}
      responses:
        '200': {description: Success}

  /vehicles/search:
    get:
      tags:
        - Vehicles
      summary: Search vehicles
      operationId: searchVehicles
      parameters:
        - name: search
          in: query
          required: true
          schema: {type: string}
      responses:
        '200': {description: Success}

  # Notifications Endpoints
  /notifications:
    get:
      tags:
        - Notifications
      summary: List notifications
      description: Get list of notifications
      operationId: listNotifications
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
      responses:
        '200':
          description: Notifications retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Notification'
    post:
      tags:
        - Notifications
      summary: Create notification
      description: Create a new notification
      operationId: createNotification
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/NotificationCreate'
      responses:
        '201':
          description: Notification created successfully
    delete:
      tags:
        - Notifications
      summary: Delete notification
      description: Delete a notification
      operationId: deleteNotification
      parameters:
        - name: id
          in: query
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Notification deleted successfully

  # Statistics Endpoints
  /statistics/bookings/new:
    get:
      tags:
        - Statistics
      summary: Get new bookings statistics
      description: Get statistics for new bookings
      operationId: getNewBookingsStats
      responses:
        '200':
          description: New bookings statistics retrieved successfully

  /orders/module/stripe/payment_intent:
    get:
      tags:
        - Orders
      summary: Get Stripe payment intent
      operationId: getStripePaymentIntent
      parameters:
        - name: id
          in: query
          required: true
          schema: {type: integer}
      responses:
        '200':
          description: Success
    post:
      tags:
        - Orders
      summary: Create Stripe payment intent
      operationId: createStripePaymentIntent
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [id, reader]
              properties:
                id: {type: integer}
                reader: {type: string}
                tax_percentage: {type: integer}
      responses:
        '200':
          description: Success
    delete:
      tags:
        - Orders
      summary: Delete Stripe payment intent
      operationId: deleteStripePaymentIntent
      parameters:
        - name: id
          in: query
          required: true
          schema: {type: integer}
      responses:
        '200':
          description: Success

  /orders/module/stripe/payment_intent/capture:
    post:
      tags:
        - Orders
      summary: Capture Stripe payment intent
      operationId: captureStripePaymentIntent
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [id]
              properties:
                id: {type: integer}
      responses:
        '200':
          description: Success

  /orders/module/stripe/debug/simulate_payment:
    post:
      tags:
        - Orders
      summary: Simulate Stripe payment
      operationId: simulateStripePayment
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [id]
              properties:
                id: {type: integer}
      responses:
        '200':
          description: Success

  /statistics/orders/new:
    get:
      tags:
        - Statistics
      summary: Get new orders statistics
      description: Get statistics for new orders
      operationId: getNewOrdersStats
      responses:
        '200':
          description: New orders statistics retrieved successfully

  /statistics/income/today:
    get:
      tags:
        - Statistics
      summary: Get today's income
      description: Get income statistics for today
      operationId: getTodayIncome
      responses:
        '200':
          description: Today's income statistics retrieved successfully

  /statistics/income/yesterday:
    get:
      tags:
        - Statistics
      summary: Get yesterday's income
      description: Get income statistics for yesterday
      operationId: getYesterdayIncome
      responses:
        '200':
          description: Yesterday's income statistics retrieved successfully

  /statistics/income/this-month:
    get:
      tags:
        - Statistics
      summary: Get this month's income
      description: Get income statistics for the current month
      operationId: getThisMonthIncome
      responses:
        '200':
          description: This month's income statistics retrieved successfully

  /statistics/income/last-month:
    get:
      tags:
        - Statistics
      summary: Get last month's income
      description: Get income statistics for the previous month
      operationId: getLastMonthIncome
      responses:
        '200':
          description: Last month's income statistics retrieved successfully

  /statistics/income/this-year:
    get:
      tags:
        - Statistics
      summary: Get this year's income
      description: Get income statistics for the current year
      operationId: getThisYearIncome
      responses:
        '200':
          description: This year's income statistics retrieved successfully

  /statistics/income/departments:
    get:
      tags:
        - Statistics
      summary: Get total income today by departments
      operationId: getTotalIncomeTodayByDepartments
      responses:
        '200': {description: Success}

  /statistics/economic/totals:
    get:
      tags:
        - Statistics
      summary: Get total economic statistics
      operationId: getEconomicTotals
      responses:
        '200': {description: Success}

  /statistics/economic/totals/department_sent_invoice_totals:
    get:
      tags:
        - Statistics
      summary: Get department sent invoice totals
      operationId: getDepartmentSentInvoiceTotals
      responses:
        '200': {description: Success}

  /statistics/economic/totals/department_draft_invoice_totals:
    get:
      tags:
        - Statistics
      summary: Get department draft invoice totals
      operationId: getDepartmentDraftInvoiceTotals
      responses:
        '200': {description: Success}

  # Worker Endpoints
  /worker/version:
    get:
      tags:
        - Worker
      summary: Get worker version
      description: Get the current version of the system worker
      operationId: getWorkerVersion
      responses:
        '200':
          description: Worker version retrieved successfully

  /worker/update-version:
    get:
      tags:
        - Worker
      summary: Update worker version
      description: Set the target version for the worker update
      operationId: updateWorkerVersion
      parameters:
        - name: version
          in: query
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Version update target set successfully

  /worker/status:
    get:
      tags:
        - Worker
      summary: Get worker status
      description: Get detailed status of the system worker
      operationId: getWorkerStatus
      responses:
        '200':
          description: Worker status retrieved successfully

  /worker/debug:
    get:
      tags:
        - Worker
      summary: Debug worker
      description: Execute debug commands on the worker (often restricted)
      operationId: debugWorker
      responses:
        '200':
          description: Debug information retrieved successfully
        '403':
          $ref: '#/components/responses/Forbidden'

  /worker/debug/on:
    get:
      tags:
        - Worker
      summary: Enable worker debug
      operationId: enableWorkerDebug
      responses:
        '200':
          description: Worker debug enabled
        '403':
          $ref: '#/components/responses/Forbidden'

  /worker/debug/off:
    get:
      tags:
        - Worker
      summary: Disable worker debug
      operationId: disableWorkerDebug
      responses:
        '200':
          description: Worker debug disabled
        '403':
          $ref: '#/components/responses/Forbidden'

  /worker/licenseplates:
    get:
      tags:
        - Worker
      summary: Get unique license plates
      description: Fetch all unique license plates from various database tables
      operationId: getWorkerLicensePlates
      responses:
        '200':
          description: License plates retrieved successfully
        '403':
          $ref: '#/components/responses/Forbidden'

  /economic/doesCustomerExist:
    get:
      tags:
        - Modules
      summary: Check if customer exists in e-conomic
      operationId: checkEconomicCustomerExists
      parameters:
        - name: cvr
          in: query
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Customer check completed
        '404':
          $ref: '#/components/responses/NotFound'

  /cvr/lookup:
    get:
      tags:
        - Modules
      summary: Lookup CVR information
      description: Get detailed information for a CVR number
      operationId: lookupCvr
      parameters:
        - name: cvr
          in: query
          required: true
          schema:
            type: string
      responses:
        '200':
          description: CVR information retrieved successfully

  /cvr/search:
    get:
      tags:
        - Modules
      summary: Search CVR
      description: Search for companies by name or CVR
      operationId: searchCvr
      parameters:
        - name: query
          in: query
          required: true
          schema:
            type: string
            minLength: 2
      responses:
        '200':
          description: Search results retrieved successfully

  # Plate Scans Endpoints
  /numberplatescans:
    get:
      tags:
        - Plate Scans
      summary: List plate scans
      description: Get a list of license plate scans
      operationId: listPlateScans
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
        - $ref: '#/components/parameters/SearchParam'
      responses:
        '200':
          description: Plate scans retrieved successfully
    post:
      tags:
        - Plate Scans
      summary: Record plate scan
      description: Record a new license plate scan
      operationId: recordPlateScan
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - plate
                - lane_id
              properties:
                plate:
                  type: string
                lane_id:
                  type: integer
      responses:
        '201':
          description: Plate scan recorded successfully

  /numberplatescans/department:
    post:
      tags:
        - Plate Scans
      summary: Record plate scan for department
      operationId: recordDepartmentPlateScan
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - plate
                - department_id
              properties:
                plate:
                  type: string
                department_id:
                  type: integer
      responses:
        '201':
          description: Plate scan recorded successfully

  /numberplatescans/post:
    get:
      tags:
        - Plate Scans
      summary: Get post-scan results
      operationId: getPlateScanPostResults
      responses:
        '200':
          description: Post-scan results retrieved successfully

  /numberplatescanners:
    get:
      tags:
        - Plate Scans
      summary: List plate scanners
      description: Get a list of all number plate scanners
      operationId: listPlateScanners
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
        - $ref: '#/components/parameters/SearchParam'
      responses:
        '200':
          description: Plate scanners retrieved successfully
    post:
      tags:
        - Plate Scans
      summary: Add plate scanner
      operationId: addPlateScanner
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [department_id, name, notes]
              properties:
                department_id: {type: integer}
                name: {type: string}
                notes: {type: string}
      responses:
        '201':
          description: Plate scanner added successfully
    put:
      tags:
        - Plate Scans
      summary: Update plate scanner
      operationId: updatePlateScanner
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [id, department_id, name, notes]
              properties:
                id: {type: integer}
                department_id: {type: integer}
                name: {type: string}
                notes: {type: string}
      responses:
        '200':
          description: Plate scanner updated successfully

  /department/numberplatescanners:
    get:
      tags:
        - Plate Scans
      summary: List department plate scanners
      operationId: listDepartmentPlateScanners
      parameters:
        - name: id
          in: query
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Department plate scanners retrieved successfully

  /relay/button/press/post:
    get:
      tags:
        - Plate Scans
      summary: Add button press
      operationId: addButtonPress
      parameters:
        - name: token
          in: query
          required: true
          schema: {type: string}
      responses:
        '201':
          description: Button press recorded

  # Module - e-conomic Endpoints
  /economic/customers/import:
    post:
      tags:
        - Modules
      summary: Import e-conomic customers
      description: Import customers from e-conomic
      operationId: importEconomicCustomers
      responses:
        '200':
          description: Customers imported successfully

  /economic/departments:
    get:
      tags:
        - Modules
      summary: Get e-conomic departments
      operationId: getEconomicDepartments
      responses:
        '200':
          description: Success

  /economic/products:
    get:
      tags:
        - Modules
      summary: Get e-conomic products
      operationId: getEconomicProducts
      responses:
        '200':
          description: Success

  /modules/economic/customer:
    get:
      tags:
        - Modules
      summary: Get e-conomic customer details
      operationId: getEconomicCustomer
      parameters:
        - name: customer_number
          in: query
          required: true
          schema: {type: integer}
      responses:
        '200':
          description: Success
    post:
      tags:
        - Modules
      summary: Create e-conomic customer
      operationId: createEconomicCustomer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [customer_number, cvr, email, phone, name]
              properties:
                customer_number: {type: integer}
                cvr: {type: integer}
                email: {type: string}
                phone: {type: integer}
                name: {type: string}
      responses:
        '200':
          description: Success

  /economic/layouts:
    get:
      tags:
        - Modules
      summary: Get e-conomic layouts
      description: Get available invoice layouts from e-conomic
      operationId: getEconomicLayouts
      responses:
        '200':
          description: Layouts retrieved successfully

  /economic/payment-terms:
    get:
      tags:
        - Modules
      summary: Get e-conomic payment terms
      description: Get available payment terms from e-conomic
      operationId: getEconomicPaymentTerms
      responses:
        '200':
          description: Payment terms retrieved successfully

  /economic/invoice/draft/export:
    post:
      tags:
        - Modules
      summary: Export draft invoice to e-conomic
      description: Export a draft invoice to e-conomic
      operationId: exportDraftInvoiceToEconomic
      responses:
        '200':
          description: Draft invoice exported successfully

  /economic/invoice/export:
    post:
      tags:
        - Modules
      summary: Export invoice to e-conomic
      description: Export a booked invoice to e-conomic
      operationId: exportInvoiceToEconomic
      responses:
        '200':
          description: Invoice exported successfully

  # Module - Stripe Endpoints
  /modules/stripe/customers:
    get:
      tags:
        - Modules
      summary: List Stripe customers
      description: Get list of Stripe customers
      operationId: listStripeCustomers
      responses:
        '200':
          description: Stripe customers retrieved successfully

  /modules/stripe/products:
    get:
      tags:
        - Modules
      summary: List Stripe products
      description: Get list of Stripe products
      operationId: listStripeProducts
      responses:
        '200':
          description: Stripe products retrieved successfully

  /modules/stripe/prices:
    get:
      tags:
        - Modules
      summary: List Stripe prices
      description: Get list of Stripe prices
      operationId: listStripePrices
      responses:
        '200':
          description: Stripe prices retrieved successfully

  /modules/stripe/invoice:
    post:
      tags:
        - Modules
      summary: Create Stripe invoice
      description: Create an invoice in Stripe
      operationId: createStripeInvoice
      responses:
        '201':
          description: Stripe invoice created successfully

  /modules/stripe/terminal/readers:
    get:
      tags:
        - Modules
      summary: List Stripe terminal readers
      operationId: listStripeTerminalReaders
      responses:
        '200':
          description: Success

  /modules/stripe/terminal/locations:
    get:
      tags:
        - Modules
      summary: List Stripe terminal locations
      operationId: listStripeTerminalLocations
      responses:
        '200':
          description: Success

  /modules/stripe/department/terminal/location:
    get:
      tags:
        - Modules
      summary: Get department terminal location
      operationId: getDepartmentTerminalLocation
      parameters:
        - name: id
          in: query
          required: true
          schema: {type: integer}
      responses:
        '200':
          description: Success
    post:
      tags:
        - Modules
      summary: Set department terminal location
      operationId: setDepartmentTerminalLocation
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [id, location]
              properties:
                id: {type: integer}
                location: {type: string}
      responses:
        '200':
          description: Success

  /modules/stripe/department/terminal/readers:
    get:
      tags:
        - Modules
      summary: Get department terminal readers
      operationId: getDepartmentTerminalReaders
      parameters:
        - name: id
          in: query
          required: true
          schema: {type: integer}
      responses:
        '200':
          description: Success

  # Module - Backup Endpoints
  /modules/backup/backups:
    get:
      tags:
        - Modules
      summary: List backup modules
      operationId: listBackupModules
      responses:
        '200':
          description: Success
    post:
      tags:
        - Modules
      summary: Create backup module
      operationId: createBackupModule
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, description]
              properties:
                name: {type: string}
                description: {type: string}
      responses:
        '200':
          description: Success

  # Module - XLVask Endpoints
  /modules/xlvask/usageLog:
    get:
      tags:
        - Modules
      summary: Get XLVask usage logs
      description: Retrieve usage logs from XLVask system
      operationId: getXlvaskUsageLogs
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
      responses:
        '200':
          description: Usage logs retrieved successfully

  /modules/xlvask/vehicles:
    get:
      tags:
        - Modules
      summary: List XLVask vehicles
      description: Get list of vehicles from XLVask
      operationId: listXlvaskVehicles
      responses:
        '200':
          description: XLVask vehicles retrieved successfully

  /modules/xlvask/customers:
    get:
      tags:
        - Modules
      summary: List XLVask customers
      description: Get list of customers from XLVask
      operationId: listXlvaskCustomers
      responses:
        '200':
          description: XLVask customers retrieved successfully

  /modules/action-logs:
    get:
      tags:
        - Modules
      summary: List module action logs
      description: Retrieve a paginated list of module action logs with searching and filtering
      operationId: listModuleActionLogs
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/LimitParam'
        - $ref: '#/components/parameters/SearchParam'
        - $ref: '#/components/parameters/FiltersParam'
      responses:
        '200':
          description: Module action logs retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ModuleActionLog'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  # Module - Self-Serve Endpoints
  /modules/self-serve/lane/status:
    get:
      tags:
        - Modules
      summary: Get self-serve lane status
      description: Retrieve the current status of a self-serve lane
      operationId: getSelfServeLaneStatus
      parameters:
        - name: lane_id
          in: query
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Lane status retrieved successfully

  /modules/self-serve/lane/command:
    post:
      tags:
        - Modules
      summary: Send self-serve lane command
      description: Send a command (e.g., start, stop, reset) to a self-serve lane
      operationId: sendSelfServeLaneCommand
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - lane_id
                - command
              properties:
                lane_id:
                  type: integer
                command:
                  type: string
                  enum: [start, stop, reset]
      responses:
        '200':
          description: Command sent successfully

  # Module - Other Integration Endpoints
  /modules/motorapi/lookup:
    get:
      tags:
        - Modules
      summary: Lookup vehicle via MotorAPI
      description: Look up vehicle information using license plate
      operationId: motorApiLookup
      parameters:
        - name: plate
          in: query
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Vehicle information retrieved successfully

  /modules/virkdata/search:
    get:
      tags:
        - Modules
      summary: Search VirkData
      description: Search for company information in VirkData
      operationId: virkdataSearch
      parameters:
        - name: search
          in: query
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Company information retrieved successfully

  /modules/fxratesapi/rate:
    get:
      tags:
        - Modules
      summary: Get exchange rate
      description: Get current exchange rate
      operationId: getExchangeRate
      parameters:
        - name: from
          in: query
          required: true
          schema:
            type: string
        - name: to
          in: query
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Exchange rate retrieved successfully

  /modules/fxratesapi/rates:
    get:
      tags:
        - Modules
      summary: Get all exchange rates
      description: Get all available exchange rates
      operationId: getAllExchangeRates
      responses:
        '200':
          description: Exchange rates retrieved successfully

  /modules/entra/users:
    get:
      tags:
        - Modules
      summary: List Microsoft Entra users
      description: Get list of users from Microsoft Entra (Azure AD)
      operationId: listEntraUsers
      responses:
        '200':
          description: Entra users retrieved successfully

  # Attachments Endpoints
  /attachments/upload:
    post:
      tags:
        - Attachments
      summary: Upload attachment
      description: Upload a file attachment
      operationId: uploadAttachment
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                file:
                  type: string
                  format: binary
      responses:
        '201':
          description: Attachment uploaded successfully
        '400':
          $ref: '#/components/responses/BadRequest'

  /orders/attachments:
    get:
      tags:
        - Attachments
      summary: List order attachments
      description: Get attachments for an order
      operationId: listOrderAttachments
      parameters:
        - name: order_id
          in: query
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Order attachments retrieved successfully

  /orders/attachments/upload:
    post:
      tags:
        - Attachments
      summary: Upload order attachment
      description: Upload an attachment to an order
      operationId: uploadOrderAttachment
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                order_id:
                  type: integer
                file:
                  type: string
                  format: binary
      responses:
        '201':
          description: Order attachment uploaded successfully

  /orders/attachments/download:
    get:
      tags:
        - Attachments
      summary: Download order attachment
      description: Download a specific order attachment
      operationId: downloadOrderAttachment
      parameters:
        - name: id
          in: query
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Attachment downloaded successfully
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary

  # Forms Endpoints
  /form:
    get:
      tags:
        - Forms
      summary: Get form
      description: Retrieve a form definition
      operationId: getForm
      parameters:
        - name: id
          in: query
          schema:
            type: integer
      responses:
        '200':
          description: Form retrieved successfully
    post:
      tags:
        - Forms
      summary: Submit form
      description: Submit a form
      operationId: submitForm
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                form_id:
                  type: integer
                data:
                  type: object
      responses:
        '201':
          description: Form submitted successfully

  # Permissions Endpoints
  /permissions:
    get:
      tags:
        - Users
      summary: List permissions
      description: Get list of all available permissions
      operationId: listPermissions
      responses:
        '200':
          description: Permissions retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Permission'

  # Customer Management Endpoints
  /customer/attributes:
    get:
      tags:
        - Users
      summary: Get customer attributes
      description: Get custom attributes for a customer
      operationId: getCustomerAttributes
      parameters:
        - name: customer_id
          in: query
          schema:
            type: integer
      responses:
        '200':
          description: Customer attributes retrieved successfully
    post:
      tags:
        - Users
      summary: Add customer attribute
      description: Add a custom attribute to a customer
      operationId: addCustomerAttribute
      responses:
        '201':
          description: Customer attribute added successfully
    delete:
      tags:
        - Users
      summary: Delete customer attribute
      description: Remove a custom attribute from a customer
      operationId: deleteCustomerAttribute
      responses:
        '200':
          description: Customer attribute deleted successfully

  /customer/notes:
    get:
      tags:
        - Users
      summary: Get customer notes
      description: Get notes for a customer
      operationId: getCustomerNotes
      parameters:
        - name: customer_id
          in: query
          schema:
            type: integer
      responses:
        '200':
          description: Customer notes retrieved successfully
    post:
      tags:
        - Users
      summary: Add customer note
      description: Add a note to a customer
      operationId: addCustomerNote
      responses:
        '201':
          description: Customer note added successfully
    delete:
      tags:
        - Users
      summary: Delete customer note
      description: Remove a note from a customer
      operationId: deleteCustomerNote
      responses:
        '200':
          description: Customer note deleted successfully

  /customers/search:
    post:
      tags:
        - Users
      summary: Search customers
      description: Search for customers using various criteria
      operationId: searchCustomers
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                query:
                  type: string
      responses:
        '200':
          description: Customers found successfully

  # Configuration Endpoints
  /economic/config:
    get:
      tags: [Config]
      summary: Get e-conomic config
      operationId: getEconomicConfig
      responses:
        '200': {description: Success}
    post:
      tags: [Config]
      summary: Update e-conomic config
      operationId: updateEconomicConfig
      responses:
        '200': {description: Success}

  /reCAPTCHA/config:
    get:
      tags: [Config]
      summary: Get reCAPTCHA config
      operationId: getRecaptchaConfig
      responses:
        '200': {description: Success}
    post:
      tags: [Config]
      summary: Update reCAPTCHA config
      operationId: updateRecaptchaConfig
      responses:
        '200': {description: Success}

  /email/config:
    get:
      tags: [Config]
      summary: Get email config
      operationId: getEmailConfig
      responses:
        '200': {description: Success}
    post:
      tags: [Config]
      summary: Update email config
      operationId: updateEmailConfig
      responses:
        '200': {description: Success}

  /email/config/test:
    post:
      tags: [Config]
      summary: Test email config
      operationId: testEmailConfig
      responses:
        '200': {description: Success}

  /backups/config:
    get:
      tags: [Config]
      summary: Get backups config
      operationId: getBackupsConfig
      responses:
        '200': {description: Success}
    post:
      tags: [Config]
      summary: Update backups config
      operationId: updateBackupsConfig
      responses:
        '200': {description: Success}

  /motorapi/config:
    get:
      tags: [Config]
      summary: Get MotorAPI config
      operationId: getMotorApiConfig
      responses:
        '200': {description: Success}
    post:
      tags: [Config]
      summary: Update MotorAPI config
      operationId: updateMotorApiConfig
      responses:
        '200': {description: Success}

  /stripe/config:
    get:
      tags: [Config]
      summary: Get Stripe config
      operationId: getStripeConfig
      responses:
        '200': {description: Success}
    post:
      tags: [Config]
      summary: Update Stripe config
      operationId: updateStripeConfig
      responses:
        '200': {description: Success}

  /fxratesapi/config:
    get:
      tags: [Config]
      summary: Get FXRatesAPI config
      operationId: getFxRatesApiConfig
      responses:
        '200': {description: Success}
    post:
      tags: [Config]
      summary: Update FXRatesAPI config
      operationId: updateFxRatesApiConfig
      responses:
        '200': {description: Success}

  /gatewayapi/config:
    get:
      tags: [Config]
      summary: Get GatewayAPI config
      operationId: getGatewayApiConfig
      responses:
        '200': {description: Success}
    post:
      tags: [Config]
      summary: Update GatewayAPI config
      operationId: updateGatewayApiConfig
      responses:
        '200': {description: Success}

  /xlvask/config:
    get:
      tags: [Config]
      summary: Get XLVask config
      operationId: getXlvaskConfig
      responses:
        '200': {description: Success}
    post:
      tags: [Config]
      summary: Update XLVask config
      operationId: updateXlvaskConfig
      responses:
        '200': {description: Success}

  /entra/config:
    get:
      tags: [Config]
      summary: Get Entra config
      operationId: getEntraConfig
      responses:
        '200': {description: Success}
    post:
      tags: [Config]
      summary: Update Entra config
      operationId: updateEntraConfig
      responses:
        '200': {description: Success}

  /limble/config:
    get:
      tags: [Config]
      summary: Get Limble config
      operationId: getLimbleConfig
      responses:
        '200': {description: Success}
    post:
      tags: [Config]
      summary: Update Limble config
      operationId: updateLimbleConfig
      responses:
        '200': {description: Success}

  /ocrspace/config:
    get:
      tags: [Config]
      summary: Get OcrSpace config
      operationId: getOcrSpaceConfig
      responses:
        '200': {description: Success}
    post:
      tags: [Config]
      summary: Update OcrSpace config
      operationId: updateOcrSpaceConfig
      responses:
        '200': {description: Success}

  /openai/config:
    get:
      tags: [Config]
      summary: Get OpenAI config
      operationId: getOpenAiConfig
      responses:
        '200': {description: Success}
    post:
      tags: [Config]
      summary: Update OpenAI config
      operationId: updateOpenAiConfig
      responses:
        '200': {description: Success}

  /licenseplaterecognizer/config:
    get:
      tags: [Config]
      summary: Get LicensePlateRecognizer config
      operationId: getLicensePlateRecognizerConfig
      responses:
        '200': {description: Success}
    post:
      tags: [Config]
      summary: Update LicensePlateRecognizer config
      operationId: updateLicensePlateRecognizerConfig
      responses:
        '200': {description: Success}

  /virkdata/config:
    get:
      tags: [Config]
      summary: Get Virkdata config
      operationId: getVirkdataConfig
      responses:
        '200': {description: Success}
    post:
      tags: [Config]
      summary: Update Virkdata config
      operationId: updateVirkdataConfig
      responses:
        '200': {description: Success}

  /shelly/config:
    get:
      tags: [Config]
      summary: Get Shelly config
      operationId: getShellyConfig
      responses:
        '200': {description: Success}
    post:
      tags: [Config]
      summary: Update Shelly config
      operationId: updateShellyConfig
      responses:
        '200': {description: Success}

  /selfserve/config:
    get:
      tags: [Config]
      summary: Get Self-Serve config
      operationId: getSelfServeConfig
      responses:
        '200': {description: Success}
    post:
      tags: [Config]
      summary: Update Self-Serve config
      operationId: updateSelfServeConfig
      responses:
        '200': {description: Success}

  /branding:
    get:
      tags:
        - Branding
      summary: List branding options
      description: Retrieve a list of branding options or a specific branding option if ID is provided
      operationId: listBrandingOptions
      parameters:
        - name: id
          in: query
          required: false
          schema:
            type: integer
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
      responses:
        '200':
          description: Branding options retrieved successfully
        '400':
          $ref: '#/components/responses/BadRequest'
        '403':
          $ref: '#/components/responses/Forbidden'
    post:
      tags:
        - Branding
      summary: Add branding option
      description: Create a new branding option
      operationId: addBrandingOption
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, description, cvr]
              properties:
                name: {type: string}
                description: {type: string}
                cvr: {type: integer}
      responses:
        '200':
          description: Branding option added successfully
        '403':
          $ref: '#/components/responses/Forbidden'
    put:
      tags:
        - Branding
      summary: Edit branding option
      description: Update an existing branding option
      operationId: editBrandingOption
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [id]
              properties:
                id: {type: integer}
                name: {type: string}
                description: {type: string}
                cvr: {type: integer}
      responses:
        '200':
          description: Branding option updated successfully
        '403':
          $ref: '#/components/responses/Forbidden'

  /roles:
    get:
      tags:
        - Roles
      summary: List roles
      operationId: listRoles
      responses:
        '200':
          description: Success
    post:
      tags:
        - Roles
      summary: Add role
      operationId: addRole
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name: {type: string}
      responses:
        '200':
          description: Success
    put:
      tags:
        - Roles
      summary: Edit role
      operationId: editRole
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [id, name]
              properties:
                id: {type: integer}
                name: {type: string}
      responses:
        '200':
          description: Success

  /roles/permissions:
    post:
      tags:
        - Roles
      summary: Add permission to role
      operationId: addRolePermission
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [role_id, permission]
              properties:
                role_id: {type: integer}
                permission: {type: string}
      responses:
        '200':
          description: Success
    delete:
      tags:
        - Roles
      summary: Remove permission from role
      operationId: removeRolePermission
      parameters:
        - name: role_id
          in: query
          required: true
          schema: {type: integer}
        - name: permission
          in: query
          required: true
          schema: {type: string}
      responses:
        '200':
          description: Success

  /roles/clone:
    post:
      tags:
        - Roles
      summary: Clone role
      operationId: cloneRole
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [role_id, name]
              properties:
                role_id: {type: integer}
                name: {type: string}
      responses:
        '200':
          description: Success

  /modules/washcertificates:
    get:
      tags:
        - Modules
      summary: List wash certificates
      operationId: listWashCertificates
      responses:
        '200':
          description: Success

  /modules/xlvask/services/usage/orders:
    get:
      tags:
        - Modules
      summary: Get XLVask usage orders
      operationId: getXlvaskUsageOrders
      responses:
        '200':
          description: Success

  /modules/xlvask/services/usage/orders/fast-link:
    get:
      tags:
        - Modules
      summary: Get XLVask usage orders fast link
      operationId: getXlvaskUsageOrdersFastLink
      responses:
        '200':
          description: Success

  /superuser/department:
    get:
      tags:
        - Departments
      summary: List departments (superuser)
      operationId: listSuperuserDepartments
      responses:
        '200':
          description: Success

  /superuser/department/prices:
    get:
      tags:
        - Departments
      summary: Get department prices
      operationId: getDepartmentPrices
      parameters:
        - name: department_id
          in: query
          required: true
          schema: {type: integer}
      responses:
        '200':
          description: Success
    post:
      tags:
        - Departments
      summary: Set department price
      operationId: setDepartmentPrice
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [department_id, product_id, price]
              properties:
                department_id: {type: integer}
                product_id: {type: integer}
                price: {type: integer}
      responses:
        '200':
          description: Success

  /superuser/department/variables:
    get:
      tags:
        - Departments
      summary: Get department variables
      operationId: getDepartmentVariables
      parameters:
        - name: department_id
          in: query
          required: true
          schema: {type: integer}
      responses:
        '200':
          description: Success
    post:
      tags:
        - Departments
      summary: Set department variable
      operationId: setDepartmentVariable
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [department_id, variable, value]
              properties:
                department_id: {type: integer}
                variable: {type: string}
                value: {type: string}
      responses:
        '200':
          description: Success

  /departments/daily-reports:
    get:
      tags:
        - Departments
      summary: List daily reports
      operationId: listDailyReports
      responses:
        '200':
          description: Success
    post:
      tags:
        - Departments
      summary: Add daily report
      operationId: addDailyReport
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [department_id, date, report]
              properties:
                department_id: {type: integer}
                date: {type: string}
                report: {type: string}
      responses:
        '200':
          description: Success
    put:
      tags:
        - Departments
      summary: Edit daily report
      operationId: editDailyReport
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [id, report]
              properties:
                id: {type: integer}
                report: {type: string}
      responses:
        '200':
          description: Success

  /departments/daily-reports/get:
    get:
      tags:
        - Departments
      summary: Get daily report
      operationId: getDailyReport
      parameters:
        - name: department_id
          in: query
          required: true
          schema: {type: integer}
        - name: date
          in: query
          required: true
          schema: {type: string}
      responses:
        '200':
          description: Success

  /departments/daily-reports/product-count:
    get:
      tags:
        - Departments
      summary: Get product count for daily reports
      operationId: getDailyReportProductCount
      parameters:
        - name: date
          in: query
          required: true
          schema: {type: string}
        - name: date_to
          in: query
          required: false
          schema: {type: string}
        - name: department_id
          in: query
          required: true
          schema: {type: integer}
        - name: product_id
          in: query
          required: true
          schema: {type: integer}
      responses:
        '200':
          description: Success

  /departments/daily-reports/transaction-count:
    get:
      tags:
        - Departments
      summary: Get transaction count for daily reports
      operationId: getDailyReportTransactionCount
      parameters:
        - name: date
          in: query
          required: true
          schema: {type: string}
        - name: date_to
          in: query
          required: false
          schema: {type: string}
        - name: department_id
          in: query
          required: true
          schema: {type: integer}
      responses:
        '200':
          description: Success

  /departments/daily-reports/bookings-count:
    get:
      tags:
        - Departments
      summary: Get bookings count for daily reports
      operationId: getDailyReportBookingsCount
      parameters:
        - name: date
          in: query
          required: true
          schema: {type: string}
        - name: department_id
          in: query
          required: true
          schema: {type: integer}
      responses:
        '200':
          description: Success

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: JWT token obtained from /auth/login or /auth/employee/login

  parameters:
    PageParam:
      name: page
      in: query
      description: Page number for pagination
      schema:
        type: integer
        minimum: 1
        default: 1
    PerPageParam:
      name: per_page
      in: query
      description: Number of items per page
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 30
    SearchParam:
      name: search
      in: query
      description: Search query string
      schema:
        type: string
    LimitParam:
      name: limit
      in: query
      description: Number of items per page
      schema:
        type: integer
        minimum: 1
        maximum: 1000
        default: 100
    FiltersParam:
      name: filters
      in: query
      description: Filters for the list (e.g., module:selfserve,status_code:200)
      schema:
        type: string

  responses:
    BadRequest:
      description: Bad request - Invalid input parameters
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: Unauthorized - Invalid or missing authentication token
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Forbidden:
      description: Forbidden - Insufficient permissions
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotFound:
      description: Not found - Resource does not exist
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    InternalServerError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'

  schemas:
    Error:
      type: object
      properties:
        error:
          type: string
          description: Error message
        code:
          type: integer
          description: HTTP status code

    User:
      type: object
      properties:
        id:
          type: integer
          description: User ID
        customer_number:
          type: integer
          description: e-conomic customer number
        display_name:
          type: string
          description: User's display name
        group_id:
          type: integer
          description: User group/role ID
        phone_country_code:
          type: integer
          description: Phone country code
        phone:
          type: integer
          description: Phone number
        email:
          type: string
          format: email
          description: Email address
        sms_notifications_enabled:
          type: boolean
          description: SMS notifications enabled
        email_notifications_enabled:
          type: boolean
          description: Email notifications enabled
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    UserCreate:
      type: object
      required:
        - customer_number
        - password
      properties:
        customer_number:
          type: integer
        password:
          type: string
          format: password
        display_name:
          type: string
        group_id:
          type: integer
        email:
          type: string
          format: email
        phone:
          type: integer
        phone_country_code:
          type: integer

    UserUpdate:
      type: object
      properties:
        id:
          type: integer
        customer_number:
          type: integer
        display_name:
          type: string
        group_id:
          type: integer
        email:
          type: string
          format: email
        phone:
          type: integer
        phone_country_code:
          type: integer

    Order:
      type: object
      properties:
        id:
          type: integer
          description: Order ID
        customer_id:
          type: integer
          description: Customer number
        customer_name:
          type: string
          description: Customer name
        user_id:
          type: integer
          description: User ID
        cashier_id:
          type: integer
          description: Cashier user ID
        cashier_name:
          type: string
          description: Cashier name
        department_id:
          type: integer
          description: Department ID
        status:
          type: string
          description: Order status
        total_net_amount:
          type: number
          format: float
          description: Total order amount
        po:
          type: string
          description: Purchase order number
          nullable: true
        lane:
          type: string
          description: Lane information
          nullable: true
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    DepartmentSelfserveQuestion:
      type: object
      properties:
        id:
          type: integer
          description: Question ID
        department:
          type: integer
          description: Department ID
        lane:
          type: integer
          description: Lane ID
        product:
          type: integer
          description: Product ID
        question_condition:
          type: integer
          description: Question condition object ID
          nullable: true
        question:
          type: string
          description: Question text
        description:
          type: string
          description: Question description
        order_priority:
          type: integer
          description: Display order priority (lower numbers shown first)
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    DepartmentSelfserveTask:
      type: object
      properties:
        id:
          type: integer
          description: Task ID
        department:
          type: integer
          description: Department ID
        lane:
          type: integer
          description: Lane ID
        product:
          type: integer
          description: Product ID
        question:
          type: integer
          description: Question ID (if conditional task)
          nullable: true
        task:
          type: string
          description: Task text
        description:
          type: string
          description: Task description
        order_priority:
          type: integer
          description: Display order priority (lower numbers shown first)
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    DepartmentSelfserveCondition:
      type: object
      properties:
        id:
          type: integer
          description: Condition ID
        department:
          type: integer
          description: Department ID
        lane:
          type: integer
          description: Lane ID
        product:
          type: integer
          description: Product ID
        condition_id:
          type: integer
          description: Optional condition ID
          nullable: true
        name:
          type: string
          description: Condition name
        description:
          type: string
          description: Condition description
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    DepartmentSelfserveConditionRule:
      type: object
      properties:
        id:
          type: integer
          description: Rule ID
        condition_id:
          type: integer
          description: Condition object ID
        type:
          type: string
          description: Condition type (e.g., IS_TRUE, IS_FALSE)
        object_type:
          type: string
          description: The object type to which the condition applies (e.g., question, task, etc.)
        object_id:
          type: integer
          description: The object id to which the condition applies
        name:
          type: string
          description: Condition name
        description:
          type: string
          description: Condition description
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    OrderCreate:
      type: object
      required:
        - customer_id
        - department_id
      properties:
        customer_id:
          type: integer
        department_id:
          type: integer
        cashier_id:
          type: integer
        po:
          type: string
        lane:
          type: string

    OrderUpdate:
      type: object
      properties:
        id:
          type: integer
        customer_id:
          type: integer
        department_id:
          type: integer
        status:
          type: string
        po:
          type: string
        lane:
          type: string

    OrderItem:
      type: object
      properties:
        id:
          type: integer
        order_id:
          type: integer
        product_id:
          type: integer
        product_name:
          type: string
        quantity:
          type: integer
        unit_price:
          type: number
          format: float
        discount:
          type: number
          format: float
        total_price:
          type: number
          format: float

    OrderItemCreate:
      type: object
      required:
        - order_id
        - product_id
        - quantity
      properties:
        order_id:
          type: integer
        product_id:
          type: integer
        quantity:
          type: integer
        discount:
          type: number
          format: float

    OrderItemUpdate:
      type: object
      required:
        - id
      properties:
        id:
          type: integer
        quantity:
          type: integer
        discount:
          type: number
          format: float

    Department:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        description:
          type: string
        economic_department_id:
          type: integer
        visible:
          type: boolean
        dimension:
          type: integer
        branding:
          type: integer
        longitude:
          type: number
          format: float
        latitude:
          type: number
          format: float
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    DepartmentCreate:
      type: object
      required:
        - name
        - economic_department_id
      properties:
        name:
          type: string
        description:
          type: string
        economic_department_id:
          type: integer
        visible:
          type: boolean
        longitude:
          type: number
          format: float
        latitude:
          type: number
          format: float

    DepartmentUpdate:
      type: object
      required:
        - id
      properties:
        id:
          type: integer
        name:
          type: string
        description:
          type: string
        visible:
          type: boolean
        longitude:
          type: number
          format: float
        latitude:
          type: number
          format: float

    DepartmentLane:
      type: object
      properties:
        id:
          type: integer
        department:
          type: integer
        name:
          type: string
        relay_in_id:
          type: string
        relay_out_id:
          type: string
        relay_machine_id:
          type: string
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    DepartmentLaneCreate:
      type: object
      required:
        - department
        - name
      properties:
        department:
          type: integer
        name:
          type: string
        relay_in_id:
          type: string
        relay_out_id:
          type: string
        relay_machine_id:
          type: string

    DepartmentLaneUpdate:
      type: object
      required:
        - id
      properties:
        id:
          type: integer
        department:
          type: integer
        name:
          type: string
        relay_in_id:
          type: string
        relay_out_id:
          type: string
        relay_machine_id:
          type: string

    Product:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        description:
          type: string
        price:
          type: number
          format: float
        category_id:
          type: integer
        category_name:
          type: string
        visible:
          type: boolean
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    ProductCreate:
      type: object
      required:
        - name
        - price
        - category_id
      properties:
        name:
          type: string
        description:
          type: string
        price:
          type: number
          format: float
        category_id:
          type: integer
        visible:
          type: boolean

    ProductUpdate:
      type: object
      required:
        - id
      properties:
        id:
          type: integer
        name:
          type: string
        description:
          type: string
        price:
          type: number
          format: float
        category_id:
          type: integer
        visible:
          type: boolean

    Category:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        description:
          type: string
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    CategoryCreate:
      type: object
      required:
        - name
      properties:
        name:
          type: string
        description:
          type: string

    CategoryUpdate:
      type: object
      required:
        - id
      properties:
        id:
          type: integer
        name:
          type: string
        description:
          type: string

    ModuleActionLog:
      type: object
      properties:
        id:
          type: integer
          description: Log ID
        module:
          type: string
          description: The module name
        action:
          type: string
          description: The action name
        status_code:
          type: integer
          description: HTTP status code
        data:
          type: object
          description: The action data (JSON decoded)
        created_at:
          type: string
          format: date-time
          description: Log creation timestamp

    Booking:
      type: object
      properties:
        id:
          type: integer
        customer_id:
          type: integer
        department_id:
          type: integer
        booking_time:
          type: string
          format: date-time
        status:
          type: string
        created_at:
          type: string
          format: date-time

    BookingUpdate:
      type: object
      required:
        - id
      properties:
        id:
          type: integer
        status:
          type: string
        booking_time:
          type: string
          format: date-time

    Vehicle:
      type: object
      properties:
        id:
          type: integer
        plate:
          type: string
        customer_id:
          type: integer
        created_at:
          type: string
          format: date-time

    Notification:
      type: object
      properties:
        id:
          type: integer
        user_id:
          type: integer
        title:
          type: string
        message:
          type: string
        read:
          type: boolean
        created_at:
          type: string
          format: date-time

    NotificationCreate:
      type: object
      required:
        - user_id
        - title
        - message
      properties:
        user_id:
          type: integer
        title:
          type: string
        message:
          type: string

    Permission:
      type: object
      properties:
        name:
          type: string
          description: Permission identifier
        description:
          type: string
          description: Human-readable description
