diff --git a/openapi.yaml b/openapi.yaml new file mode 100644 index 00000000..8e2bd269 --- /dev/null +++ b/openapi.yaml @@ -0,0 +1,5143 @@ +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/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 + + 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 diff --git a/src/components/displays/department/tables/SelfServeQuestionsTable.vue b/src/components/displays/department/tables/SelfServeQuestionsTable.vue index 0fe235a2..f347d4aa 100644 --- a/src/components/displays/department/tables/SelfServeQuestionsTable.vue +++ b/src/components/displays/department/tables/SelfServeQuestionsTable.vue @@ -78,6 +78,7 @@ const onDrop = async (event, newIndex) => { {{ SessionUser.objects.self_serve_questions.columns.order_priority.label }} + {{ SessionUser.objects.self_serve_questions.columns.question_condition.label }} {{ SessionUser.objects.self_serve_questions.columns.question.label }} {{ SessionUser.objects.self_serve_questions.columns.description.label }} {{ SessionUser.objects.self_serve_questions.columns.lane.label }} @@ -108,6 +109,14 @@ const onDrop = async (event, newIndex) => { :edit-function="SessionUser.objects.self_serve_questions.showEditObjectFieldForm" :permission-check-function="SessionUser.canAccessAdmin" /> + { + let questions = await SessionUser.objects.self_serve_questions.get.all(); + const departmentId = lockedValues.department || lockedValues.department_id; + const productId = lockedValues.product || lockedValues.vehicle_type || lockedValues.product_id; + + if (departmentId) { + questions = questions.filter(q => parseInt(q.department) === parseInt(departmentId)); + } + if (productId) { + questions = questions.filter(q => parseInt(q.product) === parseInt(productId)); + } + + let options = questions.map(q => ({ + ...q, + name: q.question + })); + + options.unshift({ + id: 0, + name: "Ingen" + }); + + return options; + }, + parse: (id) => { + return SessionUser.objects.self_serve_questions.functions.getQuestionText(id); } }, order_priority: { @@ -113,7 +140,7 @@ export const SelfServeQuestions = { } }, }, - add: async (department, lane, product, question, description, order_priority) => { + add: async (department, lane, product, question, description, question_condition, order_priority) => { return ObjectsGlobal.add.object( SelfServeQuestions.meta.endpoint, { @@ -122,6 +149,7 @@ export const SelfServeQuestions = { product: parseInt(product), question: question, description: description, + question_condition: (question_condition && parseInt(question_condition) !== 0) ? parseInt(question_condition) : null, order_priority: parseInt(order_priority), } ); @@ -151,20 +179,12 @@ export const SelfServeQuestions = { parseInt(order_priority) ) }, - image: async (id, image) => { + question_condition: async (id, question_condition) => { return ObjectsGlobal.set.column( SelfServeQuestions.meta.endpoint, id, - "image", - parseInt(image) - ) - }, - vehicle_type: async (id, vehicle_type) => { - return ObjectsGlobal.set.column( - SelfServeQuestions.meta.endpoint, - id, - "vehicle_type", - parseInt(vehicle_type) + "question_condition", + (question_condition && parseInt(question_condition) !== 0) ? parseInt(question_condition) : null ) }, product: async (id, product) => {