{"openapi":"3.0.0","paths":{"/api/v1/tenants":{"get":{"operationId":"TenantController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}},{"name":"status","required":false,"in":"query","description":"Filter by tenant status (e.g. ACTIVE, SUSPENDED)","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TenantEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all tenants","tags":["Tenants"]}},"/api/v1/tenants/me":{"get":{"operationId":"TenantController_mine_v1","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TenantBusinessDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"The signed-in staff member’s company, for printing on receipts","tags":["Tenants"]}},"/api/v1/tenants/{id}":{"get":{"operationId":"TenantController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TenantEntity"}}}]}}}},"404":{"description":"Tenant not found."}},"security":[{"bearer":[]}],"summary":"Get a tenant by ID","tags":["Tenants"]},"patch":{"operationId":"TenantController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTenantDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TenantEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a tenant","tags":["Tenants"]}},"/api/v1/users":{"post":{"operationId":"UserController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/UserEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new user","tags":["Users"]},"get":{"operationId":"UserController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}},{"name":"status","required":false,"in":"query","description":"Filter by user status (e.g. ACTIVE, SUSPENDED)","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/UserEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all users","tags":["Users"]}},"/api/v1/users/{id}":{"get":{"operationId":"UserController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/UserEntity"}}}]}}}},"404":{"description":"User not found."}},"security":[{"bearer":[]}],"summary":"Get a user by ID","tags":["Users"]},"patch":{"operationId":"UserController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/UserEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a user","tags":["Users"]},"delete":{"operationId":"UserController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/UserEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a user","tags":["Users"]}},"/api/v1/auth/signin":{"post":{"description":"The tenant is taken from the account, so no tenantId is sent. Pass branchId to start in a specific branch; otherwise the branch is auto-selected when the user has exactly one, and `access[]` lists every branch they may switch to.","operationId":"AuthController_signIn_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignInDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/LoginResponseDto"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Invalid credentials, the account is not active, or its tenant is suspended, inactive or deleted."},"429":{"description":"Too many attempts on this account; wait a minute."}},"summary":"Sign in","tags":["Auth"]}},"/api/v1/auth/refresh":{"post":{"description":"Sign-in returns a refresh_token lasting 7 days. Send it here before the hour-long access_token runs out to get a new pair; the account is checked again as at sign-in.","operationId":"AuthController_refresh_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/RefreshResponseDto"}}}]}}}},"201":{"description":""},"401":{"description":"Expired or invalid; sign in again"}},"summary":"Swap a refresh token for a new access token","tags":["Auth"]}},"/api/v1/auth/approve":{"post":{"description":"The manager types their own User ID and password on the till the cashier is signed in to. Returns a token good for 5 minutes that approves only `permission` and cannot be used to sign in. Send it as the x-approver-authorization header.","operationId":"AuthController_approve_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApproveDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ApprovalResponseDto"}}}]}}}},"201":{"description":""},"401":{"description":"Wrong User ID or password"},"403":{"description":"The same person, or someone who cannot approve this"}},"security":[{"bearer":[]}],"summary":"A manager's approval on this till","tags":["Auth"]}},"/api/v1/auth/set-active-branch":{"post":{"operationId":"AuthController_setActiveBranch_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetActiveBranchDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/LoginResponseDto"}}}]}}}},"201":{"description":""}},"security":[{"bearer":[]}],"summary":"Switch the active branch, re-issuing the token for that branch","tags":["Auth"]}},"/api/v1/auth/session":{"get":{"operationId":"AuthController_getSession_v1","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SessionUserDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get current session info","tags":["Auth"]}},"/api/v1/system-admin/tenants/onboard":{"post":{"operationId":"SystemAdminController_onboardTenant_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardTenantDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/OnboardTenantResponseDto"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardTenantResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Onboard a new tenant: creates the tenant, a branch, its enabled modules, starter roles and the owner user in one transaction","tags":["System Admin"]}},"/api/v1/system-admin/tenants/{id}/modules":{"get":{"operationId":"SystemAdminController_getTenantModules_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TenantModulesDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Read which modules a tenant may build roles from","tags":["System Admin"]},"put":{"operationId":"SystemAdminController_setTenantModules_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetTenantModulesDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SetTenantModulesResultDto"}}}]}}}},"400":{"description":"Unknown module name, or the tenant does not exist."}},"security":[{"bearer":[]}],"summary":"Set which modules a tenant may build roles from. Disabling a module strips its permissions from the tenant’s roles.","tags":["System Admin"]}},"/api/v1/system-admin/tenants/{id}/reset":{"get":{"description":"Row counts per part, for the confirmation screen.","operationId":"SystemAdminController_previewReset_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"What a reset would delete from a tenant, part by part","tags":["System Admin"]},"post":{"description":"Deletes the chosen parts (and the parts they depend on) for this tenant only, in one transaction. The tenant, its branches, users, roles and shop settings stay. Cannot be undone; confirmName must be the tenant name.","operationId":"SystemAdminController_resetTenant_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetTenantDto"}}}},"responses":{"201":{"description":""},"400":{"description":"Name does not match, unknown part, or other data still uses it."}},"security":[{"bearer":[]}],"summary":"Reset part of a tenant's data","tags":["System Admin"]}},"/api/v1/system-admin/tenants/{id}":{"delete":{"operationId":"SystemAdminController_removeTenant_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TenantEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a tenant and all its data","tags":["System Admin"]}},"/api/v1/system-admin/users":{"post":{"operationId":"SystemAdminController_createUser_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserAsAdminDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/UserEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Create a user with explicit tenant context","tags":["System Admin"]}},"/api/v1/system-admin/roles/assign-permissions":{"post":{"operationId":"SystemAdminController_assignPermissionsToRole_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignPermissionToRoleDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/AssignPermissionsResultDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Assign permissions to a role","tags":["System Admin"]}},"/api/v1/system-admin/users/assign-role":{"post":{"operationId":"SystemAdminController_assignRoleToUser_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignRoleToUserDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/UserRoleBranchEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Assign a role to a user at a branch","tags":["System Admin"]}},"/api/v1/branches":{"post":{"operationId":"BranchController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBranchDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/BranchEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BranchEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new branch","tags":["Branches"]},"get":{"operationId":"BranchController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}},{"name":"status","required":false,"in":"query","description":"Filter by branch status (e.g. ACTIVE, INACTIVE)","schema":{"type":"string"}},{"name":"type","required":false,"in":"query","description":"Filter by branch type (e.g. RETAIL, WAREHOUSE)","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/BranchEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all branches","tags":["Branches"]}},"/api/v1/branches/{id}":{"get":{"operationId":"BranchController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/BranchEntity"}}}]}}}},"404":{"description":"Branch not found."}},"security":[{"bearer":[]}],"summary":"Get a branch by ID","tags":["Branches"]},"patch":{"operationId":"BranchController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBranchDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/BranchEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a branch","tags":["Branches"]},"delete":{"operationId":"BranchController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/BranchEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a branch","tags":["Branches"]}},"/api/v1/roles":{"post":{"operationId":"RoleController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRoleDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/RoleEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoleEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new role in your tenant","tags":["Roles"]},"get":{"operationId":"RoleController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/RoleEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all roles","tags":["Roles"]}},"/api/v1/roles/available-permissions":{"get":{"operationId":"RoleController_availablePermissions_v1","parameters":[{"name":"search","required":false,"in":"query","description":"Filter by module:subject:action substring.","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PermissionEntity"}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List the permissions your tenant may assign, based on its enabled modules","tags":["Roles"]}},"/api/v1/roles/{id}":{"get":{"operationId":"RoleController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/RoleEntity"}}}]}}}},"404":{"description":"Role not found."}},"security":[{"bearer":[]}],"summary":"Get a role by ID","tags":["Roles"]},"patch":{"operationId":"RoleController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRoleDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/RoleEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Rename or re-parent a role","tags":["Roles"]},"delete":{"operationId":"RoleController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/RoleEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a role","tags":["Roles"]}},"/api/v1/roles/{id}/permissions":{"post":{"operationId":"RoleController_assignPermissions_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignPermissionToRoleDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/RolePermissionsResultDto"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RolePermissionsResultDto"}}}},"403":{"description":"A permission is outside the tenant’s modules, or you do not hold it yourself."}},"security":[{"bearer":[]}],"summary":"Add permissions to a role, keeping the ones it already has","tags":["Roles"]},"put":{"operationId":"RoleController_setPermissions_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetRolePermissionsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/RolePermissionsResultDto"}}}]}}}},"403":{"description":"A permission is outside the tenant’s modules, or you do not hold it yourself."}},"security":[{"bearer":[]}],"summary":"Set the role’s permissions to exactly this list, removing anything else","tags":["Roles"]}},"/api/v1/permissions":{"get":{"operationId":"PermissionController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PermissionEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get the permissions available to you. Tenants see only the modules they have enabled.","tags":["Permissions"]}},"/api/v1/categories":{"post":{"operationId":"CategoryController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCategoryDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/CategoryEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new category","tags":["Categories"]},"get":{"operationId":"CategoryController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CategoryEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all categories (paginated)","tags":["Categories"]}},"/api/v1/categories/tree":{"get":{"operationId":"CategoryController_findTree_v1","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/CategoryEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get category tree (nested children)","tags":["Categories"]}},"/api/v1/categories/{id}":{"get":{"operationId":"CategoryController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/CategoryEntity"}}}]}}}},"404":{"description":"Category not found."}},"security":[{"bearer":[]}],"summary":"Get a category by ID","tags":["Categories"]},"patch":{"operationId":"CategoryController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCategoryDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/CategoryEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a category","tags":["Categories"]},"delete":{"operationId":"CategoryController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/CategoryEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a category","tags":["Categories"]}},"/api/v1/uom-classes":{"post":{"operationId":"UomClassController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUomClassDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/UomClassEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UomClassEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new UOM class","tags":["UOM Classes"]},"get":{"operationId":"UomClassController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/UomClassEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all UOM classes","tags":["UOM Classes"]}},"/api/v1/uom-classes/{id}":{"get":{"operationId":"UomClassController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/UomClassEntity"}}}]}}}},"404":{"description":"UOM class not found."}},"security":[{"bearer":[]}],"summary":"Get a UOM class by ID","tags":["UOM Classes"]},"patch":{"operationId":"UomClassController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUomClassDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/UomClassEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a UOM class","tags":["UOM Classes"]},"delete":{"operationId":"UomClassController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/UomClassEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a UOM class","tags":["UOM Classes"]}},"/api/v1/uoms":{"post":{"operationId":"UomController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUomDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/UomEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UomEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new UOM","tags":["UOMs"]},"get":{"operationId":"UomController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}},{"name":"classId","required":false,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/UomEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all UOMs","tags":["UOMs"]}},"/api/v1/uoms/{id}":{"get":{"operationId":"UomController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/UomEntity"}}}]}}}},"404":{"description":"UOM not found."}},"security":[{"bearer":[]}],"summary":"Get a UOM by ID","tags":["UOMs"]},"patch":{"operationId":"UomController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUomDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/UomEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a UOM","tags":["UOMs"]},"delete":{"operationId":"UomController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/UomEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a UOM","tags":["UOMs"]}},"/api/v1/products":{"post":{"operationId":"ProductController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProductDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ProductEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new product","tags":["Products"]},"get":{"operationId":"ProductController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}},{"name":"categoryId","required":false,"in":"query","description":"Filter by category ID","schema":{"format":"uuid","type":"string"}},{"name":"trackingType","required":false,"in":"query","description":"Filter by tracking type (e.g. STANDARD, SERIALIZED)","schema":{"type":"string"}},{"name":"inStockOnly","required":false,"in":"query","description":"If true, return only products whose total on-hand stock is greater than 0","schema":{"type":"boolean"}},{"name":"isAvailable","required":false,"in":"query","description":"true: only items that can be ordered now. false: only items marked unavailable. Leave out for both (show unavailable ones muted).","schema":{"type":"boolean"}},{"name":"locationId","required":false,"in":"query","description":"Scope stock computation to this location (applies to inStockOnly filter and totalOnHand enrichment)","schema":{"format":"uuid","type":"string"}},{"name":"kind","required":false,"in":"query","description":"Only this kind: ITEM (menu), SERVICE or RENTAL.","schema":{"type":"string","enum":["ITEM","SERVICE","RENTAL"]}},{"name":"soldAt","required":false,"in":"query","description":"Only what is sold at this POS area: products naming it, and those sold everywhere.","schema":{"type":"string","enum":["BAR","SPA","KTV"]}},{"name":"rents","required":false,"in":"query","description":"Only rentals of this kind of place.","schema":{"type":"string","enum":["KTV_ROOM","SPA_ROOM","TABLE"]}},{"name":"placeId","required":false,"in":"query","description":"A KTV room, SPA room or table: only the rentals that can be used there (made for that kind of place, and for every one of them or this one).","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ProductEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all products","tags":["Products"]}},"/api/v1/products/{id}":{"get":{"operationId":"ProductController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ProductEntity"}}}]}}}},"404":{"description":"Product not found."}},"security":[{"bearer":[]}],"summary":"Get a product by ID","tags":["Products"]},"patch":{"operationId":"ProductController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProductDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ProductEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a product","tags":["Products"]},"delete":{"operationId":"ProductController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ProductEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a product","tags":["Products"]}},"/api/v1/products/{id}/availability":{"patch":{"description":"The Operation Dashboard switch. Unavailable = sold out for now: still listed, but no new order line can take it. Already-ordered lines are unaffected.","operationId":"ProductController_setAvailability_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetAvailabilityDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ProductEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Mark a product available or unavailable","tags":["Products"]}},"/api/v1/products/{id}/setup":{"get":{"description":"What the one-page item editor shows beside the product itself.","operationId":"ProductController_getSetup_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/MenuItemSetupViewDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"A menu item's add-on groups and ingredients","tags":["Products"]},"put":{"description":"Sets exactly the add-on groups given, and the item recipe from the ingredients; an empty ingredient list stops using a recipe. Fields left out are untouched.","operationId":"ProductController_saveSetup_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MenuItemSetupDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/MenuItemSetupViewDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Save a menu item's add-on groups and ingredients","tags":["Products"]}},"/api/v1/products/{productId}/variants":{"post":{"operationId":"ProductVariantController_create_v1","parameters":[{"name":"productId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProductVariantDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ProductVariantEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductVariantEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new product variant","tags":["Product Variants"]},"get":{"operationId":"ProductVariantController_findAll_v1","parameters":[{"name":"productId","required":true,"in":"path","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ProductVariantEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all variants for a product","tags":["Product Variants"]}},"/api/v1/products/{productId}/variants/{id}":{"get":{"operationId":"ProductVariantController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"productId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ProductVariantEntity"}}}]}}}},"404":{"description":"Product variant not found."}},"security":[{"bearer":[]}],"summary":"Get a product variant by ID","tags":["Product Variants"]},"patch":{"operationId":"ProductVariantController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"productId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProductVariantDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ProductVariantEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a product variant","tags":["Product Variants"]},"delete":{"operationId":"ProductVariantController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"productId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ProductVariantEntity"}}}]}}}},"400":{"description":"Cannot delete the last variant of a product."},"404":{"description":"Product variant not found."}},"security":[{"bearer":[]}],"summary":"Delete a product variant","tags":["Product Variants"]}},"/api/v1/venue-settings":{"get":{"description":"SPA and KTV on or off, whether guests may order food and drinks in each, and whether they pay when ordering or at the end. Readable by any signed-in staff and tablets, so the POS knows how to behave. A business that never saved its settings gets the defaults: everything on, pay when ordering.","operationId":"VenueSettingController_get_v1","parameters":[{"name":"tenantId","required":false,"in":"query","description":"System admins only: the tenant to read or change.","schema":{"format":"uuid","example":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/VenueSettingDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"How this business runs its rooms","tags":["Venue Settings"]},"put":{"description":"Send only the switches that change.","operationId":"VenueSettingController_update_v1","parameters":[{"name":"tenantId","required":false,"in":"query","description":"System admins only: the tenant to read or change.","schema":{"format":"uuid","example":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateVenueSettingDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/VenueSettingDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Change how this business runs its rooms","tags":["Venue Settings"]}},"/api/v1/locations":{"post":{"operationId":"LocationController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLocationDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/LocationEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LocationEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new location","tags":["Locations"]},"get":{"operationId":"LocationController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/LocationEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all locations (paginated)","tags":["Locations"]}},"/api/v1/locations/tree":{"get":{"operationId":"LocationController_findTree_v1","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/LocationEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get location tree (nested subLocations)","tags":["Locations"]}},"/api/v1/locations/{id}":{"get":{"operationId":"LocationController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/LocationEntity"}}}]}}}},"404":{"description":"Location not found."}},"security":[{"bearer":[]}],"summary":"Get a location by ID","tags":["Locations"]},"patch":{"operationId":"LocationController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateLocationDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/LocationEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a location","tags":["Locations"]},"delete":{"operationId":"LocationController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/LocationEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a location","tags":["Locations"]}},"/api/v1/vendors":{"post":{"operationId":"VendorController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateVendorDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/VendorEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VendorEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new vendor","tags":["Vendors"]},"get":{"operationId":"VendorController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/VendorEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all vendors","tags":["Vendors"]}},"/api/v1/vendors/{id}":{"get":{"operationId":"VendorController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/VendorEntity"}}}]}}}},"404":{"description":"Vendor not found."}},"security":[{"bearer":[]}],"summary":"Get a vendor by ID","tags":["Vendors"]},"patch":{"operationId":"VendorController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateVendorDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/VendorEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a vendor","tags":["Vendors"]},"delete":{"operationId":"VendorController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/VendorEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a vendor","tags":["Vendors"]}},"/api/v1/transfer-orders":{"post":{"operationId":"TransferOrderController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTransferOrderDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TransferOrderEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransferOrderEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new transfer order","tags":["Transfer Orders"]},"get":{"operationId":"TransferOrderController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TransferOrderEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all transfer orders","tags":["Transfer Orders"]}},"/api/v1/transfer-orders/{id}":{"get":{"operationId":"TransferOrderController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TransferOrderEntity"}}}]}}}},"404":{"description":"Transfer order not found."}},"security":[{"bearer":[]}],"summary":"Get a transfer order by ID","tags":["Transfer Orders"]},"patch":{"operationId":"TransferOrderController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTransferOrderDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TransferOrderEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a transfer order","tags":["Transfer Orders"]},"delete":{"operationId":"TransferOrderController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TransferOrderEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a transfer order","tags":["Transfer Orders"]}},"/api/v1/transfer-orders/{transferOrderId}/lines":{"post":{"operationId":"TransferOrderLineController_create_v1","parameters":[{"name":"transferOrderId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTransferOrderLineDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TransferOrderLineEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransferOrderLineEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new transfer order line","tags":["Transfer Order Lines"]},"get":{"operationId":"TransferOrderLineController_findAll_v1","parameters":[{"name":"transferOrderId","required":true,"in":"path","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TransferOrderLineEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all lines for a transfer order","tags":["Transfer Order Lines"]}},"/api/v1/transfer-orders/{transferOrderId}/lines/{id}":{"get":{"operationId":"TransferOrderLineController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"transferOrderId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TransferOrderLineEntity"}}}]}}}},"404":{"description":"Transfer order line not found."}},"security":[{"bearer":[]}],"summary":"Get a transfer order line by ID","tags":["Transfer Order Lines"]},"patch":{"operationId":"TransferOrderLineController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"transferOrderId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTransferOrderLineDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TransferOrderLineEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a transfer order line","tags":["Transfer Order Lines"]},"delete":{"operationId":"TransferOrderLineController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"transferOrderId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TransferOrderLineEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a transfer order line","tags":["Transfer Order Lines"]}},"/api/v1/purchase-requisitions":{"post":{"operationId":"PurchaseRequisitionController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePurchaseRequisitionDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PurchaseRequisitionEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurchaseRequisitionEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new purchase requisition","tags":["Purchase Requisitions"]},"get":{"operationId":"PurchaseRequisitionController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PurchaseRequisitionEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all purchase requisitions","tags":["Purchase Requisitions"]}},"/api/v1/purchase-requisitions/{id}":{"get":{"operationId":"PurchaseRequisitionController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PurchaseRequisitionEntity"}}}]}}}},"404":{"description":"Purchase requisition not found."}},"security":[{"bearer":[]}],"summary":"Get a purchase requisition by ID","tags":["Purchase Requisitions"]},"patch":{"operationId":"PurchaseRequisitionController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePurchaseRequisitionDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PurchaseRequisitionEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a purchase requisition","tags":["Purchase Requisitions"]},"delete":{"operationId":"PurchaseRequisitionController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PurchaseRequisitionEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a purchase requisition","tags":["Purchase Requisitions"]}},"/api/v1/purchase-orders":{"post":{"operationId":"PurchaseOrderController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePurchaseOrderDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PurchaseOrderEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurchaseOrderEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new purchase order","tags":["Purchase Orders"]},"get":{"operationId":"PurchaseOrderController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PurchaseOrderEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all purchase orders","tags":["Purchase Orders"]}},"/api/v1/purchase-orders/{id}":{"get":{"operationId":"PurchaseOrderController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PurchaseOrderEntity"}}}]}}}},"404":{"description":"Purchase order not found."}},"security":[{"bearer":[]}],"summary":"Get a purchase order by ID","tags":["Purchase Orders"]},"patch":{"operationId":"PurchaseOrderController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePurchaseOrderDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PurchaseOrderEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a purchase order","tags":["Purchase Orders"]},"delete":{"operationId":"PurchaseOrderController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PurchaseOrderEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a purchase order","tags":["Purchase Orders"]}},"/api/v1/goods-received-notes":{"post":{"operationId":"GoodsReceivedNoteController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGoodsReceivedNoteDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/GoodsReceivedNoteEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GoodsReceivedNoteEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new goods received note","tags":["Goods Received Notes"]},"get":{"operationId":"GoodsReceivedNoteController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GoodsReceivedNoteEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all goods received notes","tags":["Goods Received Notes"]}},"/api/v1/goods-received-notes/{id}":{"get":{"operationId":"GoodsReceivedNoteController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/GoodsReceivedNoteEntity"}}}]}}}},"404":{"description":"Goods received note not found."}},"security":[{"bearer":[]}],"summary":"Get a goods received note by ID","tags":["Goods Received Notes"]},"patch":{"operationId":"GoodsReceivedNoteController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGoodsReceivedNoteDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/GoodsReceivedNoteEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a goods received note","tags":["Goods Received Notes"]},"delete":{"operationId":"GoodsReceivedNoteController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/GoodsReceivedNoteEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a goods received note","tags":["Goods Received Notes"]}},"/api/v1/goods-received-notes/{grnId}/lines":{"post":{"operationId":"GrnLineController_create_v1","parameters":[{"name":"grnId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGrnLineDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/GrnLineEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrnLineEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new GRN line","tags":["GRN Lines"]},"get":{"operationId":"GrnLineController_findAll_v1","parameters":[{"name":"grnId","required":true,"in":"path","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GrnLineEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all lines for a GRN","tags":["GRN Lines"]}},"/api/v1/goods-received-notes/{grnId}/lines/{id}":{"get":{"operationId":"GrnLineController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"grnId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/GrnLineEntity"}}}]}}}},"404":{"description":"GRN line not found."}},"security":[{"bearer":[]}],"summary":"Get a GRN line by ID","tags":["GRN Lines"]},"patch":{"operationId":"GrnLineController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"grnId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGrnLineDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/GrnLineEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a GRN line","tags":["GRN Lines"]},"delete":{"operationId":"GrnLineController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"grnId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/GrnLineEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a GRN line","tags":["GRN Lines"]}},"/api/v1/vendor-invoices":{"post":{"operationId":"VendorInvoiceController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateVendorInvoiceDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/VendorInvoiceEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VendorInvoiceEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new vendor invoice","tags":["Vendor Invoices"]},"get":{"operationId":"VendorInvoiceController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/VendorInvoiceEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all vendor invoices","tags":["Vendor Invoices"]}},"/api/v1/vendor-invoices/{id}":{"get":{"operationId":"VendorInvoiceController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/VendorInvoiceEntity"}}}]}}}},"404":{"description":"Vendor invoice not found."}},"security":[{"bearer":[]}],"summary":"Get a vendor invoice by ID","tags":["Vendor Invoices"]},"patch":{"operationId":"VendorInvoiceController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateVendorInvoiceDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/VendorInvoiceEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a vendor invoice","tags":["Vendor Invoices"]},"delete":{"operationId":"VendorInvoiceController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/VendorInvoiceEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a vendor invoice","tags":["Vendor Invoices"]}},"/api/v1/landed-cost-allocations":{"post":{"operationId":"LandedCostAllocationController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLandedCostAllocationDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/LandedCostAllocationEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LandedCostAllocationEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new landed cost allocation","tags":["Landed Cost Allocations"]},"get":{"operationId":"LandedCostAllocationController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/LandedCostAllocationEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all landed cost allocations","tags":["Landed Cost Allocations"]}},"/api/v1/landed-cost-allocations/{id}":{"get":{"operationId":"LandedCostAllocationController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/LandedCostAllocationEntity"}}}]}}}},"404":{"description":"Landed cost allocation not found."}},"security":[{"bearer":[]}],"summary":"Get a landed cost allocation by ID","tags":["Landed Cost Allocations"]},"patch":{"operationId":"LandedCostAllocationController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateLandedCostAllocationDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/LandedCostAllocationEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a landed cost allocation","tags":["Landed Cost Allocations"]},"delete":{"operationId":"LandedCostAllocationController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/LandedCostAllocationEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a landed cost allocation","tags":["Landed Cost Allocations"]}},"/api/v1/customers":{"post":{"operationId":"CustomerController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCustomerDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/CustomerEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new customer","tags":["Customers"]},"get":{"operationId":"CustomerController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CustomerEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Search and list customers (search by phone, name, or email)","tags":["Customers"]}},"/api/v1/customers/{id}":{"get":{"operationId":"CustomerController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/CustomerEntity"}}}]}}}},"404":{"description":"Customer not found."}},"security":[{"bearer":[]}],"summary":"Get a customer by ID","tags":["Customers"]},"patch":{"operationId":"CustomerController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCustomerDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/CustomerEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a customer","tags":["Customers"]},"delete":{"operationId":"CustomerController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/CustomerEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a customer","tags":["Customers"]}},"/api/v1/loyalty-ledger":{"get":{"operationId":"LoyaltyLedgerGlobalController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}},{"name":"customerId","required":false,"in":"query","schema":{"format":"uuid","type":"string"}},{"name":"transactionType","required":false,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/LoyaltyLedgerEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all loyalty ledger entries (tenant-scoped, filterable)","tags":["Loyalty Ledger"]}},"/api/v1/loyalty-ledger/{id}":{"get":{"operationId":"LoyaltyLedgerGlobalController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/LoyaltyLedgerEntity"}}}]}}}},"404":{"description":"Loyalty ledger entry not found."}},"security":[{"bearer":[]}],"summary":"Get a loyalty ledger entry by ID (tenant-scoped)","tags":["Loyalty Ledger"]}},"/api/v1/customers/{customerId}/loyalty-ledger":{"post":{"operationId":"LoyaltyLedgerController_create_v1","parameters":[{"name":"customerId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLoyaltyLedgerDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/LoyaltyLedgerEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoyaltyLedgerEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new loyalty ledger entry","tags":["Loyalty Ledger"]},"get":{"operationId":"LoyaltyLedgerController_findAll_v1","parameters":[{"name":"customerId","required":true,"in":"path","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/LoyaltyLedgerEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all loyalty ledger entries for a customer","tags":["Loyalty Ledger"]}},"/api/v1/customers/{customerId}/loyalty-ledger/{id}":{"get":{"operationId":"LoyaltyLedgerController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"customerId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/LoyaltyLedgerEntity"}}}]}}}},"404":{"description":"Loyalty ledger entry not found."}},"security":[{"bearer":[]}],"summary":"Get a loyalty ledger entry by ID","tags":["Loyalty Ledger"]},"patch":{"operationId":"LoyaltyLedgerController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"customerId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateLoyaltyLedgerDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/LoyaltyLedgerEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a loyalty ledger entry","tags":["Loyalty Ledger"]},"delete":{"operationId":"LoyaltyLedgerController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"customerId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/LoyaltyLedgerEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a loyalty ledger entry","tags":["Loyalty Ledger"]}},"/api/v1/customer-interactions":{"get":{"operationId":"CustomerInteractionGlobalController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}},{"name":"customerId","required":false,"in":"query","schema":{"format":"uuid","type":"string"}},{"name":"interactionType","required":false,"in":"query","schema":{"type":"string"}},{"name":"interactionChannel","required":false,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CustomerInteractionEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all customer interactions (tenant-scoped, filterable)","tags":["Customer Interactions"]}},"/api/v1/customer-interactions/{id}":{"get":{"operationId":"CustomerInteractionGlobalController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/CustomerInteractionEntity"}}}]}}}},"404":{"description":"Customer interaction not found."}},"security":[{"bearer":[]}],"summary":"Get a customer interaction by ID (tenant-scoped)","tags":["Customer Interactions"]}},"/api/v1/customers/{customerId}/interactions":{"post":{"operationId":"CustomerInteractionController_create_v1","parameters":[{"name":"customerId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCustomerInteractionDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/CustomerInteractionEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerInteractionEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new customer interaction","tags":["Customer Interactions"]},"get":{"operationId":"CustomerInteractionController_findAll_v1","parameters":[{"name":"customerId","required":true,"in":"path","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CustomerInteractionEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all interactions for a customer","tags":["Customer Interactions"]}},"/api/v1/customers/{customerId}/interactions/{id}":{"get":{"operationId":"CustomerInteractionController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"customerId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/CustomerInteractionEntity"}}}]}}}},"404":{"description":"Customer interaction not found."}},"security":[{"bearer":[]}],"summary":"Get a customer interaction by ID","tags":["Customer Interactions"]},"patch":{"operationId":"CustomerInteractionController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"customerId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCustomerInteractionDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/CustomerInteractionEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a customer interaction","tags":["Customer Interactions"]},"delete":{"operationId":"CustomerInteractionController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"customerId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/CustomerInteractionEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a customer interaction","tags":["Customer Interactions"]}},"/api/v1/sales-orders":{"post":{"operationId":"SalesOrderController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSalesOrderDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SalesOrderEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SalesOrderEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new sales order","tags":["Sales Orders"]},"get":{"description":"Drives the order tabs. `serviceType` narrows to one channel - TAKEAWAY for the take-away list. `waitingPickup=true` is the \"Waiting Pickup\" tab: orders with nothing left to prepare that nobody has collected yet, which is the same condition the pickup endpoint enforces, so every order listed can actually be picked up. Note this is separate from a line being PENDING, which means the opposite - the kitchen has not started it.","operationId":"SalesOrderController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}},{"name":"status","required":false,"in":"query","description":"Filter by order status (e.g. DRAFT, CONFIRMED, COMPLETED)","schema":{"type":"string"}},{"name":"customerId","required":false,"in":"query","description":"Filter by customer ID","schema":{"format":"uuid","type":"string"}},{"name":"dateFrom","required":false,"in":"query","description":"Filter orders from this date (ISO 8601)","schema":{"format":"date-time","type":"string"}},{"name":"dateTo","required":false,"in":"query","description":"Filter orders until this date (ISO 8601)","schema":{"format":"date-time","type":"string"}},{"name":"serviceType","required":false,"in":"query","description":"Filter by how the order is served: DINE_IN, TAKEAWAY, DELIVERY, COUNTER.","schema":{"type":"string","enum":["DINE_IN","TAKEAWAY","DELIVERY","COUNTER"]}},{"name":"waitingPickup","required":false,"in":"query","description":"Only orders sitting on the counter waiting to be collected: nothing left to prepare and not yet picked up. Narrows to TAKEAWAY and COUNTER unless `serviceType` says otherwise. This is the same condition the pickup endpoint enforces, so anything listed here can actually be picked up.","schema":{"example":"true","type":"boolean"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SalesOrderEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all sales orders","tags":["Sales Orders"]}},"/api/v1/sales-orders/{id}/settle":{"post":{"description":"Settles an order that already exists, for the shape checkout cannot handle: a KTV room or a dining table, where the order is opened when the party sits down and lines land on it for hours. Prices the order from its lines as they stand, checks the payments cover it, takes the money and marks it COMPLETED. Same tender rules as checkout, guest cards included - a card tender may omit its amount and is charged the remainder.","operationId":"SalesOrderController_settle_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettleOrderDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SettleOrderResponseDto"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettleOrderResponseDto"}}}},"400":{"description":"Payments do not cover the bill, a credit limit is exceeded, or there is nothing on the order to pay for."},"409":{"description":"The order has already been paid, or is not a draft."}},"security":[{"bearer":[]}],"summary":"Pay a bill that was built up over time","tags":["Sales Orders"]}},"/api/v1/sales-orders/{id}/bill":{"get":{"description":"Prices an open order the way settle and table checkout will: items, their tax, and the shop service charge with the tax on it. Use it to show the total to collect; the server works it out again when paid.","operationId":"SalesOrderController_bill_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"discount","required":false,"in":"query","description":"A discount the till will take off the bill as a whole, so the service charge is worked out after it.","schema":{"example":"1000","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/BillPreviewDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"What a bill paid at the end comes to, before paying it","tags":["Sales Orders"]}},"/api/v1/sales-orders/{id}":{"get":{"operationId":"SalesOrderController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SalesOrderEntity"}}}]}}}},"404":{"description":"Sales order not found."}},"security":[{"bearer":[]}],"summary":"Get a sales order by ID","tags":["Sales Orders"]},"patch":{"operationId":"SalesOrderController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSalesOrderDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SalesOrderEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a sales order","tags":["Sales Orders"]},"delete":{"operationId":"SalesOrderController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SalesOrderEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a sales order","tags":["Sales Orders"]}},"/api/v1/sales-orders/{salesOrderId}/lines":{"post":{"operationId":"SalesOrderLineController_create_v1","parameters":[{"name":"salesOrderId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSalesOrderLineDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SalesOrderLineEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SalesOrderLineEntity"}}}},"409":{"description":"An item is marked unavailable (sold out for now). The message names it, e.g. \"Not available right now: Mohinga\"."}},"security":[{"bearer":[]}],"summary":"Create a new sales order line","tags":["Sales Order Lines"]},"get":{"operationId":"SalesOrderLineController_findAll_v1","parameters":[{"name":"salesOrderId","required":true,"in":"path","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SalesOrderLineEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all lines for a sales order","tags":["Sales Order Lines"]}},"/api/v1/sales-orders/{salesOrderId}/lines/{id}":{"get":{"operationId":"SalesOrderLineController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"salesOrderId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SalesOrderLineEntity"}}}]}}}},"404":{"description":"Sales order line not found."}},"security":[{"bearer":[]}],"summary":"Get a sales order line by ID","tags":["Sales Order Lines"]},"patch":{"operationId":"SalesOrderLineController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"salesOrderId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSalesOrderLineDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SalesOrderLineEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a sales order line","tags":["Sales Order Lines"]},"delete":{"operationId":"SalesOrderLineController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"salesOrderId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SalesOrderLineEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a sales order line","tags":["Sales Order Lines"]}},"/api/v1/sales-orders/{salesOrderId}/lines/{id}/fire":{"post":{"operationId":"SalesOrderLineController_fire_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"salesOrderId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SalesOrderLineEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SalesOrderLineEntity"}}}},"400":{"description":"Line is not in PENDING state."}},"security":[{"bearer":[]}],"summary":"Fire a line (PENDING → FIRED)","tags":["Sales Order Lines"]}},"/api/v1/sales-orders/{salesOrderId}/lines/{id}/ready":{"post":{"operationId":"SalesOrderLineController_ready_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"salesOrderId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SalesOrderLineEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SalesOrderLineEntity"}}}},"400":{"description":"Line is not in FIRED state."}},"security":[{"bearer":[]}],"summary":"Mark a line ready (FIRED → READY)","tags":["Sales Order Lines"]}},"/api/v1/sales-orders/{salesOrderId}/lines/{id}/serve":{"post":{"operationId":"SalesOrderLineController_serve_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"salesOrderId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SalesOrderLineEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SalesOrderLineEntity"}}}},"400":{"description":"Line is not in READY state."}},"security":[{"bearer":[]}],"summary":"Mark a line served (READY → SERVED)","tags":["Sales Order Lines"]}},"/api/v1/sales-orders/{salesOrderId}/lines/{id}/void":{"post":{"operationId":"SalesOrderLineController_voidLine_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"salesOrderId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoidLineDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SalesOrderLineEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SalesOrderLineEntity"}}}},"400":{"description":"Line is in a terminal state."}},"security":[{"bearer":[]}],"summary":"Void a line with a reason","tags":["Sales Order Lines"]}},"/api/v1/sales-orders/{salesOrderId}/lines/{id}/comp":{"post":{"operationId":"SalesOrderLineController_compLine_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"salesOrderId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompLineDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SalesOrderLineEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SalesOrderLineEntity"}}}},"400":{"description":"Line is in a terminal state."}},"security":[{"bearer":[]}],"summary":"Comp a line with a discount reason","tags":["Sales Order Lines"]}},"/api/v1/sales-orders/{salesOrderId}/payments":{"post":{"operationId":"OrderPaymentController_create_v1","parameters":[{"name":"salesOrderId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrderPaymentDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/OrderPaymentEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderPaymentEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new order payment","tags":["Order Payments"]},"get":{"operationId":"OrderPaymentController_findAll_v1","parameters":[{"name":"salesOrderId","required":true,"in":"path","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OrderPaymentEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all payments for a sales order","tags":["Order Payments"]}},"/api/v1/sales-orders/{salesOrderId}/payments/{id}":{"get":{"operationId":"OrderPaymentController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"salesOrderId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/OrderPaymentEntity"}}}]}}}},"404":{"description":"Order payment not found."}},"security":[{"bearer":[]}],"summary":"Get an order payment by ID","tags":["Order Payments"]},"patch":{"operationId":"OrderPaymentController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"salesOrderId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOrderPaymentDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/OrderPaymentEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update an order payment","tags":["Order Payments"]},"delete":{"operationId":"OrderPaymentController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"salesOrderId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/OrderPaymentEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete an order payment","tags":["Order Payments"]}},"/api/v1/checkout":{"post":{"description":"Creates the order and settles it in one call. Several entries in `payments` are a split tender. For a guest card, send the tapped card as `guestCardId` and leave `amount` out: only the server knows the tier discount, so the card covers whatever the bill comes to. At most one card tender may omit its amount. Paying on account is a payment method whose kind is CUSTOMER_CREDIT, plus `customerId` on the order. Reuse `idempotencyKey` when retrying after a network error and the original sale is returned rather than a second charge.","operationId":"CheckoutController_checkout_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/CheckoutResponseDto"}}}]}}}},"400":{"description":"Payments do not cover the bill, a credit limit is exceeded, stock is short, or a card tender omitted its amount alongside another that also did."},"404":{"description":"A variant, customer, payment method or guest card was not found."},"409":{"description":"The wallet behind the card is busy - being settled, or charged by another till. Safe to retry with the same idempotency key."},"422":{"description":"The card cannot pay: not active, expired, or short of the amount. Only a postpaid card may go negative."}},"security":[{"bearer":[]}],"summary":"Ring up a sale and take payment","tags":["Checkout"]}},"/api/v1/checkout/{id}/void":{"post":{"description":"Reverses the whole sale: stock goes back, loyalty points are taken back, and anything paid by guest card is credited to the wallet. Only a COMPLETED order can be voided - once any part has been refunded it has a history to keep, and a return is the way to undo it.","operationId":"CheckoutController_voidSale_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/CheckoutResponseDto"}}}]}}}},"404":{"description":"No COMPLETED order with that id in your tenant."}},"security":[{"bearer":[]}],"summary":"Void a completed sale","tags":["Checkout"]}},"/api/v1/receipts/{salesOrderId}":{"get":{"operationId":"ReceiptController_getReceipt_v1","parameters":[{"name":"salesOrderId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ReceiptResponseDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get receipt for a completed sale","tags":["Receipts"]}},"/api/v1/refunds":{"post":{"operationId":"RefundController_processReturn_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProcessReturnDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ReturnResponseDto"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReturnResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Process a return/refund","tags":["Refunds"]}},"/api/v1/refunds/{id}":{"get":{"operationId":"RefundController_getReturn_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ReturnResponseDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get return details by ID","tags":["Refunds"]}},"/api/v1/refunds/order/{salesOrderId}":{"get":{"operationId":"RefundController_getReturnsByOrder_v1","parameters":[{"name":"salesOrderId","required":true,"in":"path","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ReturnResponseDto"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List all returns for a sales order","tags":["Refunds"]}},"/api/v1/card-tiers":{"post":{"description":"Tiers are the hotel’s to define and change at any time. Editing one never affects cards already issued.","operationId":"CardTierController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCardTierDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/CardTierEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardTierEntity"}}}},"409":{"description":"A tier with that name already exists"}},"security":[{"bearer":[]}],"summary":"Create a card tier","tags":["Card Tiers"]},"get":{"operationId":"CardTierController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CardTierEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List card tiers","tags":["Card Tiers"]}},"/api/v1/card-tiers/{id}":{"get":{"operationId":"CardTierController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/CardTierEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get a card tier","tags":["Card Tiers"]},"patch":{"description":"Affects cards issued from now on. Balances and terms on existing cards are untouched, because a wallet keeps the terms it was sold on.","operationId":"CardTierController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCardTierDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/CardTierEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a card tier","tags":["Card Tiers"]},"delete":{"description":"Cards already issued against it keep working.","operationId":"CardTierController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/CardTierEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Retire a card tier","tags":["Card Tiers"]}},"/api/v1/guest-wallets":{"post":{"description":"Creates the wallet, links every card supplied, applies the tier preload and records the cash, all in one transaction. The tier’s terms are copied onto the wallet, so later edits to the tier leave this guest alone.","operationId":"GuestWalletController_issue_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IssueWalletDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/GuestWalletEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuestWalletEntity"}}}},"409":{"description":"One of those cards is already in use"}},"security":[{"bearer":[]}],"summary":"Issue a wallet and its cards","tags":["Guest Wallets"]},"get":{"description":"Filter by `customerId` for every card a customer has ever been issued.","operationId":"GuestWalletController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GuestWalletListItemDto"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List guest wallets","tags":["Guest Wallets"]}},"/api/v1/guest-wallets/{id}":{"get":{"operationId":"GuestWalletController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/GuestWalletEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get a guest wallet","tags":["Guest Wallets"]}},"/api/v1/guest-wallets/{id}/cards":{"get":{"description":"A KTV room may hand out several, all spending one balance.","operationId":"GuestWalletController_findCards_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/GuestCardEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Cards drawing on this wallet","tags":["Guest Wallets"]}},"/api/v1/guest-wallets/{id}/ledger":{"get":{"description":"Every movement, newest first. Append-only: nothing here is ever edited.","operationId":"GuestWalletController_findLedger_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WalletLedgerEntryEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Wallet statement","tags":["Guest Wallets"]}},"/api/v1/guest-wallets/{id}/audit":{"get":{"description":"Replays every entry and compares the result with the stored balance. Reports drift; never repairs it, because a silent correction would destroy the evidence that something wrote a wrong number.","operationId":"GuestWalletController_audit_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/WalletAuditDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Check a wallet against its ledger","tags":["Guest Wallets"]}},"/api/v1/guest-wallets/{id}/top-up":{"post":{"description":"Works on every tier. A mobile wallet transfer is refused without a reference.","operationId":"GuestWalletController_topUp_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopUpWalletDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/WalletLedgerEntryEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WalletLedgerEntryEntity"}}}},"409":{"description":"The wallet is being settled"}},"security":[{"bearer":[]}],"summary":"Add value to a wallet","tags":["Guest Wallets"]}},"/api/v1/guest-wallets/{id}/settlement-quote":{"get":{"description":"Read-only and safe to poll. Drive the checkout screen off `action` and `blockers` rather than re-deriving them from the balance.","operationId":"WalletSettlementController_quote_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SettlementQuoteDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"What closing this wallet would take","tags":["Guest Wallet Settlement"]}},"/api/v1/guest-wallets/{id}/begin-settlement":{"post":{"description":"Stops the card being spent while the desk counts the guest out. Without this their friend could buy a round at the bar mid-count, and the refund would be paid against a balance that had already moved.","operationId":"WalletSettlementController_begin_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/GuestWalletEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuestWalletEntity"}}}}},"security":[{"bearer":[]}],"summary":"Begin settling a wallet","tags":["Guest Wallet Settlement"]}},"/api/v1/guest-wallets/{id}/cancel-settlement":{"post":{"description":"For a guest who decides to stay after all.","operationId":"WalletSettlementController_cancel_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/GuestWalletEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuestWalletEntity"}}}}},"security":[{"bearer":[]}],"summary":"Return a wallet to spendable","tags":["Guest Wallet Settlement"]}},"/api/v1/guest-wallets/{id}/settle":{"post":{"description":"Forfeits promotional value, refunds the guest’s own money, collects what a postpaid card owes, retires the cards and closes the account - all at once. A wallet holding anything cannot close; the database refuses it outright.","operationId":"WalletSettlementController_settle_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"x-approver-authorization","in":"header","description":"The approving manager’s own bearer token, obtained by signing in on this terminal. Must be a different person from the one making the request.","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettleWalletDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/GuestWalletEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuestWalletEntity"}}}},"409":{"description":"The guest still has an open bill"},"422":{"description":"A postpaid card owes money that has not been collected"}},"security":[{"bearer":[]}],"summary":"Settle and close a wallet","tags":["Guest Wallet Settlement"]}},"/api/v1/guest-wallets/{id}/refund":{"post":{"description":"For a guest who wants cash back mid-stay and carries on spending. Only their own money can be returned - promotional value is never paid out - and never on a postpaid card, which is settled at checkout instead.","operationId":"WalletSettlementController_refund_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"x-approver-authorization","in":"header","description":"The approving manager’s own bearer token, obtained by signing in on this terminal. Must be a different person from the one making the request.","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefundWalletDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/GuestWalletEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuestWalletEntity"}}}},"422":{"description":"A postpaid card, or more than the card holds or the guest actually put in"}},"security":[{"bearer":[]}],"summary":"Hand back part of a balance without closing","tags":["Guest Wallet Settlement"]}},"/api/v1/guest-wallets/{id}/void":{"post":{"description":"Only while it is untouched. Anything else is a real history that has to be settled rather than erased.","operationId":"WalletSettlementController_voidWallet_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"x-approver-authorization","in":"header","description":"The approving manager’s own bearer token, obtained by signing in on this terminal. Must be a different person from the one making the request.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/GuestWalletEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuestWalletEntity"}}}}},"security":[{"bearer":[]}],"summary":"Void a wallet issued in error","tags":["Guest Wallet Settlement"]}},"/api/v1/guest-cards/lookup":{"get":{"description":"What a till calls when a card is tapped. Returns the card and the wallet it draws on, for display. Never decide affordability from this: the balance can change between the lookup and the tender, and the server rechecks under a lock.","operationId":"GuestCardController_lookup_v1","parameters":[{"name":"cardUid","required":true,"in":"query","schema":{"example":"04A3B2C1","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/GuestCardEntity"}}}]}}}},"404":{"description":"No active card with that UID"}},"security":[{"bearer":[]}],"summary":"Look up a card by its UID","tags":["Guest Cards"]}},"/api/v1/guest-cards":{"post":{"description":"For a room where several guests each carry a card on one balance.","operationId":"GuestCardController_link_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkCardDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/GuestCardEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuestCardEntity"}}}},"409":{"description":"That card is already active elsewhere"}},"security":[{"bearer":[]}],"summary":"Link another card to a wallet","tags":["Guest Cards"]},"get":{"operationId":"GuestCardController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GuestCardListItemDto"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List guest cards","tags":["Guest Cards"]}},"/api/v1/guest-cards/{id}":{"get":{"operationId":"GuestCardController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/GuestCardEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get a guest card","tags":["Guest Cards"]},"delete":{"description":"Used at checkout. Frees the UID for the next guest.","operationId":"GuestCardController_deactivate_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/GuestCardEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Take a card out of use","tags":["Guest Cards"]}},"/api/v1/guest-cards/{id}/report-lost":{"post":{"description":"Stops the card paying immediately. It does NOT cancel the room key - the door lock is a separate system and must be cancelled there too, or the card still opens the room.","operationId":"GuestCardController_reportLost_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/GuestCardEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuestCardEntity"}}}}},"security":[{"bearer":[]}],"summary":"Report a card lost","tags":["Guest Cards"]}},"/api/v1/guest-cards/{id}/replace":{"post":{"description":"Issues a new card on the same wallet. The balance is untouched and no ledger entry is written, because the money was never on the card.","operationId":"GuestCardController_replace_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplaceCardDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/GuestCardEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuestCardEntity"}}}}},"security":[{"bearer":[]}],"summary":"Replace a lost card","tags":["Guest Cards"]}},"/api/v1/reports/guest-card/daily-cash":{"get":{"description":"Deposits and sales are reported side by side and never summed. A top-up is money held for a guest, not money earned; adding them together tells a property it made revenue it has merely been handed.","operationId":"GuestCardReportController_dailyCash_v1","parameters":[{"name":"locationId","required":false,"in":"query","schema":{}},{"name":"businessDate","required":false,"in":"query","schema":{"example":"2026-09-12"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/DailyCashReportDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Cash in and out for a day","tags":["Guest Card Reports"]}},"/api/v1/reports/guest-card/revenue":{"get":{"description":"Recognised when a guest spends, not when they pay in. Top-ups cannot appear here: they have no sales order to be counted against.","operationId":"GuestCardReportController_revenue_v1","parameters":[{"name":"locationId","required":false,"in":"query","schema":{}},{"name":"to","required":false,"in":"query","schema":{"example":"2026-09-12"}},{"name":"from","required":false,"in":"query","schema":{"example":"2026-09-01"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OutletRevenueRowDto"}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Revenue by outlet","tags":["Guest Card Reports"]}},"/api/v1/reports/guest-card/liability":{"get":{"description":"The balance-sheet number, split by funding. Purchased value is a real debt that leaves in cash at checkout; granted value is a marketing cost that is mostly forfeited.","operationId":"GuestCardReportController_liability_v1","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/OutstandingLiabilityDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Unspent guest money","tags":["Guest Card Reports"]}},"/api/v1/reports/guest-card/open-wallets":{"get":{"description":"With ages. A wallet open a month is not a guest still here - it is an account somebody forgot to close.","operationId":"GuestCardReportController_openWallets_v1","parameters":[{"name":"olderThanDays","required":false,"in":"query","schema":{"example":7}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OpenWalletRowDto"}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Wallets still open","tags":["Guest Card Reports"]}},"/api/v1/reports/guest-card/negative-balances":{"get":{"description":"Must be empty before those guests leave, which is why a negative wallet cannot be closed.","operationId":"GuestCardReportController_negativeBalances_v1","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/NegativeBalanceRowDto"}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Postpaid cards in debt","tags":["Guest Card Reports"]}},"/api/v1/reports/guest-card/refunds":{"get":{"description":"Grouped by both. One cashier’s refunds are a workload; the same cashier and the same approver together, repeatedly, is a pattern worth looking at.","operationId":"GuestCardReportController_refunds_v1","parameters":[{"name":"to","required":false,"in":"query","schema":{"example":"2026-09-12"}},{"name":"from","required":false,"in":"query","schema":{"example":"2026-09-01"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/RefundsByStaffRowDto"}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Refunds by staff and approver","tags":["Guest Card Reports"]}},"/api/v1/reports/guest-card/tier-usage":{"get":{"operationId":"GuestCardReportController_tierUsage_v1","parameters":[{"name":"to","required":false,"in":"query","schema":{"example":"2026-09-12"}},{"name":"from","required":false,"in":"query","schema":{"example":"2026-09-01"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TierUsageRowDto"}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Spending by tier, as the cards were sold","tags":["Guest Card Reports"]}},"/api/v1/reports/guest-card/lost-cards":{"get":{"operationId":"GuestCardReportController_lostCards_v1","parameters":[{"name":"from","required":false,"in":"query","description":"An instant, not a business date: cards are deactivated by clock.","schema":{"example":"2026-09-01T00:00:00.000Z"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/LostCardRowDto"}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Lost cards and their replacements","tags":["Guest Card Reports"]}},"/api/v1/reports/guest-card/shift-reconciliation":{"get":{"description":"Expected cash counts top-ups and refunds as well as sales, because those notes are in the same drawer. Flags any closed session whose variance was never approved.","operationId":"GuestCardReportController_shiftReconciliation_v1","parameters":[{"name":"businessDate","required":false,"in":"query","schema":{}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ShiftReconciliationRowDto"}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Shift reconciliation","tags":["Guest Card Reports"]}},"/api/v1/reports/guest-card/audit":{"get":{"description":"Every ledger entry summed must equal every wallet balance summed, each wallet must replay to its cached balance with a gap-free sequence, and each entry must follow from the one before. Records what does not add up and never repairs it - a silent correction destroys the evidence. A system admin gets one result per tenant, because the equation has to hold in each hotel on its own.","operationId":"GuestCardReportController_runAudit_v1","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TenantAuditResultDto"}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Run the audit equation","tags":["Guest Card Reports"]}},"/api/v1/reports/guest-card/discrepancies":{"get":{"operationId":"GuestCardReportController_discrepancies_v1","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/LedgerDiscrepancyDto"}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Discrepancies nobody has dealt with yet","tags":["Guest Card Reports"]}},"/api/v1/reports/guest-card/discrepancies/{id}/resolve":{"post":{"description":"Records that somebody understood it. Correcting the balance itself is a separate adjustment entry needing a manager’s approval.","operationId":"GuestCardReportController_resolve_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ResolveDiscrepancyResultDto"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"bearer":[]}],"summary":"Mark a discrepancy dealt with","tags":["Guest Card Reports"]}},"/api/v1/pos-registers":{"post":{"operationId":"PosRegisterController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePosRegisterDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PosRegisterEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Create a new POS register","tags":["POS Registers"]},"get":{"operationId":"PosRegisterController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PosRegisterEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all POS registers","tags":["POS Registers"]}},"/api/v1/pos-registers/{id}":{"get":{"operationId":"PosRegisterController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PosRegisterEntity"}}}]}}}},"404":{"description":"POS register not found."}},"security":[{"bearer":[]}],"summary":"Get a POS register by ID","tags":["POS Registers"]},"patch":{"operationId":"PosRegisterController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePosRegisterDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PosRegisterEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a POS register","tags":["POS Registers"]},"delete":{"operationId":"PosRegisterController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PosRegisterEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a POS register","tags":["POS Registers"]}},"/api/v1/pos-registers/{id}/printers":{"get":{"description":"The checkout and finance printers for this register. A sector with no printers assigned falls back to the outlet's active printers in it.","operationId":"PosRegisterController_findPrinters_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/RegisterPrintersDto"}}}]}}}},"404":{"description":"POS register not found."}},"security":[{"bearer":[]}],"summary":"Where this till prints","tags":["POS Registers"]}},"/api/v1/pos-sessions":{"post":{"description":"Opens a shift on a till with the cash counted into the drawer. The cashier is whoever is signed in. A till has one open shift at a time (409 otherwise).","operationId":"PosSessionController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePosSessionDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PosSessionEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PosSessionEntity"}}}}},"security":[{"bearer":[]}],"summary":"Open a shift","tags":["POS Sessions"]},"get":{"description":"Each shift with its till and cashier names, and what it sold: totalSales, totalRefunds, netTotal and salesCount - the same figures as its summary.","operationId":"PosSessionController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PosSessionEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List shifts, newest first","tags":["POS Sessions"]}},"/api/v1/pos-sessions/current":{"get":{"description":"Null shift: none open. A daily shift is due a day after it opened and takes no money once overdue, until it is closed.","operationId":"PosSessionController_current_v1","parameters":[{"name":"registerId","required":true,"in":"query","description":"The till","schema":{"format":"uuid","example":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/CurrentShiftDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"The shift open on a till","tags":["POS Sessions"]}},"/api/v1/pos-sessions/{id}":{"get":{"operationId":"PosSessionController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PosSessionEntity"}}}]}}}},"404":{"description":"POS session not found."}},"security":[{"bearer":[]}],"summary":"Get a POS session by ID","tags":["POS Sessions"]},"patch":{"operationId":"PosSessionController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePosSessionDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PosSessionEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a POS session","tags":["POS Sessions"]},"delete":{"operationId":"PosSessionController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PosSessionEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a POS session","tags":["POS Sessions"]}},"/api/v1/pos-sessions/{id}/close":{"post":{"description":"Returns the shift report. Without actualClosingCash the shift just closes. With it, the count is set against the expected cash; a drawer that does not balance needs a manager to sign it off, and who signed it is recorded.","operationId":"PosSessionController_closeSession_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"x-approver-authorization","in":"header","description":"A manager’s own bearer token. Required only when the counted cash differs from the expected figure.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClosePosSessionDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/EndOfDaySummaryDto"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EndOfDaySummaryDto"}}}},"422":{"description":"The till is out and nobody has approved the difference"}},"security":[{"bearer":[]}],"summary":"Close a shift, with or without a cash count","tags":["POS Sessions"]}},"/api/v1/pos-sessions/{id}/summary":{"get":{"operationId":"PosSessionController_getSessionSummary_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/EndOfDaySummaryDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get POS session summary (sales, refunds, payment breakdown)","tags":["POS Sessions"]}},"/api/v1/payment-methods":{"post":{"operationId":"PaymentMethodController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePaymentMethodDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PaymentMethodEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentMethodEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new payment method","tags":["Payment Methods"]},"get":{"operationId":"PaymentMethodController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PaymentMethodEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all payment methods","tags":["Payment Methods"]}},"/api/v1/payment-methods/{id}":{"get":{"operationId":"PaymentMethodController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PaymentMethodEntity"}}}]}}}},"404":{"description":"Payment method not found."}},"security":[{"bearer":[]}],"summary":"Get a payment method by ID","tags":["Payment Methods"]},"patch":{"operationId":"PaymentMethodController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePaymentMethodDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PaymentMethodEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a payment method","tags":["Payment Methods"]},"delete":{"operationId":"PaymentMethodController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PaymentMethodEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a payment method","tags":["Payment Methods"]}},"/api/v1/cash-movements":{"post":{"description":"Paid-ins, paid-outs, drops and float corrections. These count towards the expected cash at shift close but never towards sales, because they are not trade.","operationId":"CashMovementController_record_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordCashMovementDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/CashMovementEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CashMovementEntity"}}}}},"security":[{"bearer":[]}],"summary":"Record money in or out of a till","tags":["Cash Movements"]},"get":{"operationId":"CashMovementController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CashMovementEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List cash movements","tags":["Cash Movements"]}},"/api/v1/cash-movements/{id}":{"get":{"operationId":"CashMovementController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/CashMovementEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get a cash movement","tags":["Cash Movements"]}},"/api/v1/outlet-settings":{"get":{"description":"Only outlets that have a row. An outlet missing from this list is one whose service charge is still whatever the till sends.","operationId":"OutletSettingController_findAll_v1","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OutletSettingWithLocationDto"}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List outlet settings","tags":["Outlet Settings"]}},"/api/v1/outlet-settings/{locationId}":{"get":{"operationId":"OutletSettingController_findOne_v1","parameters":[{"name":"locationId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/OutletSettingDto"}}}]}}}},"404":{"description":"That outlet has no row, so the till’s figure still stands"}},"security":[{"bearer":[]}],"summary":"Get one outlet’s settings","tags":["Outlet Settings"]},"put":{"description":"Creating a row makes the server authoritative for that outlet’s service charge, which until now has been an unvalidated number sent by the till. Outlets with no row keep behaving exactly as they do today.","operationId":"OutletSettingController_upsert_v1","parameters":[{"name":"locationId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertOutletSettingDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/OutletSettingDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Set an outlet’s commercial configuration","tags":["Outlet Settings"]},"delete":{"description":"Hands the service charge back to whatever the till sends. Rarely what you want; set the rate to zero instead.","operationId":"OutletSettingController_remove_v1","parameters":[{"name":"locationId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/OutletSettingDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Remove an outlet’s settings","tags":["Outlet Settings"]}},"/api/v1/promotion-rules":{"post":{"description":"A discount the server applies by itself wherever items are sold (counter, tables, SPA, KTV, room tablet) while it runs. Set what it applies to (whole menu, categories with their sub-categories, or items), which POS and outlets, and when (dates, days, a daily time window).","operationId":"PromotionController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePromotionDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PromotionEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Create a promotion","tags":["Promotions"]},"get":{"operationId":"PromotionController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Name contains","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}},{"name":"activeOnly","required":false,"in":"query","description":"true: only switched on","schema":{"type":"boolean"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PromotionEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List promotions","tags":["Promotions"]}},"/api/v1/promotion-rules/running":{"get":{"description":"For the POS to show. Open to any signed-in user. The server applies them by itself; the POS does not send discounts for them.","operationId":"PromotionController_running_v1","parameters":[{"name":"locationId","required":false,"in":"query","description":"The outlet selling.","schema":{"format":"uuid","example":"uuid","type":"string"}},{"name":"posType","required":true,"in":"query","schema":{"example":"BAR","type":"string","enum":["BAR","SPA","KTV"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PromotionEntity"}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Promotions running now at a till","tags":["Promotions"]}},"/api/v1/promotion-rules/preview":{"post":{"description":"What promotions would take off these items if sold now, for the cart screen. Writes nothing. Open to any signed-in user.","operationId":"PromotionController_preview_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromotionPreviewDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PromotionPreviewResultDto"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromotionPreviewResultDto"}}}}},"security":[{"bearer":[]}],"summary":"Preview the discount on items","tags":["Promotions"]}},"/api/v1/promotion-rules/{id}":{"get":{"operationId":"PromotionController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PromotionEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get a promotion","tags":["Promotions"]},"patch":{"operationId":"PromotionController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePromotionDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PromotionEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Change a promotion","tags":["Promotions"]},"delete":{"description":"Retired, not erased: past sales still show what it took off.","operationId":"PromotionController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PromotionEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Remove a promotion","tags":["Promotions"]}},"/api/v1/inventory-ledger":{"post":{"operationId":"InventoryLedgerController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateInventoryLedgerDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/InventoryLedgerEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryLedgerEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new inventory ledger entry","tags":["Inventory Ledger"]},"get":{"operationId":"InventoryLedgerController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/InventoryLedgerEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all inventory ledger entries","tags":["Inventory Ledger"]}},"/api/v1/inventory-ledger/expiring":{"get":{"operationId":"InventoryLedgerController_findExpiring_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}},{"name":"days","required":false,"in":"query","description":"Number of days to look ahead for expiring stock","schema":{"minimum":1,"default":30,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/InventoryLedgerEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get stock expiring within N days","tags":["Inventory Ledger"]}},"/api/v1/inventory-ledger/write-off":{"post":{"operationId":"InventoryLedgerController_writeOff_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteOffInventoryDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/InventoryLedgerEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryLedgerEntity"}}}}},"security":[{"bearer":[]}],"summary":"Write off expired or damaged stock","tags":["Inventory Ledger"]}},"/api/v1/inventory-ledger/balance/{variantId}/{locationId}":{"get":{"operationId":"InventoryLedgerController_getBalance_v1","parameters":[{"name":"variantId","required":true,"in":"path","schema":{"type":"string"}},{"name":"locationId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/InventoryBalanceDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get inventory balance for a variant at a location","tags":["Inventory Ledger"]}},"/api/v1/inventory-ledger/{id}":{"get":{"operationId":"InventoryLedgerController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/InventoryLedgerEntity"}}}]}}}},"404":{"description":"Inventory ledger entry not found."}},"security":[{"bearer":[]}],"summary":"Get an inventory ledger entry by ID","tags":["Inventory Ledger"]},"delete":{"operationId":"InventoryLedgerController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/InventoryLedgerEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete an inventory ledger entry","tags":["Inventory Ledger"]}},"/api/v1/exchange-rates":{"post":{"operationId":"ExchangeRateController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateExchangeRateDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ExchangeRateEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExchangeRateEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new exchange rate","tags":["Exchange Rates"]},"get":{"operationId":"ExchangeRateController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ExchangeRateEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all exchange rates","tags":["Exchange Rates"]}},"/api/v1/exchange-rates/{id}":{"get":{"operationId":"ExchangeRateController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ExchangeRateEntity"}}}]}}}},"404":{"description":"Exchange rate not found."}},"security":[{"bearer":[]}],"summary":"Get an exchange rate by ID","tags":["Exchange Rates"]},"patch":{"operationId":"ExchangeRateController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateExchangeRateDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ExchangeRateEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update an exchange rate","tags":["Exchange Rates"]},"delete":{"operationId":"ExchangeRateController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ExchangeRateEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete an exchange rate","tags":["Exchange Rates"]}},"/api/v1/tax-rates":{"post":{"operationId":"TaxRateController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTaxRateDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TaxRateEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaxRateEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new tax rate","tags":["Tax Rates"]},"get":{"operationId":"TaxRateController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TaxRateEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all tax rates","tags":["Tax Rates"]}},"/api/v1/tax-rates/{id}":{"get":{"operationId":"TaxRateController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TaxRateEntity"}}}]}}}},"404":{"description":"Tax rate not found."}},"security":[{"bearer":[]}],"summary":"Get a tax rate by ID","tags":["Tax Rates"]},"patch":{"operationId":"TaxRateController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTaxRateDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TaxRateEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a tax rate","tags":["Tax Rates"]},"delete":{"operationId":"TaxRateController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TaxRateEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a tax rate","tags":["Tax Rates"]}},"/api/v1/accounting-periods":{"post":{"operationId":"AccountingPeriodController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAccountingPeriodDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/AccountingPeriodEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountingPeriodEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new accounting period","tags":["Accounting Periods"]},"get":{"operationId":"AccountingPeriodController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AccountingPeriodEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all accounting periods","tags":["Accounting Periods"]}},"/api/v1/accounting-periods/{id}":{"get":{"operationId":"AccountingPeriodController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/AccountingPeriodEntity"}}}]}}}},"404":{"description":"Accounting period not found."}},"security":[{"bearer":[]}],"summary":"Get an accounting period by ID","tags":["Accounting Periods"]},"patch":{"operationId":"AccountingPeriodController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAccountingPeriodDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/AccountingPeriodEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update an accounting period","tags":["Accounting Periods"]},"delete":{"operationId":"AccountingPeriodController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/AccountingPeriodEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete an accounting period","tags":["Accounting Periods"]}},"/api/v1/chart-of-accounts":{"post":{"operationId":"ChartOfAccountController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateChartOfAccountDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ChartOfAccountEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChartOfAccountEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new chart of account","tags":["Chart of Accounts"]},"get":{"operationId":"ChartOfAccountController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ChartOfAccountEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all chart of accounts","tags":["Chart of Accounts"]}},"/api/v1/chart-of-accounts/{id}":{"get":{"operationId":"ChartOfAccountController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ChartOfAccountEntity"}}}]}}}},"404":{"description":"Chart of account not found."}},"security":[{"bearer":[]}],"summary":"Get a chart of account by ID","tags":["Chart of Accounts"]},"patch":{"operationId":"ChartOfAccountController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateChartOfAccountDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ChartOfAccountEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a chart of account","tags":["Chart of Accounts"]},"delete":{"operationId":"ChartOfAccountController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ChartOfAccountEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a chart of account","tags":["Chart of Accounts"]}},"/api/v1/journal-entries":{"post":{"operationId":"JournalEntryController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateJournalEntryDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/JournalEntryEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JournalEntryEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new journal entry","tags":["Journal Entries"]},"get":{"operationId":"JournalEntryController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/JournalEntryEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all journal entries","tags":["Journal Entries"]}},"/api/v1/journal-entries/{id}":{"get":{"operationId":"JournalEntryController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/JournalEntryEntity"}}}]}}}},"404":{"description":"Journal entry not found."}},"security":[{"bearer":[]}],"summary":"Get a journal entry by ID","tags":["Journal Entries"]},"patch":{"operationId":"JournalEntryController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateJournalEntryDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/JournalEntryEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a journal entry","tags":["Journal Entries"]},"delete":{"operationId":"JournalEntryController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/JournalEntryEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a journal entry","tags":["Journal Entries"]}},"/api/v1/journal-entries/{journalEntryId}/lines":{"post":{"operationId":"JournalLineController_create_v1","parameters":[{"name":"journalEntryId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateJournalLineDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/JournalLineEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JournalLineEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new journal line","tags":["Journal Lines"]},"get":{"operationId":"JournalLineController_findAll_v1","parameters":[{"name":"journalEntryId","required":true,"in":"path","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/JournalLineEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all lines for a journal entry","tags":["Journal Lines"]}},"/api/v1/journal-entries/{journalEntryId}/lines/{id}":{"get":{"operationId":"JournalLineController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"journalEntryId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/JournalLineEntity"}}}]}}}},"404":{"description":"Journal line not found."}},"security":[{"bearer":[]}],"summary":"Get a journal line by ID","tags":["Journal Lines"]},"patch":{"operationId":"JournalLineController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"journalEntryId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateJournalLineDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/JournalLineEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a journal line","tags":["Journal Lines"]},"delete":{"operationId":"JournalLineController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"journalEntryId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/JournalLineEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a journal line","tags":["Journal Lines"]}},"/api/v1/bank-statements":{"post":{"operationId":"BankStatementController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBankStatementDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/BankStatementEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BankStatementEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new bank statement","tags":["Bank Statements"]},"get":{"operationId":"BankStatementController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/BankStatementEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all bank statements","tags":["Bank Statements"]}},"/api/v1/bank-statements/{id}":{"get":{"operationId":"BankStatementController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/BankStatementEntity"}}}]}}}},"404":{"description":"Bank statement not found."}},"security":[{"bearer":[]}],"summary":"Get a bank statement by ID","tags":["Bank Statements"]},"patch":{"operationId":"BankStatementController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBankStatementDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/BankStatementEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a bank statement","tags":["Bank Statements"]},"delete":{"operationId":"BankStatementController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/BankStatementEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a bank statement","tags":["Bank Statements"]}},"/api/v1/bank-statements/{bankStatementId}/lines":{"post":{"operationId":"BankStatementLineController_create_v1","parameters":[{"name":"bankStatementId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBankStatementLineDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/BankStatementLineEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BankStatementLineEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new bank statement line","tags":["Bank Statement Lines"]},"get":{"operationId":"BankStatementLineController_findAll_v1","parameters":[{"name":"bankStatementId","required":true,"in":"path","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/BankStatementLineEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all lines for a bank statement","tags":["Bank Statement Lines"]}},"/api/v1/bank-statements/{bankStatementId}/lines/{id}":{"get":{"operationId":"BankStatementLineController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"bankStatementId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/BankStatementLineEntity"}}}]}}}},"404":{"description":"Bank statement line not found."}},"security":[{"bearer":[]}],"summary":"Get a bank statement line by ID","tags":["Bank Statement Lines"]},"patch":{"operationId":"BankStatementLineController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"bankStatementId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBankStatementLineDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/BankStatementLineEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a bank statement line","tags":["Bank Statement Lines"]},"delete":{"operationId":"BankStatementLineController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"bankStatementId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/BankStatementLineEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a bank statement line","tags":["Bank Statement Lines"]}},"/api/v1/reconciliation-matches":{"post":{"operationId":"ReconciliationMatchController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReconciliationMatchDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ReconciliationMatchEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReconciliationMatchEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new reconciliation match","tags":["Reconciliation Matches"]},"get":{"operationId":"ReconciliationMatchController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ReconciliationMatchEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all reconciliation matches","tags":["Reconciliation Matches"]}},"/api/v1/reconciliation-matches/{id}":{"get":{"operationId":"ReconciliationMatchController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ReconciliationMatchEntity"}}}]}}}},"404":{"description":"Reconciliation match not found."}},"security":[{"bearer":[]}],"summary":"Get a reconciliation match by ID","tags":["Reconciliation Matches"]},"patch":{"operationId":"ReconciliationMatchController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateReconciliationMatchDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ReconciliationMatchEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a reconciliation match","tags":["Reconciliation Matches"]},"delete":{"operationId":"ReconciliationMatchController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ReconciliationMatchEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a reconciliation match","tags":["Reconciliation Matches"]}},"/api/v1/fixed-assets":{"post":{"operationId":"FixedAssetController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFixedAssetDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/FixedAssetEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FixedAssetEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new fixed asset","tags":["Fixed Assets"]},"get":{"operationId":"FixedAssetController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/FixedAssetEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all fixed assets","tags":["Fixed Assets"]}},"/api/v1/fixed-assets/{id}":{"get":{"operationId":"FixedAssetController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/FixedAssetEntity"}}}]}}}},"404":{"description":"Fixed asset not found."}},"security":[{"bearer":[]}],"summary":"Get a fixed asset by ID","tags":["Fixed Assets"]},"patch":{"operationId":"FixedAssetController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFixedAssetDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/FixedAssetEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a fixed asset","tags":["Fixed Assets"]},"delete":{"operationId":"FixedAssetController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/FixedAssetEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a fixed asset","tags":["Fixed Assets"]}},"/api/v1/fixed-assets/{fixedAssetId}/depreciation-schedules":{"post":{"operationId":"DepreciationScheduleController_create_v1","parameters":[{"name":"fixedAssetId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDepreciationScheduleDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/DepreciationScheduleEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DepreciationScheduleEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a new depreciation schedule","tags":["Depreciation Schedules"]},"get":{"operationId":"DepreciationScheduleController_findAll_v1","parameters":[{"name":"fixedAssetId","required":true,"in":"path","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DepreciationScheduleEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all depreciation schedules for a fixed asset","tags":["Depreciation Schedules"]}},"/api/v1/fixed-assets/{fixedAssetId}/depreciation-schedules/{id}":{"get":{"operationId":"DepreciationScheduleController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"fixedAssetId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/DepreciationScheduleEntity"}}}]}}}},"404":{"description":"Depreciation schedule not found."}},"security":[{"bearer":[]}],"summary":"Get a depreciation schedule by ID","tags":["Depreciation Schedules"]},"patch":{"operationId":"DepreciationScheduleController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"fixedAssetId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDepreciationScheduleDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/DepreciationScheduleEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a depreciation schedule","tags":["Depreciation Schedules"]},"delete":{"operationId":"DepreciationScheduleController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"fixedAssetId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/DepreciationScheduleEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a depreciation schedule","tags":["Depreciation Schedules"]}},"/api/v1/uploads":{"get":{"operationId":"UploadController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}},{"name":"folder","required":false,"in":"query","description":"Filter by folder","schema":{"type":"string"}},{"name":"branchId","required":false,"in":"query","description":"Filter by branch ID","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/UploadResponseDto"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get all uploaded files with pagination","tags":["Uploads"]},"post":{"operationId":"UploadController_uploadFile_v1","parameters":[{"name":"folder","required":false,"in":"query","description":"Subfolder to store the file","schema":{"example":"products","type":"string"}},{"name":"branchId","required":false,"in":"query","description":"Branch ID (defaults to user branch)","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}},"required":["file"]}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/UploadResponseDto"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Upload a single file","tags":["Uploads"]}},"/api/v1/uploads/multiple":{"post":{"operationId":"UploadController_uploadFiles_v1","parameters":[{"name":"folder","required":false,"in":"query","schema":{"type":"string"}},{"name":"branchId","required":false,"in":"query","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"files":{"type":"array","items":{"type":"string","format":"binary"}}},"required":["files"]}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/UploadResponseDto"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UploadResponseDto"}}}}}},"security":[{"bearer":[]}],"summary":"Upload multiple files (max 10)","tags":["Uploads"]}},"/api/v1/uploads/{id}":{"delete":{"operationId":"UploadController_deleteFile_v1","parameters":[{"name":"id","required":true,"in":"path","description":"Upload record ID","schema":{"type":"string"}}],"responses":{"200":{"description":"File deleted successfully.","content":{"application/json":{"schema":{"properties":{"message":{"type":"string","example":"File deleted successfully"}}}}}}},"security":[{"bearer":[]}],"summary":"Delete an uploaded file by ID","tags":["Uploads"]}},"/api/v1/modifier-groups":{"post":{"operationId":"ModifierGroupController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateModifierGroupDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ModifierGroupEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModifierGroupEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a modifier group","tags":["Modifier Groups"]},"get":{"operationId":"ModifierGroupController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ModifierGroupEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List modifier groups (paginated)","tags":["Modifier Groups"]}},"/api/v1/modifier-groups/{id}":{"get":{"operationId":"ModifierGroupController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ModifierGroupEntity"}}}]}}}},"404":{"description":"Modifier group not found."}},"security":[{"bearer":[]}],"summary":"Get a modifier group by ID","tags":["Modifier Groups"]},"patch":{"operationId":"ModifierGroupController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateModifierGroupDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ModifierGroupEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a modifier group","tags":["Modifier Groups"]},"delete":{"operationId":"ModifierGroupController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ModifierGroupEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a modifier group","tags":["Modifier Groups"]}},"/api/v1/modifier-groups/{id}/products":{"post":{"operationId":"ModifierGroupController_attachToProduct_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachModifierGroupDto"}}}},"responses":{"204":{"description":"Attached."}},"security":[{"bearer":[]}],"summary":"Attach a modifier group to a product","tags":["Modifier Groups"]}},"/api/v1/modifier-groups/{id}/products/{productId}":{"delete":{"operationId":"ModifierGroupController_detachFromProduct_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"productId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":"Detached."}},"security":[{"bearer":[]}],"summary":"Detach a modifier group from a product","tags":["Modifier Groups"]}},"/api/v1/modifier-groups/{groupId}/modifiers":{"post":{"operationId":"ModifierController_create_v1","parameters":[{"name":"groupId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateModifierDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ModifierEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModifierEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a modifier within a group","tags":["Modifiers"]},"get":{"operationId":"ModifierController_findAll_v1","parameters":[{"name":"groupId","required":true,"in":"path","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ModifierEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List modifiers in a group","tags":["Modifiers"]}},"/api/v1/modifier-groups/{groupId}/modifiers/{id}":{"get":{"operationId":"ModifierController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ModifierEntity"}}}]}}}},"404":{"description":"Modifier not found."}},"security":[{"bearer":[]}],"summary":"Get a modifier by ID","tags":["Modifiers"]},"patch":{"operationId":"ModifierController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateModifierDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ModifierEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a modifier","tags":["Modifiers"]},"delete":{"operationId":"ModifierController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ModifierEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a modifier","tags":["Modifiers"]}},"/api/v1/recipes":{"post":{"operationId":"RecipeController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRecipeDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/RecipeEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a recipe (with ingredients)","tags":["Recipes"]},"get":{"operationId":"RecipeController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/RecipeEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List recipes (paginated)","tags":["Recipes"]}},"/api/v1/recipes/by-variant/{variantId}":{"get":{"operationId":"RecipeController_findByVariant_v1","parameters":[{"name":"variantId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/RecipeEntity"}}}]}}}},"404":{"description":"Recipe not found."}},"security":[{"bearer":[]}],"summary":"Get the recipe for a specific variant","tags":["Recipes"]}},"/api/v1/recipes/{id}":{"get":{"operationId":"RecipeController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/RecipeEntity"}}}]}}}},"404":{"description":"Recipe not found."}},"security":[{"bearer":[]}],"summary":"Get a recipe by ID","tags":["Recipes"]},"patch":{"operationId":"RecipeController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRecipeDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/RecipeEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a recipe (and optionally replace ingredients)","tags":["Recipes"]},"delete":{"operationId":"RecipeController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/RecipeEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a recipe","tags":["Recipes"]}},"/api/v1/bundles":{"post":{"operationId":"BundleController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBundleDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/BundleEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BundleEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a bundle (combo) with components","tags":["Bundles"]},"get":{"operationId":"BundleController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/BundleEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List bundles (paginated)","tags":["Bundles"]}},"/api/v1/bundles/{id}":{"get":{"operationId":"BundleController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/BundleEntity"}}}]}}}},"404":{"description":"Bundle not found."}},"security":[{"bearer":[]}],"summary":"Get a bundle by ID","tags":["Bundles"]},"patch":{"operationId":"BundleController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBundleDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/BundleEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a bundle (and optionally replace components)","tags":["Bundles"]},"delete":{"operationId":"BundleController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/BundleEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a bundle","tags":["Bundles"]}},"/api/v1/pricing-schedules":{"post":{"operationId":"PricingScheduleController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePricingScheduleDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PricingScheduleEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PricingScheduleEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a pricing schedule (with rules)","tags":["Pricing Schedules"]},"get":{"operationId":"PricingScheduleController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PricingScheduleEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List pricing schedules (paginated)","tags":["Pricing Schedules"]}},"/api/v1/pricing-schedules/{id}":{"get":{"operationId":"PricingScheduleController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PricingScheduleEntity"}}}]}}}},"404":{"description":"Pricing schedule not found."}},"security":[{"bearer":[]}],"summary":"Get a pricing schedule by ID","tags":["Pricing Schedules"]},"patch":{"operationId":"PricingScheduleController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePricingScheduleDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PricingScheduleEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a pricing schedule (and optionally replace rules)","tags":["Pricing Schedules"]},"delete":{"operationId":"PricingScheduleController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PricingScheduleEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a pricing schedule","tags":["Pricing Schedules"]}},"/api/v1/dining-zones":{"post":{"operationId":"DiningZoneController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDiningZoneDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/DiningZoneEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiningZoneEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a dining zone","tags":["Dining Zones"]},"get":{"operationId":"DiningZoneController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DiningZoneEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List dining zones (paginated)","tags":["Dining Zones"]}},"/api/v1/dining-zones/{id}":{"get":{"operationId":"DiningZoneController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/DiningZoneEntity"}}}]}}}},"404":{"description":"Dining zone not found."}},"security":[{"bearer":[]}],"summary":"Get a dining zone by ID","tags":["Dining Zones"]},"patch":{"operationId":"DiningZoneController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDiningZoneDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/DiningZoneEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a dining zone","tags":["Dining Zones"]},"delete":{"operationId":"DiningZoneController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/DiningZoneEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a dining zone","tags":["Dining Zones"]}},"/api/v1/dining-tables":{"post":{"operationId":"DiningTableController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDiningTableDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/DiningTableEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiningTableEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a dining table","tags":["Dining Tables"]},"get":{"description":"Drives the floor plan: every table with its layout, plus `activeSession` carrying the guest count, units ordered and seated duration for the ones in service. `activeSession` is null when nobody is seated. `itemCount` is units, not lines - voided lines are left out, comped lines counted. Tick a live duration badge from `openedAt`; `seatedSeconds` is only the value at the moment the response was built.","operationId":"DiningTableController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}},{"name":"zoneId","required":false,"in":"query","description":"Filter by zone","schema":{"format":"uuid","type":"string"}},{"name":"status","required":false,"in":"query","schema":{"type":"string","enum":["AVAILABLE","OCCUPIED","DIRTY","RESERVED"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DiningTableEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List dining tables (paginated)","tags":["Dining Tables"]}},"/api/v1/dining-tables/{id}":{"get":{"description":"Returns the same card shape as the list, `activeSession` included, so a single table can be refreshed without re-reading the whole floor.","operationId":"DiningTableController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/DiningTableEntity"}}}]}}}},"404":{"description":"Dining table not found."}},"security":[{"bearer":[]}],"summary":"Get a dining table by ID","tags":["Dining Tables"]},"patch":{"operationId":"DiningTableController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDiningTableDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/DiningTableEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a dining table","tags":["Dining Tables"]},"delete":{"operationId":"DiningTableController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/DiningTableEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a dining table","tags":["Dining Tables"]}},"/api/v1/dining-tables/{id}/status":{"patch":{"operationId":"DiningTableController_updateStatus_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDiningTableStatusDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/DiningTableEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Change a dining table status","tags":["Dining Tables"]}},"/api/v1/sections":{"post":{"operationId":"SectionController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSectionDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SectionEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SectionEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a section","tags":["Sections"]},"get":{"operationId":"SectionController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SectionEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List sections (paginated)","tags":["Sections"]}},"/api/v1/sections/{id}":{"get":{"operationId":"SectionController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SectionEntity"}}}]}}}},"404":{"description":"Section not found."}},"security":[{"bearer":[]}],"summary":"Get a section by ID","tags":["Sections"]},"patch":{"operationId":"SectionController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSectionDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SectionEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a section","tags":["Sections"]},"delete":{"operationId":"SectionController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SectionEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a section","tags":["Sections"]}},"/api/v1/sections/{id}/tables":{"post":{"operationId":"SectionController_attachTable_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachTableDto"}}}},"responses":{"204":{"description":"Attached."}},"security":[{"bearer":[]}],"summary":"Attach a dining table to this section","tags":["Sections"]}},"/api/v1/sections/{id}/tables/{tableId}":{"delete":{"operationId":"SectionController_detachTable_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"tableId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":"Detached."}},"security":[{"bearer":[]}],"summary":"Detach a dining table from this section","tags":["Sections"]}},"/api/v1/sections/{id}/assignments":{"post":{"operationId":"SectionController_createAssignment_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSectionAssignmentDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SectionAssignmentEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SectionAssignmentEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a waiter assignment to this section","tags":["Sections"]},"get":{"operationId":"SectionController_listAssignments_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SectionAssignmentEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List assignments for this section","tags":["Sections"]}},"/api/v1/sections/assignments/{assignmentId}":{"patch":{"operationId":"SectionController_updateAssignment_v1","parameters":[{"name":"assignmentId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSectionAssignmentDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SectionAssignmentEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update an assignment (notes / endsAt)","tags":["Sections"]}},"/api/v1/sections/assignments/{assignmentId}/end":{"post":{"operationId":"SectionController_endAssignment_v1","parameters":[{"name":"assignmentId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SectionAssignmentEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SectionAssignmentEntity"}}}}},"security":[{"bearer":[]}],"summary":"End an assignment (sets endsAt to now)","tags":["Sections"]}},"/api/v1/printers":{"post":{"operationId":"KitchenPrinterController_create[0]_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKitchenPrinterDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KitchenPrinterEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Create a printer (KDS, checkout or finance)","tags":["Printers"]},"get":{"operationId":"KitchenPrinterController_findAll[0]_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}},{"name":"locationId","required":false,"in":"query","schema":{"format":"uuid","example":"uuid","type":"string"}},{"name":"sector","required":false,"in":"query","description":"Only printers serving this sector.","schema":{"type":"string","enum":["KDS","CHECKOUT","FINANCE"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/KitchenPrinterDetailDto"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List printers (paginated), optionally by outlet or sector","tags":["Printers"]}},"/api/v1/kitchen-printers":{"post":{"operationId":"KitchenPrinterController_create[1]_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKitchenPrinterDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KitchenPrinterEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Create a printer (KDS, checkout or finance)","tags":["Printers"],"deprecated":true},"get":{"operationId":"KitchenPrinterController_findAll[1]_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}},{"name":"locationId","required":false,"in":"query","schema":{"format":"uuid","example":"uuid","type":"string"}},{"name":"sector","required":false,"in":"query","description":"Only printers serving this sector.","schema":{"type":"string","enum":["KDS","CHECKOUT","FINANCE"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/KitchenPrinterDetailDto"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List printers (paginated), optionally by outlet or sector","tags":["Printers"],"deprecated":true}},"/api/v1/printers/{id}":{"get":{"operationId":"KitchenPrinterController_findOne[0]_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KitchenPrinterDetailDto"}}}]}}}},"404":{"description":"Printer not found."}},"security":[{"bearer":[]}],"summary":"Get a printer by ID","tags":["Printers"]},"patch":{"operationId":"KitchenPrinterController_update[0]_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateKitchenPrinterDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KitchenPrinterEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a printer","tags":["Printers"]},"delete":{"operationId":"KitchenPrinterController_remove[0]_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KitchenPrinterEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a printer","tags":["Printers"]}},"/api/v1/kitchen-printers/{id}":{"get":{"operationId":"KitchenPrinterController_findOne[1]_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KitchenPrinterDetailDto"}}}]}}}},"404":{"description":"Printer not found."}},"security":[{"bearer":[]}],"summary":"Get a printer by ID","tags":["Printers"],"deprecated":true},"patch":{"operationId":"KitchenPrinterController_update[1]_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateKitchenPrinterDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KitchenPrinterEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a printer","tags":["Printers"],"deprecated":true},"delete":{"operationId":"KitchenPrinterController_remove[1]_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KitchenPrinterEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a printer","tags":["Printers"],"deprecated":true}},"/api/v1/printers/{id}/categories":{"post":{"operationId":"KitchenPrinterController_attachCategory[0]_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachCategoryDto"}}}},"responses":{"204":{"description":"Attached."}},"security":[{"bearer":[]}],"summary":"Route a category to this printer","tags":["Printers"]}},"/api/v1/kitchen-printers/{id}/categories":{"post":{"operationId":"KitchenPrinterController_attachCategory[1]_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachCategoryDto"}}}},"responses":{"204":{"description":"Attached."}},"security":[{"bearer":[]}],"summary":"Route a category to this printer","tags":["Printers"],"deprecated":true}},"/api/v1/printers/{id}/categories/{categoryId}":{"delete":{"operationId":"KitchenPrinterController_detachCategory[0]_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"categoryId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":"Detached."}},"security":[{"bearer":[]}],"summary":"Stop routing a category to this printer","tags":["Printers"]}},"/api/v1/kitchen-printers/{id}/categories/{categoryId}":{"delete":{"operationId":"KitchenPrinterController_detachCategory[1]_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"categoryId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":"Detached."}},"security":[{"bearer":[]}],"summary":"Stop routing a category to this printer","tags":["Printers"],"deprecated":true}},"/api/v1/discount-reasons":{"post":{"operationId":"DiscountReasonController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDiscountReasonDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/DiscountReasonEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscountReasonEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a discount reason","tags":["Discount Reasons"]},"get":{"operationId":"DiscountReasonController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}},{"name":"activeOnly","required":false,"in":"query","description":"true: only the active ones","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DiscountReasonEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List discount reasons (paginated)","tags":["Discount Reasons"]}},"/api/v1/discount-reasons/{id}":{"get":{"operationId":"DiscountReasonController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/DiscountReasonEntity"}}}]}}}},"404":{"description":"Discount reason not found."}},"security":[{"bearer":[]}],"summary":"Get a discount reason by ID","tags":["Discount Reasons"]},"patch":{"operationId":"DiscountReasonController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDiscountReasonDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/DiscountReasonEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a discount reason","tags":["Discount Reasons"]},"delete":{"operationId":"DiscountReasonController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/DiscountReasonEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a discount reason","tags":["Discount Reasons"]}},"/api/v1/void-reasons":{"post":{"operationId":"VoidReasonController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateVoidReasonDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/VoidReasonEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoidReasonEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a void reason","tags":["Void Reasons"]},"get":{"operationId":"VoidReasonController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}},{"name":"activeOnly","required":false,"in":"query","description":"true: only the active ones","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/VoidReasonEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List void reasons (paginated)","tags":["Void Reasons"]}},"/api/v1/void-reasons/{id}":{"get":{"operationId":"VoidReasonController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/VoidReasonEntity"}}}]}}}},"404":{"description":"Void reason not found."}},"security":[{"bearer":[]}],"summary":"Get a void reason by ID","tags":["Void Reasons"]},"patch":{"operationId":"VoidReasonController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateVoidReasonDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/VoidReasonEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a void reason","tags":["Void Reasons"]},"delete":{"operationId":"VoidReasonController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/VoidReasonEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a void reason","tags":["Void Reasons"]}},"/api/v1/table-sessions":{"post":{"operationId":"TableSessionController_open_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenTableSessionDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TableSessionEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TableSessionEntity"}}}}},"security":[{"bearer":[]}],"summary":"Open a new table session (seat guests)","tags":["Table Sessions"]},"get":{"operationId":"TableSessionController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"example":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"example":10,"type":"number"}},{"name":"tableId","required":false,"in":"query","description":"Filter by table","schema":{"format":"uuid","example":"uuid","type":"string"}},{"name":"waiterId","required":false,"in":"query","description":"Filter by waiter","schema":{"format":"uuid","example":"uuid","type":"string"}},{"name":"sessionState","required":false,"in":"query","schema":{"type":"string","enum":["SEATED","ORDERING","SERVED","PAYMENT_PENDING","CLOSED"]}},{"name":"openOnly","required":false,"in":"query","description":"Only sessions that are still open (no closedAt)","schema":{"example":"true","type":"boolean"}},{"name":"sortBy","required":false,"in":"query","schema":{"example":"openedAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","schema":{"example":"desc","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TableSessionEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List table sessions (paginated)","tags":["Table Sessions"]}},"/api/v1/table-sessions/{id}":{"get":{"operationId":"TableSessionController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TableSessionEntity"}}}]}}}},"404":{"description":"Table session not found."}},"security":[{"bearer":[]}],"summary":"Get a table session by ID with order + seat allocations","tags":["Table Sessions"]},"patch":{"operationId":"TableSessionController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTableSessionDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TableSessionEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update waiter or guest count","tags":["Table Sessions"]}},"/api/v1/table-sessions/{id}/state":{"post":{"operationId":"TableSessionController_transitionState_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSessionStateDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TableSessionEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TableSessionEntity"}}}}},"security":[{"bearer":[]}],"summary":"Transition session state","tags":["Table Sessions"]}},"/api/v1/table-sessions/{id}/lines":{"post":{"operationId":"TableSessionController_addLine_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddSessionLineDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TableSessionLineResultDto"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}},"409":{"description":"An item is marked unavailable (sold out for now). The message names it, e.g. \"Not available right now: Mohinga\"."}},"security":[{"bearer":[]}],"summary":"Add an order line to the session","tags":["Table Sessions"]}},"/api/v1/table-sessions/{id}/charges":{"get":{"description":"The charges this table offers (service charge, VIP room fee, pool table...) and the clocks running on its bill.","operationId":"TableSessionController_charges_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TableChargesDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Table charges","tags":["Table Sessions"]},"post":{"description":"A fixed fee goes on the bill; time paid first goes on as the units asked for; a clock starts and is billed for the time used when it stops or at checkout.","operationId":"TableSessionController_addCharge_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PickedRoomChargeDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TableChargesDto"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TableChargesDto"}}}}},"security":[{"bearer":[]}],"summary":"Add a table charge","tags":["Table Sessions"]}},"/api/v1/table-sessions/{id}/charges/stop":{"post":{"description":"Stops one clock (variantId) or all, putting the time used on the bill. The till stops them all before taking payment; checkout stops any left.","operationId":"TableSessionController_stopCharges_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StopTableChargeDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TableChargesDto"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TableChargesDto"}}}}},"security":[{"bearer":[]}],"summary":"Stop table clocks","tags":["Table Sessions"]}},"/api/v1/table-sessions/{id}/seats":{"post":{"operationId":"TableSessionController_allocateSeat_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AllocateSeatDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SessionSeatAllocationEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionSeatAllocationEntity"}}}}},"security":[{"bearer":[]}],"summary":"Allocate an order line to a seat","tags":["Table Sessions"]}},"/api/v1/table-sessions/{id}/seats/{allocationId}":{"delete":{"operationId":"TableSessionController_removeAllocation_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"allocationId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SessionSeatAllocationEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Remove a seat allocation","tags":["Table Sessions"]}},"/api/v1/table-sessions/{id}/checkout":{"post":{"operationId":"TableSessionController_checkout_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutSessionDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TableSessionEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TableSessionEntity"}}}}},"security":[{"bearer":[]}],"summary":"Checkout the session (close + capture payments + free table)","tags":["Table Sessions"]}},"/api/v1/kds/fire":{"post":{"operationId":"KdsTicketController_fire_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FireTicketsDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/FireTicketsResultDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Fire pending lines to KDS — pass sessionId (dine-in) or salesOrderId (counter/QSR)","tags":["KDS Tickets"]}},"/api/v1/kds/tickets":{"get":{"operationId":"KdsTicketController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"example":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"example":50,"type":"number"}},{"name":"stationId","required":false,"in":"query","schema":{"format":"uuid","example":"uuid","type":"string"}},{"name":"sessionId","required":false,"in":"query","schema":{"format":"uuid","example":"uuid","type":"string"}},{"name":"salesOrderId","required":false,"in":"query","description":"Only tickets for this sales order","schema":{"format":"uuid","example":"uuid","type":"string"}},{"name":"status","required":false,"in":"query","schema":{"type":"string","enum":["PENDING","PREPARING","READY","EXPEDITED"]}},{"name":"activeOnly","required":false,"in":"query","description":"Only active tickets (not READY)","schema":{"example":"true","type":"boolean"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/KdsTicketViewDto"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List KDS tickets (paginated)","tags":["KDS Tickets"]}},"/api/v1/kds/tickets/{id}":{"get":{"operationId":"KdsTicketController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KdsTicketViewDto"}}}]}}}},"404":{"description":"KDS ticket not found."}},"security":[{"bearer":[]}],"summary":"Get a KDS ticket by ID","tags":["KDS Tickets"]}},"/api/v1/kds/tickets/{id}/start":{"post":{"operationId":"KdsTicketController_start_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KdsTicketEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KdsTicketEntity"}}}}},"security":[{"bearer":[]}],"summary":"Start preparing (PENDING -> PREPARING)","tags":["KDS Tickets"]}},"/api/v1/kds/tickets/{id}/ready":{"post":{"operationId":"KdsTicketController_markReady_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KdsTicketEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KdsTicketEntity"}}}}},"security":[{"bearer":[]}],"summary":"Bump entire ticket (-> READY, marks all lines + sales lines READY)","tags":["KDS Tickets"]}},"/api/v1/kds/tickets/{id}/recall":{"post":{"operationId":"KdsTicketController_recall_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KdsTicketEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KdsTicketEntity"}}}}},"security":[{"bearer":[]}],"summary":"Recall a bumped ticket (READY -> PREPARING)","tags":["KDS Tickets"]}},"/api/v1/kds/tickets/close-old":{"post":{"description":"Marks the shop's tickets still open after the given number of hours as ready, with their lines, so stale tickets stop showing as pending.","operationId":"KdsTicketController_closeOld_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CloseOldTicketsDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"summary":"Close old open tickets","tags":["KDS Tickets"]}},"/api/v1/kds/tickets/{id}/expedite":{"post":{"operationId":"KdsTicketController_expedite_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KdsTicketEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KdsTicketEntity"}}}}},"security":[{"bearer":[]}],"summary":"Mark ticket as EXPEDITED","tags":["KDS Tickets"]}},"/api/v1/kds/tickets/lines/{lineId}/ready":{"post":{"operationId":"KdsTicketController_bumpLine_v1","parameters":[{"name":"lineId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KdsTicketLineEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KdsTicketLineEntity"}}}}},"security":[{"bearer":[]}],"summary":"Bump a single ticket line — auto-promotes ticket if all lines READY","tags":["KDS Tickets"]}},"/api/v1/kds/stations":{"post":{"description":"printerIds puts one or more KDS printers at the station, e.g. two printers, or a printer and an LED board.","operationId":"KdsStationController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKdsStationDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KdsStationEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Create a KDS station","tags":["KDS Stations"]},"get":{"operationId":"KdsStationController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"example":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"example":10,"type":"number"}},{"name":"search","required":false,"in":"query","schema":{"example":"Hot","type":"string"}},{"name":"locationId","required":false,"in":"query","schema":{"format":"uuid","example":"uuid","type":"string"}},{"name":"sortBy","required":false,"in":"query","schema":{"example":"name","type":"string"}},{"name":"sortOrder","required":false,"in":"query","schema":{"example":"asc","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/KdsStationEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List KDS stations (paginated)","tags":["KDS Stations"]}},"/api/v1/kds/stations/{id}":{"get":{"operationId":"KdsStationController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KdsStationEntity"}}}]}}}},"404":{"description":"KDS station not found."}},"security":[{"bearer":[]}],"summary":"Get a KDS station by ID","tags":["KDS Stations"]},"patch":{"operationId":"KdsStationController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateKdsStationDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KdsStationEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a KDS station","tags":["KDS Stations"]},"delete":{"operationId":"KdsStationController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KdsStationEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a KDS station","tags":["KDS Stations"]}},"/api/v1/reservations":{"post":{"operationId":"ReservationController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReservationDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ReservationEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReservationEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a reservation","tags":["Reservations"]},"get":{"operationId":"ReservationController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"example":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"example":10,"type":"number"}},{"name":"search","required":false,"in":"query","schema":{"example":"Jane","type":"string"}},{"name":"locationId","required":false,"in":"query","schema":{"format":"uuid","example":"uuid","type":"string"}},{"name":"customerId","required":false,"in":"query","schema":{"format":"uuid","example":"uuid","type":"string"}},{"name":"status","required":false,"in":"query","schema":{"type":"string","enum":["PENDING","CONFIRMED","SEATED","NO_SHOW","CANCELED","COMPLETED"]}},{"name":"fromDate","required":false,"in":"query","schema":{"example":"2026-05-10T00:00:00Z","type":"string"}},{"name":"toDate","required":false,"in":"query","schema":{"example":"2026-05-11T00:00:00Z","type":"string"}},{"name":"sortBy","required":false,"in":"query","schema":{"example":"reservedAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","schema":{"example":"asc","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ReservationEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List reservations (paginated)","tags":["Reservations"]}},"/api/v1/reservations/{id}":{"get":{"operationId":"ReservationController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ReservationEntity"}}}]}}}},"404":{"description":"Reservation not found."}},"security":[{"bearer":[]}],"summary":"Get a reservation by ID","tags":["Reservations"]},"patch":{"operationId":"ReservationController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateReservationDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ReservationEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a reservation","tags":["Reservations"]},"delete":{"operationId":"ReservationController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ReservationEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Soft-delete a reservation","tags":["Reservations"]}},"/api/v1/reservations/{id}/confirm":{"post":{"operationId":"ReservationController_confirm_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ConfirmReservationResultDto"}}}]}}}},"201":{"description":""}},"security":[{"bearer":[]}],"summary":"Confirm a reservation (PENDING -> CONFIRMED, returns conflict warnings)","tags":["Reservations"]}},"/api/v1/reservations/{id}/seat":{"post":{"operationId":"ReservationController_seat_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeatReservationDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SeatReservationResultDto"}}}]}}}},"201":{"description":""}},"security":[{"bearer":[]}],"summary":"Seat the reservation — opens a TableSession and links it","tags":["Reservations"]}},"/api/v1/reservations/{id}/cancel":{"post":{"operationId":"ReservationController_cancel_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ReservationEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReservationEntity"}}}}},"security":[{"bearer":[]}],"summary":"Cancel a reservation","tags":["Reservations"]}},"/api/v1/reservations/{id}/no-show":{"post":{"operationId":"ReservationController_noShow_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ReservationEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReservationEntity"}}}}},"security":[{"bearer":[]}],"summary":"Mark a reservation as no-show","tags":["Reservations"]}},"/api/v1/waitlist":{"post":{"operationId":"WaitlistController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWaitlistEntryDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/WaitlistEntryEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WaitlistEntryEntity"}}}}},"security":[{"bearer":[]}],"summary":"Add a walk-in party to the waitlist","tags":["Waitlist"]},"get":{"operationId":"WaitlistController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"example":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"example":20,"type":"number"}},{"name":"search","required":false,"in":"query","schema":{"example":"John","type":"string"}},{"name":"locationId","required":false,"in":"query","schema":{"format":"uuid","example":"uuid","type":"string"}},{"name":"status","required":false,"in":"query","schema":{"type":"string","enum":["WAITING","NOTIFIED","SEATED","CANCELED","NO_SHOW"]}},{"name":"activeOnly","required":false,"in":"query","description":"Only active (WAITING / NOTIFIED)","schema":{"example":"true","type":"boolean"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WaitlistEntryEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List waitlist entries (paginated)","tags":["Waitlist"]}},"/api/v1/waitlist/{id}":{"get":{"operationId":"WaitlistController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/WaitlistEntryEntity"}}}]}}}},"404":{"description":"Waitlist entry not found."}},"security":[{"bearer":[]}],"summary":"Get a waitlist entry by ID","tags":["Waitlist"]},"patch":{"operationId":"WaitlistController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWaitlistEntryDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/WaitlistEntryEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a waitlist entry","tags":["Waitlist"]}},"/api/v1/waitlist/{id}/notify":{"post":{"operationId":"WaitlistController_notify_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/WaitlistEntryEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WaitlistEntryEntity"}}}}},"security":[{"bearer":[]}],"summary":"Notify the party (WAITING -> NOTIFIED)","tags":["Waitlist"]}},"/api/v1/waitlist/{id}/seat":{"post":{"operationId":"WaitlistController_seat_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeatWaitlistDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SeatWaitlistResultDto"}}}]}}}},"201":{"description":""}},"security":[{"bearer":[]}],"summary":"Seat the party — opens a TableSession and links it","tags":["Waitlist"]}},"/api/v1/waitlist/{id}/cancel":{"post":{"operationId":"WaitlistController_cancel_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/WaitlistEntryEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WaitlistEntryEntity"}}}}},"security":[{"bearer":[]}],"summary":"Cancel a waitlist entry","tags":["Waitlist"]}},"/api/v1/waitlist/{id}/no-show":{"post":{"operationId":"WaitlistController_noShow_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/WaitlistEntryEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WaitlistEntryEntity"}}}}},"security":[{"bearer":[]}],"summary":"Mark waitlist as no-show","tags":["Waitlist"]}},"/api/v1/tip-pools":{"post":{"operationId":"TipPoolController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTipPoolDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TipPoolEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TipPoolEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a tip pool — auto-snapshots tips/serviceCharge from sales in window","tags":["Tip Pools"]},"get":{"operationId":"TipPoolController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"example":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"example":10,"type":"number"}},{"name":"locationId","required":false,"in":"query","schema":{"format":"uuid","example":"uuid","type":"string"}},{"name":"status","required":false,"in":"query","schema":{"type":"string","enum":["OPEN","SETTLED"]}},{"name":"fromDate","required":false,"in":"query","schema":{"example":"2026-05-01T00:00:00Z","type":"string"}},{"name":"toDate","required":false,"in":"query","schema":{"example":"2026-05-31T23:59:59Z","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TipPoolEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List tip pools (paginated)","tags":["Tip Pools"]}},"/api/v1/tip-pools/{id}":{"get":{"operationId":"TipPoolController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TipPoolEntity"}}}]}}}},"404":{"description":"Tip pool not found."}},"security":[{"bearer":[]}],"summary":"Get a tip pool with allocations","tags":["Tip Pools"]},"patch":{"operationId":"TipPoolController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTipPoolDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TipPoolEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a tip pool (re-snapshots totals if period changed)","tags":["Tip Pools"]},"delete":{"operationId":"TipPoolController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TipPoolEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Soft-delete a tip pool (only OPEN)","tags":["Tip Pools"]}},"/api/v1/tip-pools/{id}/allocations":{"get":{"operationId":"TipPoolController_listAllocations_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TipPoolAllocationEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List allocations for a tip pool","tags":["Tip Pools"]},"post":{"operationId":"TipPoolController_addAllocation_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAllocationDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TipPoolAllocationEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TipPoolAllocationEntity"}}}}},"security":[{"bearer":[]}],"summary":"Add an allocation to a tip pool","tags":["Tip Pools"]}},"/api/v1/tip-pools/{id}/allocations/{allocationId}":{"patch":{"operationId":"TipPoolController_updateAllocation_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"allocationId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAllocationDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TipPoolAllocationEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update an allocation","tags":["Tip Pools"]},"delete":{"operationId":"TipPoolController_removeAllocation_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"allocationId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TipPoolAllocationEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Remove an allocation","tags":["Tip Pools"]}},"/api/v1/tip-pools/{id}/distribute":{"post":{"operationId":"TipPoolController_distribute_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TipPoolEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TipPoolEntity"}}}}},"security":[{"bearer":[]}],"summary":"Auto-fill allocation amounts using the pool distribution method","tags":["Tip Pools"]}},"/api/v1/tip-pools/{id}/settle":{"post":{"operationId":"TipPoolController_settle_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TipPoolEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TipPoolEntity"}}}}},"security":[{"bearer":[]}],"summary":"Settle the pool — finalizes (immutable)","tags":["Tip Pools"]}},"/api/v1/shift-templates":{"post":{"description":"An end time at or before the start means the shift runs past midnight.","operationId":"ShiftTemplateController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateShiftTemplateDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ShiftTemplateEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShiftTemplateEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a shift template, e.g. Evening 17:00-02:00","tags":["Shift Templates"]},"get":{"operationId":"ShiftTemplateController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ShiftTemplateEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List shift templates","tags":["Shift Templates"]}},"/api/v1/shift-templates/{id}":{"get":{"operationId":"ShiftTemplateController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ShiftTemplateEntity"}}}]}}}},"404":{"description":"Shift template not found."}},"security":[{"bearer":[]}],"summary":"Get a shift template","tags":["Shift Templates"]},"patch":{"operationId":"ShiftTemplateController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateShiftTemplateDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ShiftTemplateEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a shift template","tags":["Shift Templates"]},"delete":{"description":"Soft delete. Shifts already rostered from it keep their scheduled times.","operationId":"ShiftTemplateController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ShiftTemplateEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a shift template","tags":["Shift Templates"]}},"/api/v1/shift-rosters":{"post":{"operationId":"ShiftRosterController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateShiftRosterDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ShiftRosterEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShiftRosterEntity"}}}},"409":{"description":"That person is already rostered on an overlapping shift."}},"security":[{"bearer":[]}],"summary":"Roster one person onto one shift","tags":["Shift Roster"]},"get":{"operationId":"ShiftRosterController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}},{"name":"locationId","required":false,"in":"query","schema":{"format":"uuid","example":"uuid","type":"string"}},{"name":"userId","required":false,"in":"query","schema":{"format":"uuid","example":"uuid","type":"string"}},{"name":"from","required":false,"in":"query","schema":{"example":"2026-08-25","type":"string"}},{"name":"to","required":false,"in":"query","schema":{"example":"2026-08-31","type":"string"}},{"name":"status","required":false,"in":"query","schema":{"type":"string","enum":["PUBLISHED","SWAP_REQUESTED","COMPLETED","ABSENT"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ShiftRosterEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List rostered shifts","tags":["Shift Roster"]}},"/api/v1/shift-rosters/run":{"post":{"description":"How a week is planned. Days someone is already booked are skipped and listed in the response rather than failing the run.","operationId":"ShiftRosterController_createRun_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateShiftRosterRunDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ShiftRosterRunResultDto"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShiftRosterRunResultDto"}}}}},"security":[{"bearer":[]}],"summary":"Roster several people onto a template across a date range","tags":["Shift Roster"]}},"/api/v1/shift-rosters/{id}":{"get":{"operationId":"ShiftRosterController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ShiftRosterEntity"}}}]}}}},"404":{"description":"Shift roster not found."}},"security":[{"bearer":[]}],"summary":"Get a rostered shift","tags":["Shift Roster"]},"patch":{"operationId":"ShiftRosterController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateShiftRosterDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ShiftRosterEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Reassign, re-time or mark a shift, e.g. status ABSENT","tags":["Shift Roster"]},"delete":{"operationId":"ShiftRosterController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ShiftRosterEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Remove a rostered shift","tags":["Shift Roster"]}},"/api/v1/shift-rosters/{id}/swap-request":{"post":{"description":"The shift stays with its current holder until the swap is approved.","operationId":"ShiftRosterController_requestSwap_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestShiftSwapDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ShiftRosterEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShiftRosterEntity"}}}}},"security":[{"bearer":[]}],"summary":"Ask a colleague to take this shift","tags":["Shift Roster"]}},"/api/v1/shift-rosters/{id}/swap-approve":{"post":{"operationId":"ShiftRosterController_approveSwap_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ShiftRosterEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShiftRosterEntity"}}}}},"security":[{"bearer":[]}],"summary":"Approve the pending swap, handing the shift over","tags":["Shift Roster"]}},"/api/v1/timesheets/clock-in":{"post":{"description":"Starts a shift. Pass shiftRosterId to attach it to a rostered shift, which is what makes lateness measurable. Omit userId to clock yourself in.","operationId":"TimesheetController_clockIn_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClockInDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TimesheetEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimesheetEntity"}}}},"409":{"description":"Already clocked in."}},"security":[{"bearer":[]}],"summary":"Clock in","tags":["Timesheets"]}},"/api/v1/timesheets/{id}/clock-out":{"post":{"description":"Ends the shift and derives worked, late and overtime minutes. Marks the rostered shift COMPLETED.","operationId":"TimesheetController_clockOut_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClockOutDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TimesheetEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimesheetEntity"}}}}},"security":[{"bearer":[]}],"summary":"Clock out","tags":["Timesheets"]}},"/api/v1/timesheets":{"get":{"operationId":"TimesheetController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}},{"name":"userId","required":false,"in":"query","schema":{"format":"uuid","example":"uuid","type":"string"}},{"name":"from","required":false,"in":"query","schema":{"example":"2026-08-25","type":"string"}},{"name":"to","required":false,"in":"query","schema":{"example":"2026-08-31","type":"string"}},{"name":"status","required":false,"in":"query","schema":{"type":"string","enum":["PENDING_APPROVAL","APPROVED","REJECTED"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TimesheetEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List timesheets","tags":["Timesheets"]}},"/api/v1/timesheets/worked-hours":{"get":{"description":"The hours a tip pool distributing BY_HOURS should use. Only approved timesheets count.","operationId":"TimesheetController_workedHours_v1","parameters":[{"name":"from","required":true,"in":"query","schema":{"example":"2026-08-25","type":"string"}},{"name":"to","required":true,"in":"query","schema":{"example":"2026-08-31","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WorkedHoursDto"}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Approved worked hours per person over a period","tags":["Timesheets"]}},"/api/v1/timesheets/{id}":{"get":{"operationId":"TimesheetController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TimesheetEntity"}}}]}}}},"404":{"description":"Timesheet not found."}},"security":[{"bearer":[]}],"summary":"Get a timesheet","tags":["Timesheets"]}},"/api/v1/timesheets/{id}/decision":{"patch":{"operationId":"TimesheetController_decide_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DecideTimesheetDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TimesheetEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Approve or reject a timesheet","tags":["Timesheets"]}},"/api/v1/ktv-rooms":{"post":{"operationId":"KtvRoomController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKtvRoomDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KtvRoomEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"The rate product is stock-tracked rather than a service"}},"security":[{"bearer":[]}],"summary":"Create a KTV room","tags":["KTV Rooms"]},"get":{"operationId":"KtvRoomController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/KtvRoomEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List KTV rooms","tags":["KTV Rooms"]}},"/api/v1/ktv-rooms/board":{"get":{"description":"Every room with whatever is happening in it - in use, free, being cleaned - and how long the current party has been in. This is the staff panel from requirement 6.1.","operationId":"KtvRoomController_board_v1","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/KtvRoomBoardDto"}}}}]}}}}},"security":[{"bearer":[]}],"summary":"The room board","tags":["KTV Rooms"]}},"/api/v1/ktv-rooms/{id}":{"get":{"operationId":"KtvRoomController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KtvRoomEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get a KTV room","tags":["KTV Rooms"]},"patch":{"description":"Billing changes apply to the next party only. A let copies the terms when it opens, so a party already singing keeps the price they were quoted.","operationId":"KtvRoomController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateKtvRoomDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KtvRoomEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a KTV room","tags":["KTV Rooms"]},"delete":{"operationId":"KtvRoomController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KtvRoomEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Retire a KTV room","tags":["KTV Rooms"]}},"/api/v1/ktv-rooms/{id}/ready":{"post":{"description":"Moves it from CLEANING back to AVAILABLE.","operationId":"KtvRoomController_markReady_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KtvRoomEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KtvRoomEntity"}}}}},"security":[{"bearer":[]}],"summary":"Mark a cleaned room ready","tags":["KTV Rooms"]}},"/api/v1/ktv-sessions":{"post":{"description":"Opens the let and starts a bill for `hours`, at the rate that applies now. Follows Venue setup: with PAY_WHEN_ORDERING `prepay` is required and the hours (and `items`) are charged to the tapped card now; with PAY_AT_END `prepay` is refused and they go on the bill, paid after close with POST /v1/sales-orders/{salesOrderId}/settle.","operationId":"KtvSessionController_open_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenKtvSessionDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KtvRoomSessionEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KtvRoomSessionEntity"}}}},"409":{"description":"That room is already in use"}},"security":[{"bearer":[]}],"summary":"Take a room","tags":["KTV Sessions"]}},"/api/v1/ktv-sessions/{id}/extend":{"post":{"description":"At the rate that applies now: charged to the tapped card (PAY_WHEN_ORDERING), or put on the bill without a card (PAY_AT_END). The booked time grows by it.","operationId":"KtvSessionController_extend_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtendKtvSessionDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KtvChargeResultDto"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KtvChargeResultDto"}}}},"409":{"description":"An item is marked unavailable (sold out for now). The message names it, e.g. \"Not available right now: Mohinga\"."},"422":{"description":"The card cannot cover it."}},"security":[{"bearer":[]}],"summary":"Buy more hours","tags":["KTV Sessions"]}},"/api/v1/ktv-sessions/{id}/charges":{"post":{"description":"Priced on the server and sent to the kitchen. Charged to the tapped card at once (PAY_WHEN_ORDERING), or put on the bill without a card (PAY_AT_END).","operationId":"KtvSessionController_chargeItems_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoomChargeItemsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KtvChargeResultDto"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}},"409":{"description":"An item is marked unavailable (sold out for now). The message names it, e.g. \"Not available right now: Mohinga\"."},"422":{"description":"The card cannot cover it."}},"security":[{"bearer":[]}],"summary":"Order food and drink","tags":["KTV Sessions"]}},"/api/v1/ktv-sessions/{id}/foc":{"post":{"description":"Added at full price and fully discounted under the reason; sent to the kitchen like any order. No card is charged.","operationId":"KtvSessionController_giveFree_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoomGiveFreeDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KtvChargeResultDto"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}},"409":{"description":"An item is marked unavailable (sold out for now). The message names it, e.g. \"Not available right now: Mohinga\"."}},"security":[{"bearer":[]}],"summary":"Give items on the house (FOC)","tags":["KTV Sessions"]}},"/api/v1/ktv-sessions/{id}/free-hours":{"post":{"description":"For a party that ran over: the hours go on the bill at the rate that applies now, fully discounted under the reason, and the countdown moves on. No card is charged. To charge for them instead, use extend.","operationId":"KtvSessionController_giveFreeHours_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoomFreeHoursDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KtvChargeResultDto"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KtvChargeResultDto"}}}}},"security":[{"bearer":[]}],"summary":"Give hours on the house","tags":["KTV Sessions"]}},"/api/v1/ktv-sessions/{id}/lines/{lineId}/refund":{"post":{"description":"While the room is in use. Booked hours are not refunded.","operationId":"KtvSessionController_refundLine_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"lineId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoomRefundLineDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KtvChargeResultDto"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KtvChargeResultDto"}}}}},"security":[{"bearer":[]}],"summary":"Take a charged item off and refund the card","tags":["KTV Sessions"]}},"/api/v1/ktv-sessions/{id}/quote":{"get":{"description":"Read-only and safe to poll, which is how a room panel shows a live figure. Uses the same arithmetic as the close, so the quoted number is the charged one.","operationId":"KtvSessionController_quote_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KtvSessionQuoteDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"The running bill","tags":["KTV Sessions"]}},"/api/v1/ktv-sessions/{id}/planned-minutes":{"patch":{"description":"Records the time a party asked for, or changes it when they extend. Informational only - the bill is metered off the clock, so this never changes what they are charged. The value is the total length from when the room opened, not an amount to add. Null clears it.","operationId":"KtvSessionController_setPlannedMinutes_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPlannedMinutesDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KtvRoomSessionEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Set how long the party wants the room for","tags":["KTV Sessions"]}},"/api/v1/ktv-sessions/{id}/pause":{"post":{"description":"For a fault or a dispute. Paused minutes are not charged for.","operationId":"KtvSessionController_pause_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KtvRoomSessionEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KtvRoomSessionEntity"}}}}},"security":[{"bearer":[]}],"summary":"Stop the clock","tags":["KTV Sessions"]}},"/api/v1/ktv-sessions/{id}/resume":{"post":{"operationId":"KtvSessionController_resume_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KtvRoomSessionEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KtvRoomSessionEntity"}}}}},"security":[{"bearer":[]}],"summary":"Restart the clock","tags":["KTV Sessions"]}},"/api/v1/ktv-sessions/{id}/close":{"post":{"description":"Sends the room for cleaning. PAY_WHEN_ORDERING: the bill is closed with what was charged, plus a `tip` if one is sent, taken now. PAY_AT_END: the bill stays DRAFT with `amountDue`; pay it now with POST /v1/sales-orders/{salesOrderId}/settle (member card only when Venue setup says so). Older clock-billed rooms get the room charge written as lines, one per rate window, and settle the same way.","operationId":"KtvSessionController_close_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CloseKtvSessionDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KtvSessionQuoteDto"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KtvSessionQuoteDto"}}}}},"security":[{"bearer":[]}],"summary":"End the let","tags":["KTV Sessions"]}},"/api/v1/hostesses":{"post":{"description":"A hostess or dancer called to KTV rooms. Picked at the till when a service that asks who served is sold; she never logs in.","operationId":"HostessController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateHostessDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/HostessEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Add a hostess","tags":["Hostesses"]},"get":{"description":"Each with the KTV room she is in now, if any.","operationId":"HostessController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}},{"name":"activeOnly","required":false,"in":"query","description":"true: only the active ones","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/HostessEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List hostesses","tags":["Hostesses"]}},"/api/v1/hostesses/{id}":{"get":{"operationId":"HostessController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/HostessEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get a hostess","tags":["Hostesses"]},"patch":{"operationId":"HostessController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateHostessDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/HostessEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a hostess","tags":["Hostesses"]},"delete":{"description":"Past bills keep her name.","operationId":"HostessController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/HostessEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Remove a hostess","tags":["Hostesses"]}},"/api/v1/data-transfer/{kind}/template":{"get":{"description":"Headers, dropdowns of this organization’s roles, branches, categories, units and locations, and an Instructions tab.","operationId":"DataTransferController_template_v1","parameters":[{"name":"kind","required":true,"in":"path","schema":{"enum":["users","products","stock","spa-rooms","ktv-rooms"],"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Download an empty sheet to fill in","tags":["Excel import & export"]}},"/api/v1/data-transfer/{kind}/export":{"get":{"operationId":"DataTransferController_export_v1","parameters":[{"name":"kind","required":true,"in":"path","schema":{"enum":["users","products","stock","spa-rooms","ktv-rooms"],"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Download the organization’s current data","tags":["Excel import & export"]}},"/api/v1/data-transfer/{kind}/import":{"post":{"description":"Without commit, nothing is saved: the answer says, row by row, what would be created, updated or left alone, and what is wrong. With commit=true the rows are saved together, or none are if any row is wrong.","operationId":"DataTransferController_import_v1","parameters":[{"name":"kind","required":true,"in":"path","schema":{"enum":["users","products","stock","spa-rooms","ktv-rooms"],"type":"string"}},{"name":"commit","required":false,"in":"query","schema":{"type":"boolean"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}}}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"bearer":[]}],"summary":"Check, then save, a filled-in sheet","tags":["Excel import & export"]}},"/api/v1/reports/sales-summary":{"get":{"description":"Sales filed under each business date in the range, with refunds on the day they were made. Totals are built from order lines, so gross, discounts and net add up to the grand total whether a sale closed at the counter or at a table. Guest-card top-ups are deposits and never appear here.","operationId":"ReportController_salesSummary_v1","parameters":[{"name":"from","required":true,"in":"query","description":"First business date, YYYY-MM-DD, in the property’s timezone.","schema":{"pattern":"BUSINESS_DATE","example":"2026-09-01","type":"string"}},{"name":"to","required":false,"in":"query","description":"Last business date, included. Defaults to `from`.","schema":{"pattern":"BUSINESS_DATE","example":"2026-09-14","type":"string"}},{"name":"locationId","required":false,"in":"query","description":"One outlet. Omit for every outlet you can see.","schema":{"format":"uuid","example":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SalesSummaryReportDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Sales summary tab","tags":["Reports"]}},"/api/v1/reports/pos-summary":{"get":{"description":"The sales summary for one POS: SPA, KTV, or BAR (every other till, counter and table). Same figures and shape as the sales summary tab, with refunds of that POS’s sales on the day they were made.","operationId":"ReportController_posSummary_v1","parameters":[{"name":"from","required":true,"in":"query","description":"First business date, YYYY-MM-DD, in the property’s timezone.","schema":{"pattern":"BUSINESS_DATE","example":"2026-09-01","type":"string"}},{"name":"to","required":false,"in":"query","description":"Last business date, included. Defaults to `from`.","schema":{"pattern":"BUSINESS_DATE","example":"2026-09-14","type":"string"}},{"name":"locationId","required":false,"in":"query","description":"One outlet. Omit for every outlet you can see.","schema":{"format":"uuid","example":"uuid","type":"string"}},{"name":"posType","required":true,"in":"query","description":"SPA, KTV, or BAR (every other till, counter and table).","schema":{"type":"string","enum":["BAR","SPA","KTV"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SalesSummaryReportDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"POS sales summary (8.1)","tags":["Reports"]}},"/api/v1/reports/pos-bills":{"get":{"description":"Every bill one POS sold in the range, newest first: where (room or table), who, what was on it, what was given free and how it was paid. Totals are over every bill, not the page, and match the POS summary.","operationId":"ReportController_posBills_v1","parameters":[{"name":"from","required":true,"in":"query","description":"First business date, YYYY-MM-DD, in the property’s timezone.","schema":{"pattern":"BUSINESS_DATE","example":"2026-09-01","type":"string"}},{"name":"to","required":false,"in":"query","description":"Last business date, included. Defaults to `from`.","schema":{"pattern":"BUSINESS_DATE","example":"2026-09-14","type":"string"}},{"name":"locationId","required":false,"in":"query","description":"One outlet. Omit for every outlet you can see.","schema":{"format":"uuid","example":"uuid","type":"string"}},{"name":"posType","required":true,"in":"query","description":"SPA, KTV, or BAR (every other till, counter and table).","schema":{"type":"string","enum":["BAR","SPA","KTV"]}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":500,"default":50,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Order number, room or table, or guest name contains","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PosBillsReportDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"POS sales details (8.1)","tags":["Reports"]}},"/api/v1/reports/bar-categories":{"get":{"description":"Bar POS sales per top-level menu category, with its sub-categories rolled in and also listed. Net sales add up to the BAR POS summary.","operationId":"ReportController_barCategories_v1","parameters":[{"name":"from","required":true,"in":"query","description":"First business date, YYYY-MM-DD, in the property’s timezone.","schema":{"pattern":"BUSINESS_DATE","example":"2026-09-01","type":"string"}},{"name":"to","required":false,"in":"query","description":"Last business date, included. Defaults to `from`.","schema":{"pattern":"BUSINESS_DATE","example":"2026-09-14","type":"string"}},{"name":"locationId","required":false,"in":"query","description":"One outlet. Omit for every outlet you can see.","schema":{"format":"uuid","example":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/BarCategoryReportDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Bar sales by menu category (8.2)","tags":["Reports"]}},"/api/v1/reports/spa-menu":{"get":{"description":"SPA sales in sections: SPA menu (service packages), room + menu packages (packages that include food or drink), and room services (what was ordered in the room). Net sales add up to the SPA POS summary.","operationId":"ReportController_spaMenu_v1","parameters":[{"name":"from","required":true,"in":"query","description":"First business date, YYYY-MM-DD, in the property’s timezone.","schema":{"pattern":"BUSINESS_DATE","example":"2026-09-01","type":"string"}},{"name":"to","required":false,"in":"query","description":"Last business date, included. Defaults to `from`.","schema":{"pattern":"BUSINESS_DATE","example":"2026-09-14","type":"string"}},{"name":"locationId","required":false,"in":"query","description":"One outlet. Omit for every outlet you can see.","schema":{"format":"uuid","example":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SpaMenuReportDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"SPA sales by menu (8.3)","tags":["Reports"]}},"/api/v1/reports/ktv-sessions":{"get":{"description":"One row per KTV session sold in the range: room, guest, times, hours sold and given free, room and food & drink sales, payments. Plus totals over all sessions and a summary per room.","operationId":"ReportController_ktvSessions_v1","parameters":[{"name":"from","required":true,"in":"query","description":"First business date, YYYY-MM-DD, in the property’s timezone.","schema":{"pattern":"BUSINESS_DATE","example":"2026-09-01","type":"string"}},{"name":"to","required":false,"in":"query","description":"Last business date, included. Defaults to `from`.","schema":{"pattern":"BUSINESS_DATE","example":"2026-09-14","type":"string"}},{"name":"locationId","required":false,"in":"query","description":"One outlet. Omit for every outlet you can see.","schema":{"format":"uuid","example":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/KtvSessionReportDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"KTV sales per session (8.4)","tags":["Reports"]}},"/api/v1/reports/hostesses":{"get":{"description":"Every hostess call in the range: who went to which room, the service, hours and sales. Plus totals and a summary per hostess. Calls given free count as calls but not as sales.","operationId":"ReportController_hostesses_v1","parameters":[{"name":"from","required":true,"in":"query","description":"First business date, YYYY-MM-DD, in the property’s timezone.","schema":{"pattern":"BUSINESS_DATE","example":"2026-09-01","type":"string"}},{"name":"to","required":false,"in":"query","description":"Last business date, included. Defaults to `from`.","schema":{"pattern":"BUSINESS_DATE","example":"2026-09-14","type":"string"}},{"name":"locationId","required":false,"in":"query","description":"One outlet. Omit for every outlet you can see.","schema":{"format":"uuid","example":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/HostessReportDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Hostesses (KTV)","tags":["Reports"]}},"/api/v1/reports/item-sales":{"get":{"description":"Every item sold in the range. Bill-level discounts are spread across the lines they applied to, so the item net sales total equals the sales summary net sales. Returns are counted on the day they were made.","operationId":"ReportController_itemSales_v1","parameters":[{"name":"from","required":true,"in":"query","description":"First business date, YYYY-MM-DD, in the property’s timezone.","schema":{"pattern":"BUSINESS_DATE","example":"2026-09-01","type":"string"}},{"name":"to","required":false,"in":"query","description":"Last business date, included. Defaults to `from`.","schema":{"pattern":"BUSINESS_DATE","example":"2026-09-14","type":"string"}},{"name":"locationId","required":false,"in":"query","description":"One outlet. Omit for every outlet you can see.","schema":{"format":"uuid","example":"uuid","type":"string"}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":500,"default":50,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Product name or SKU contains","schema":{"type":"string"}},{"name":"categoryId","required":false,"in":"query","schema":{"format":"uuid","example":"uuid","type":"string"}},{"name":"sortBy","required":false,"in":"query","schema":{"default":"netSales","type":"string","enum":["netSales","grossSales","quantitySold","refundAmount","productName","categoryName"]}},{"name":"sortOrder","required":false,"in":"query","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ItemSalesReportDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Item sales tab","tags":["Reports"]}},"/api/v1/reports/other-income-expenses":{"get":{"description":"Paid-ins and paid-outs recorded against a till. Drops, float corrections and guest-card money are left out: none of them earns or spends anything.","operationId":"ReportController_otherIncomeExpenses_v1","parameters":[{"name":"from","required":true,"in":"query","description":"First business date, YYYY-MM-DD, in the property’s timezone.","schema":{"pattern":"BUSINESS_DATE","example":"2026-09-01","type":"string"}},{"name":"to","required":false,"in":"query","description":"Last business date, included. Defaults to `from`.","schema":{"pattern":"BUSINESS_DATE","example":"2026-09-14","type":"string"}},{"name":"locationId","required":false,"in":"query","description":"One outlet. Omit for every outlet you can see.","schema":{"format":"uuid","example":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/OtherIncomeExpenseReportDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Other expenses / income tab","tags":["Reports"]}},"/api/v1/reports/member-cards":{"get":{"description":"Cards issued and closed, money paid in and spent, refunds and forfeits in the range, and what is still owed to guests now. Top-ups are deposits, not sales.","operationId":"ReportController_memberCards_v1","parameters":[{"name":"from","required":true,"in":"query","description":"First business date, YYYY-MM-DD, in the property’s timezone.","schema":{"pattern":"BUSINESS_DATE","example":"2026-09-01","type":"string"}},{"name":"to","required":false,"in":"query","description":"Last business date, included. Defaults to `from`.","schema":{"pattern":"BUSINESS_DATE","example":"2026-09-14","type":"string"}},{"name":"locationId","required":false,"in":"query","description":"One outlet. Omit for every outlet you can see.","schema":{"format":"uuid","example":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/MemberCardReportDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Member card tab: guest cards","tags":["Reports"]}},"/api/v1/reports/loyalty-points":{"get":{"description":"Points earned and reversed in the range, and the balance members hold now. Points cannot yet be redeemed or expire, so those figures are always zero.","operationId":"ReportController_loyaltyPoints_v1","parameters":[{"name":"from","required":true,"in":"query","description":"First business date, YYYY-MM-DD, in the property’s timezone.","schema":{"pattern":"BUSINESS_DATE","example":"2026-09-01","type":"string"}},{"name":"to","required":false,"in":"query","description":"Last business date, included. Defaults to `from`.","schema":{"pattern":"BUSINESS_DATE","example":"2026-09-14","type":"string"}},{"name":"locationId","required":false,"in":"query","description":"One outlet. Omit for every outlet you can see.","schema":{"format":"uuid","example":"uuid","type":"string"}},{"name":"top","required":false,"in":"query","description":"How many top members to list","schema":{"minimum":1,"maximum":100,"default":10,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/LoyaltyPointsReportDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Member card tab: loyalty points","tags":["Reports"]}},"/api/v1/reports/daily-sales":{"get":{"operationId":"ReportController_dailySales_v1","parameters":[{"name":"locationId","required":false,"in":"query","description":"One outlet. Omit for every outlet you can see.","schema":{"format":"uuid","example":"uuid","type":"string"}},{"name":"date","required":true,"in":"query","description":"Business date, YYYY-MM-DD, in the property’s timezone.","schema":{"example":"2026-05-06","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/DailySalesSummaryDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Daily sales summary (orders, revenue, tax, tips, payment breakdown)","tags":["Reports"]}},"/api/v1/reports/sales-by-category":{"get":{"operationId":"ReportController_salesByCategory_v1","parameters":[{"name":"locationId","required":false,"in":"query","description":"One outlet. Omit for every outlet you can see.","schema":{"format":"uuid","example":"uuid","type":"string"}},{"name":"fromDate","required":true,"in":"query","description":"First business date. Only the date part is used; a time is ignored.","schema":{"example":"2026-05-01","type":"string"}},{"name":"toDate","required":true,"in":"query","description":"Last business date, included. Only the date part is used; a time is ignored.","schema":{"example":"2026-05-31","type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"example":10,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CategorySalesRowDto"}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Sales by category over a date range","tags":["Reports"]}},"/api/v1/reports/sales-by-item":{"get":{"operationId":"ReportController_salesByItem_v1","parameters":[{"name":"locationId","required":false,"in":"query","description":"One outlet. Omit for every outlet you can see.","schema":{"format":"uuid","example":"uuid","type":"string"}},{"name":"fromDate","required":true,"in":"query","description":"First business date. Only the date part is used; a time is ignored.","schema":{"example":"2026-05-01","type":"string"}},{"name":"toDate","required":true,"in":"query","description":"Last business date, included. Only the date part is used; a time is ignored.","schema":{"example":"2026-05-31","type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"example":10,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ItemSalesRowDto"}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Top items by revenue over a date range","tags":["Reports"]}},"/api/v1/reports/sales-by-hour":{"get":{"operationId":"ReportController_salesByHour_v1","parameters":[{"name":"locationId","required":false,"in":"query","description":"One outlet. Omit for every outlet you can see.","schema":{"format":"uuid","example":"uuid","type":"string"}},{"name":"date","required":true,"in":"query","description":"Business date, YYYY-MM-DD, in the property’s timezone.","schema":{"example":"2026-05-06","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/HourlySalesRowDto"}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Sales distribution by hour for a given day","tags":["Reports"]}},"/api/v1/reports/server-performance":{"get":{"operationId":"ReportController_serverPerformance_v1","parameters":[{"name":"locationId","required":false,"in":"query","description":"One outlet. Omit for every outlet you can see.","schema":{"format":"uuid","example":"uuid","type":"string"}},{"name":"fromDate","required":true,"in":"query","description":"First business date. Only the date part is used; a time is ignored.","schema":{"example":"2026-05-01","type":"string"}},{"name":"toDate","required":true,"in":"query","description":"Last business date, included. Only the date part is used; a time is ignored.","schema":{"example":"2026-05-31","type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"example":10,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ServerPerformanceRowDto"}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Per-server performance over a date range","tags":["Reports"]}},"/api/v1/reports/z-report":{"get":{"operationId":"ReportController_zReport_v1","parameters":[{"name":"locationId","required":false,"in":"query","description":"One outlet. Omit for every outlet you can see.","schema":{"format":"uuid","example":"uuid","type":"string"}},{"name":"date","required":true,"in":"query","description":"Business date, YYYY-MM-DD, in the property’s timezone.","schema":{"example":"2026-05-06","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ZReportDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Z-Report — consolidated end-of-day rollup for accounting","tags":["Reports"]}},"/api/v1/reports/shifts":{"get":{"description":"Every shift that opened in the range: POS device, staff, and what it took by payment method, with card top-ups and refunds kept apart from sales. Plus totals per staff member and per payment method. Each shift adds up the same way as its own summary.","operationId":"ReportController_shifts_v1","parameters":[{"name":"from","required":true,"in":"query","description":"First business date, YYYY-MM-DD, in the property’s timezone.","schema":{"pattern":"BUSINESS_DATE","example":"2026-09-01","type":"string"}},{"name":"to","required":false,"in":"query","description":"Last business date, included. Defaults to `from`.","schema":{"pattern":"BUSINESS_DATE","example":"2026-09-14","type":"string"}},{"name":"locationId","required":false,"in":"query","description":"One outlet. Omit for every outlet you can see.","schema":{"format":"uuid","example":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ShiftReportDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Shifts","tags":["Reports"]}},"/api/v1/reports/card-usage":{"get":{"description":"Every guest-card spend in the range, newest first: which card, guest, tier, outlet and bill, and the balance after. Reversals from voids and refunds are listed too. Totals and the per-tier summary cover every entry.","operationId":"ReportController_cardUsage_v1","parameters":[{"name":"from","required":true,"in":"query","description":"First business date, YYYY-MM-DD, in the property’s timezone.","schema":{"pattern":"BUSINESS_DATE","example":"2026-09-01","type":"string"}},{"name":"to","required":false,"in":"query","description":"Last business date, included. Defaults to `from`.","schema":{"pattern":"BUSINESS_DATE","example":"2026-09-14","type":"string"}},{"name":"locationId","required":false,"in":"query","description":"One outlet. Omit for every outlet you can see.","schema":{"format":"uuid","example":"uuid","type":"string"}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":500,"default":50,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Card number, wallet number, guest name or phone contains","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/CardActivityReportDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Card usage","tags":["Reports"]}},"/api/v1/reports/card-money":{"get":{"description":"Every top-up, preload, refund, settlement, forfeit and adjustment on guest cards in the range, newest first, with payment method, staff and approver. Plus totals per type, per tier and per payment method.","operationId":"ReportController_cardMoney_v1","parameters":[{"name":"from","required":true,"in":"query","description":"First business date, YYYY-MM-DD, in the property’s timezone.","schema":{"pattern":"BUSINESS_DATE","example":"2026-09-01","type":"string"}},{"name":"to","required":false,"in":"query","description":"Last business date, included. Defaults to `from`.","schema":{"pattern":"BUSINESS_DATE","example":"2026-09-14","type":"string"}},{"name":"locationId","required":false,"in":"query","description":"One outlet. Omit for every outlet you can see.","schema":{"format":"uuid","example":"uuid","type":"string"}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":500,"default":50,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Card number, wallet number, guest name or phone contains","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/CardActivityReportDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Card top-ups and refunds","tags":["Reports"]}},"/api/v1/counter-orders/{id}":{"get":{"operationId":"CounterOrderController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/CounterOrderDto"}}}]}}}},"404":{"description":"Order not found."}},"security":[{"bearer":[]}],"summary":"Get a counter/takeaway order with lines + KDS tickets","tags":["Counter Orders"]}},"/api/v1/counter-orders/{id}/pickup":{"post":{"operationId":"CounterOrderController_markPickedUp_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SalesOrderEntity"}}}]}}}},"201":{"description":""},"400":{"description":"Some line is not READY yet, or the order was already picked up"}},"security":[{"bearer":[]}],"summary":"Mark order picked up — moves READY lines to SERVED and stamps pickedUpAt","tags":["Counter Orders"]}},"/api/v1/room-tablet/menu":{"get":{"description":"Guest-facing: names, prices and pictures only. Cost, stock and supplier data are deliberately absent. Prices are list prices - a card tier discount is applied when the bill is settled, not shown here, because the card is not known until then.","operationId":"RoomTabletController_menu_v1","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/RoomMenuDto"}}}]}}}},"403":{"description":"The device is not assigned to a room, or nobody is seated in it."}},"security":[{"bearer":[]}],"summary":"The menu this room can order from","tags":["Room Tablet"]}},"/api/v1/room-tablet/session":{"get":{"description":"What the party has ordered so far, what it comes to, what is left on their card, and when the time they asked for runs out. The room charge is not included: it is worked out when they leave.","operationId":"RoomTabletController_session_v1","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/RoomSessionViewDto"}}}]}}}},"403":{"description":"The device is not assigned to a room, or nobody is seated in it."}},"security":[{"bearer":[]}],"summary":"This room’s tab, balance and countdown","tags":["Room Tablet"]}},"/api/v1/spa-packages":{"post":{"description":"What a SPA guest buys: a treatment with its duration and price, optionally with menu items included (\"+ juice\"). The room is only where it happens.","operationId":"SpaPackageController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSpaPackageDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SpaPackageEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Create a service package","tags":["SPA Packages"]},"get":{"operationId":"SpaPackageController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}},{"name":"activeOnly","required":false,"in":"query","description":"true: only the active ones","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SpaPackageEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List service packages","tags":["SPA Packages"]}},"/api/v1/spa-packages/{id}":{"get":{"operationId":"SpaPackageController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SpaPackageEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get a service package","tags":["SPA Packages"]},"patch":{"description":"Changes apply to the next sale; bills already made keep their price.","operationId":"SpaPackageController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSpaPackageDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SpaPackageEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a service package","tags":["SPA Packages"]},"delete":{"description":"Past sales stay in reports.","operationId":"SpaPackageController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SpaPackageEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Retire a service package","tags":["SPA Packages"]}},"/api/v1/spa-rooms":{"post":{"description":"Rounding defaults to DOWN with fifteen minutes of grace, unlike a KTV room: a treatment that runs over is still one treatment. Set the rate product and the block length to agree - 60 minutes at 30,000.","operationId":"SpaRoomController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSpaRoomDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SpaRoomEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpaRoomEntity"}}}}},"security":[{"bearer":[]}],"summary":"Create a treatment room","tags":["Spa Rooms"]},"get":{"operationId":"SpaRoomController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SpaRoomEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List treatment rooms","tags":["Spa Rooms"]}},"/api/v1/spa-rooms/board":{"get":{"description":"Rooms with their live treatment inline - one call, no per-room lookups. Each live treatment carries its therapists and `endsAt` for the countdown.","operationId":"SpaRoomController_board_v1","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SpaRoomBoardDto"}}}}]}}}}},"security":[{"bearer":[]}],"summary":"The board: every room and what is happening in it","tags":["Spa Rooms"]}},"/api/v1/spa-rooms/{id}":{"get":{"operationId":"SpaRoomController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SpaRoomEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Get a treatment room","tags":["Spa Rooms"]},"patch":{"description":"Billing changes apply to the next guest only. A treatment copies the terms when it opens, so one already under way keeps the price it was quoted.","operationId":"SpaRoomController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSpaRoomDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SpaRoomEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Edit a treatment room","tags":["Spa Rooms"]},"delete":{"operationId":"SpaRoomController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SpaRoomEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Retire a treatment room","tags":["Spa Rooms"]}},"/api/v1/spa-rooms/{id}/ready":{"post":{"description":"CLEANING → AVAILABLE. Refused while a treatment is running.","operationId":"SpaRoomController_markReady_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SpaRoomEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpaRoomEntity"}}}}},"security":[{"bearer":[]}],"summary":"Turned around and lettable again","tags":["Spa Rooms"]}},"/api/v1/spa-sessions":{"post":{"description":"Takes the room and opens a bill for the chosen `packages`. Follows Venue setup: with PAY_WHEN_ORDERING `prepay` is required and the packages (and `items`) are charged to the tapped card now; with PAY_AT_END `prepay` is refused and they go on the bill, paid after close with POST /v1/sales-orders/{salesOrderId}/settle. Several therapists may be named - four hands means two.","operationId":"SpaSessionController_open_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenSpaSessionDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SpaSessionEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpaSessionEntity"}}}},"409":{"description":"The room is already in use or out of service."}},"security":[{"bearer":[]}],"summary":"Start a treatment","tags":["Spa Treatments"]}},"/api/v1/spa-sessions/{id}/quote":{"get":{"description":"Writes nothing, so it is safe to poll for a live figure.","operationId":"SpaSessionController_quote_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SpaSessionQuoteDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"The running bill","tags":["Spa Treatments"]}},"/api/v1/spa-sessions/{id}/therapists":{"patch":{"description":"Replaces the list. Several therapists are allowed, and nothing stops one appearing on more than one treatment at a time - that is a rota rule.","operationId":"SpaSessionController_setTherapists_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetTherapistsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SpaSessionEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Set who is working the treatment","tags":["Spa Treatments"]}},"/api/v1/spa-sessions/{id}/planned-minutes":{"patch":{"description":"The total from when it began, not an amount to add. Informational only - the bill is worked out from the clock, so this never changes the price.","operationId":"SpaSessionController_setPlannedMinutes_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetSpaPlannedMinutesDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SpaSessionEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Set how long the treatment is booked for","tags":["Spa Treatments"]}},"/api/v1/spa-sessions/{id}/extend":{"post":{"description":"Charged to the tapped card now (PAY_WHEN_ORDERING), or put on the bill without a card (PAY_AT_END). The booked time grows by the package.","operationId":"SpaSessionController_extend_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtendSpaSessionDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SpaChargeResultDto"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpaChargeResultDto"}}}},"409":{"description":"An item is marked unavailable (sold out for now). The message names it, e.g. \"Not available right now: Mohinga\"."},"422":{"description":"The card cannot cover it."}},"security":[{"bearer":[]}],"summary":"Add a service package","tags":["Spa Treatments"]}},"/api/v1/spa-sessions/{id}/charges":{"post":{"description":"Priced on the server. Charged to the tapped card at once (PAY_WHEN_ORDERING), or put on the bill without a card (PAY_AT_END).","operationId":"SpaSessionController_chargeItems_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChargeSpaItemsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SpaChargeResultDto"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}},"409":{"description":"An item is marked unavailable (sold out for now). The message names it, e.g. \"Not available right now: Mohinga\"."},"422":{"description":"The card cannot cover it."}},"security":[{"bearer":[]}],"summary":"Order drinks, food or add-ons","tags":["Spa Treatments"]}},"/api/v1/spa-sessions/{id}/foc":{"post":{"description":"Added at full price and fully discounted under the comp reason; sent to the kitchen like any order. No card is charged.","operationId":"SpaSessionController_giveFree_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GiveFreeItemsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SpaChargeResultDto"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}},"409":{"description":"An item is marked unavailable (sold out for now). The message names it, e.g. \"Not available right now: Mohinga\"."}},"security":[{"bearer":[]}],"summary":"Give items on the house (FOC)","tags":["Spa Treatments"]}},"/api/v1/spa-sessions/{id}/lines/{lineId}/refund":{"post":{"description":"While the treatment is running. Refunds the card when it was paid; just removes it from an unpaid bill. Booked treatments are not refunded.","operationId":"SpaSessionController_refundLine_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"lineId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefundSpaLineDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SpaChargeResultDto"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpaChargeResultDto"}}}}},"security":[{"bearer":[]}],"summary":"Take an item off the bill","tags":["Spa Treatments"]}},"/api/v1/spa-sessions/{id}/pause":{"post":{"operationId":"SpaSessionController_pause_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SpaSessionEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpaSessionEntity"}}}}},"security":[{"bearer":[]}],"summary":"Stop the clock","tags":["Spa Treatments"]}},"/api/v1/spa-sessions/{id}/resume":{"post":{"operationId":"SpaSessionController_resume_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SpaSessionEntity"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpaSessionEntity"}}}}},"security":[{"bearer":[]}],"summary":"Restart the clock","tags":["Spa Treatments"]}},"/api/v1/spa-sessions/{id}/close":{"post":{"description":"Sends the room for cleaning. PAY_WHEN_ORDERING: the bill is closed with what was charged, plus a `tip` if one is sent, taken now. PAY_AT_END: the bill stays DRAFT with `amountDue`; pay it now with POST /v1/sales-orders/{salesOrderId}/settle (member card only when Venue setup says so). Older clock-billed treatments get their charge written as lines, one per rate window, and settle the same way.","operationId":"SpaSessionController_close_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CloseSpaSessionDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SpaSessionQuoteDto"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpaSessionQuoteDto"}}}}},"security":[{"bearer":[]}],"summary":"Finish the treatment and put it on the bill","tags":["Spa Treatments"]}},"/api/v1/tablet/visit":{"post":{"description":"The guest, their balance, and each live room on the card with its time and orders. Only the tapped card is shown.","operationId":"TabletController_visit_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TabletCardDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TabletVisitDto"}}}]}}}},"404":{"description":"No active card with that UID."}},"security":[{"bearer":[]}],"summary":"A tapped card's visit","tags":["Room Tablet"]}},"/api/v1/tablet/history":{"post":{"operationId":"TabletController_history_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TabletCardDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TabletHistoryEntryDto"}}}}]}}}}},"security":[{"bearer":[]}],"summary":"The tapped card's last 20 movements","tags":["Room Tablet"]}},"/api/v1/tablet/menu":{"get":{"operationId":"TabletController_menu_v1","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TabletMenuDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"What guests can order","tags":["Room Tablet"]}},"/api/v1/tablet/orders":{"post":{"description":"Priced on the server and charged at once to the card that started the treatment; the order goes to the kitchen and staff are alerted.","operationId":"TabletController_order_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TabletOrderDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TabletOrderResultDto"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TabletOrderResultDto"}}}},"409":{"description":"An item is marked unavailable (sold out for now). The message names it, e.g. \"Not available right now: Mohinga\"."},"422":{"description":"The card cannot cover it."}},"security":[{"bearer":[]}],"summary":"Order and pay with the tapped card","tags":["Room Tablet"]}},"/api/v1/tablet/extend":{"post":{"operationId":"TabletController_extend_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TabletExtendDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TabletOrderResultDto"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TabletOrderResultDto"}}}},"409":{"description":"An item is marked unavailable (sold out for now). The message names it, e.g. \"Not available right now: Mohinga\"."},"422":{"description":"The card cannot cover it."}},"security":[{"bearer":[]}],"summary":"Buy more sessions with the tapped card","tags":["Room Tablet"]}},"/api/v1/tablet/rooms":{"get":{"description":"Status, session length and price of every room, for a tablet's setup and its idle screen. Nothing about who is in them.","operationId":"TabletController_rooms_v1","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TabletRoomDto"}}}}]}}}}},"security":[{"bearer":[]}],"summary":"The spa rooms","tags":["Room Tablet"]}},"/api/v1/tablet/start":{"post":{"description":"Starts a treatment in the room for the chosen sessions, with anything ordered alongside, all charged to the tapped card at once.","operationId":"TabletController_start_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TabletStartDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/TabletStartResultDto"}}}]}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TabletStartResultDto"}}}},"409":{"description":"The room is in use or being prepared."},"422":{"description":"The card cannot cover it."}},"security":[{"bearer":[]}],"summary":"Take this room and pay with one tap","tags":["Room Tablet"]}},"/api/v1/room-orders":{"get":{"description":"With `pending=true`, the tablet orders nobody has acknowledged yet.","operationId":"RoomOrderController_list_v1","parameters":[{"name":"pending","required":false,"in":"query","description":"Only tablet orders nobody has acknowledged yet - the alerts.","schema":{"example":true,"type":"boolean"}},{"name":"locationId","required":false,"in":"query","schema":{"format":"uuid","example":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/RoomOrderViewDto"}}}}]}}}}},"security":[{"bearer":[]}],"summary":"Orders placed in spa rooms","tags":["Room Orders"]}},"/api/v1/room-orders/{id}/acknowledge":{"post":{"operationId":"RoomOrderController_acknowledge_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/RoomOrderViewDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Seen: clears the alert","tags":["Room Orders"]}},"/api/v1/room-orders/{id}/deliver":{"post":{"operationId":"RoomOrderController_deliver_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/RoomOrderViewDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Brought to the room: marks its items served","tags":["Room Orders"]}},"/api/v1/room-orders/{id}/claim-print":{"post":{"description":"Only the first terminal gets claimed=true and should print.","operationId":"RoomOrderController_claimPrint_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/RoomOrderPrintClaimDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Claim the ticket print","tags":["Room Orders"]}},"/api/v1/print-templates":{"post":{"description":"Any setting left out takes the built-in default for the type, so `{ \"type\": \"RECEIPT\", \"name\": \"Default receipt\" }` is a complete template. Types: RECEIPT (checkout), KITCHEN (KDS), FINANCE (office copy), SHIFT (end-of-shift report).","operationId":"PrintTemplateController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePrintTemplateDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PrintTemplateEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Create a print template","tags":["Print Templates"]},"get":{"operationId":"PrintTemplateController_findAll_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search keyword","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"default":"desc","type":"string","enum":["asc","desc"]}},{"name":"locationId","required":false,"in":"query","schema":{}},{"name":"type","required":false,"in":"query","schema":{"enum":["RECEIPT","KITCHEN","FINANCE","SHIFT"],"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PrintTemplateEntity"}},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}}}]}}}}},"security":[{"bearer":[]}],"summary":"List print templates","tags":["Print Templates"]}},"/api/v1/print-templates/resolve":{"get":{"description":"What a terminal calls before printing: the outlet's own default, else the default for every outlet, else the built-in layout. Never 404s. `source` says which one it was.","operationId":"PrintTemplateController_resolve_v1","parameters":[{"name":"type","required":true,"in":"query","description":"RECEIPT: the guest bill at checkout. KITCHEN: a KDS station ticket. FINANCE: the office copy of a bill. SHIFT: the end-of-shift report.","schema":{"example":"RECEIPT","type":"string","enum":["RECEIPT","KITCHEN","FINANCE","SHIFT"]}},{"name":"locationId","required":false,"in":"query","description":"The outlet printing. Leave out to get the tenant-wide one.","schema":{"format":"uuid","example":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ResolvedPrintTemplateDto"}}}]}}}}},"security":[{"bearer":[]}],"summary":"The template to print with","tags":["Print Templates"]}},"/api/v1/print-templates/fields":{"get":{"description":"Which settings apply to RECEIPT, KITCHEN, FINANCE or SHIFT, with their kind, options and the type's default. Any other switch is fixed at the default. Every template response carries the same list as `fields`.","operationId":"PrintTemplateController_fields_v1","parameters":[{"name":"type","required":true,"in":"query","schema":{"example":"KITCHEN","type":"string","enum":["RECEIPT","KITCHEN","FINANCE","SHIFT"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TemplateFieldDto"}}}}]}}}}},"security":[{"bearer":[]}],"summary":"The switches a template type has","tags":["Print Templates"]}},"/api/v1/print-templates/{id}":{"get":{"operationId":"PrintTemplateController_findOne_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PrintTemplateEntity"}}}]}}}},"404":{"description":"Print template not found."}},"security":[{"bearer":[]}],"summary":"Get a print template","tags":["Print Templates"]},"patch":{"description":"Settings merge: send only the switches that changed. `isDefault: true` takes over from the current default for the same outlet and type.","operationId":"PrintTemplateController_update_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePrintTemplateDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PrintTemplateEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Update a print template","tags":["Print Templates"]},"delete":{"description":"Deleting the default falls back to the tenant-wide or built-in layout.","operationId":"PrintTemplateController_remove_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GlobalResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PrintTemplateEntity"}}}]}}}}},"security":[{"bearer":[]}],"summary":"Delete a print template","tags":["Print Templates"]}}},"info":{"title":"VISION POS","description":"The VISION POS Backend API description","version":"1.0","contact":{}},"tags":[],"servers":[],"components":{"securitySchemes":{"bearer":{"scheme":"bearer","bearerFormat":"JWT","type":"http"}},"schemas":{"GlobalResponseDto":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Request successful"},"meta":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}}}},"required":["success","message"]},"TenantEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Grand Hotel Group"},"legalName":{"type":"string","nullable":true,"example":"Grand Hotel Group LLC"},"domain":{"type":"string","nullable":true,"example":"grandhotel.com"},"website":{"type":"string","nullable":true,"example":"https://grandhotel.com"},"logoUrl":{"type":"string","nullable":true,"example":"https://logo.url/logo.png"},"primaryContactName":{"type":"string","nullable":true,"example":"John Doe"},"primaryContactEmail":{"type":"string","nullable":true,"example":"john@grandhotel.com"},"primaryContactPhone":{"type":"string","nullable":true,"example":"+1234567890"},"address":{"type":"string","nullable":true,"example":"123 Main St"},"city":{"type":"string","nullable":true,"example":"New York"},"state":{"type":"string","nullable":true,"example":"NY"},"country":{"type":"string","nullable":true,"example":"USA"},"timezone":{"type":"string","nullable":true,"example":"Asia/Bangkok","description":"Null for a tenant created before timezones; filled in from the first sign-in."},"userIdPrefix":{"type":"string","nullable":true,"example":"SHW","description":"The letters every User ID in this tenant starts with."},"nextUserNumber":{"type":"number","example":12,"description":"The number the next user’s User ID gets."},"zipCode":{"type":"string","nullable":true,"example":"10001"},"status":{"type":"string","enum":["ACTIVE","INACTIVE","SUSPENDED","TRIAL"],"example":"ACTIVE"},"deletedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.148Z"}},"required":["id","name","nextUserNumber","status","createdAt"]},"TenantBusinessDto":{"type":"object","properties":{"name":{"type":"string","example":"Grand Spa"},"legalName":{"type":"string","nullable":true,"example":"Grand Spa Co., Ltd."},"address":{"type":"string","nullable":true,"example":"No. 12, Pyay Road"},"city":{"type":"string","nullable":true,"example":"Yangon"},"phone":{"type":"string","nullable":true,"example":"09 123 456 789"},"email":{"type":"string","nullable":true,"example":"hello@grandspa.com"},"website":{"type":"string","nullable":true,"example":"grandspa.com"},"logoUrl":{"type":"string","nullable":true}},"required":["name","legalName","address","city","phone","email","website","logoUrl"]},"UpdateTenantDto":{"type":"object","properties":{"timezone":{"type":"string","example":"Asia/Bangkok","description":"IANA timezone the business day is counted in: order numbers roll over at its midnight and reports file sales under its calendar. An outlet can override it. Changing it moves which day new sales are filed under; past sales keep theirs."},"name":{"type":"string","minLength":1,"maxLength":255,"example":"KFC","description":"The name of the tenant"},"legalName":{"type":"string","minLength":1,"maxLength":255,"example":"KFC Corporation","description":"The legal name"},"domain":{"type":"string","minLength":1,"maxLength":255,"example":"kfc.com","description":"The domain"},"website":{"type":"string","minLength":1,"maxLength":255,"example":"https://kfc.com","description":"The website"},"logoUrl":{"type":"string","minLength":1,"maxLength":255,"example":"https://logo.url","description":"The logo URL"},"primaryContactName":{"type":"string","minLength":1,"maxLength":255,"example":"Colonel Sanders","description":"Primary contact name"},"primaryContactEmail":{"type":"string","minLength":1,"maxLength":255,"example":"colonel@kfc.com","description":"Primary contact email"},"primaryContactPhone":{"type":"string","minLength":1,"maxLength":255,"example":"+1234567890","description":"Primary contact phone"},"address":{"type":"string","minLength":1,"maxLength":255,"example":"123 Fried Chicken St","description":"Address"},"city":{"type":"string","minLength":1,"maxLength":255,"example":"Louisville","description":"City"},"state":{"type":"string","minLength":1,"maxLength":255,"example":"Kentucky","description":"State"},"country":{"type":"string","minLength":1,"maxLength":255,"example":"USA","description":"Country"},"zipCode":{"type":"string","minLength":1,"maxLength":255,"example":"40213","description":"Zip code"}}},"UserEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid","description":"The tenant this user belongs to. A user belongs to exactly one."},"loginId":{"type":"string","nullable":true,"example":"SHW0001","description":"What the user signs in with: the tenant’s letters and a number, given by the system."},"email":{"type":"string","nullable":true,"example":"john@example.com","description":"Contact address only; not unique and not used to sign in."},"username":{"type":"string","nullable":true,"example":"john_doe"},"fullName":{"type":"string","nullable":true,"example":"John Doe"},"phoneNumber":{"type":"string","nullable":true,"example":"+1234567890"},"avatarUrl":{"type":"string","nullable":true,"example":"https://avatar.url"},"jobTitle":{"type":"string","nullable":true,"example":"Manager"},"status":{"type":"string","enum":["ACTIVE","INACTIVE","LOCKED","PENDING_VERIFICATION"],"example":"ACTIVE"},"lastLoginAt":{"format":"date-time","type":"string","nullable":true,"example":"2026-10-23T14:44:05.205Z"},"loginAttempts":{"type":"number","example":0},"lockoutUntil":{"format":"date-time","type":"string","nullable":true,"example":null},"preferredLanguage":{"type":"string","example":"EN"},"metadata":{"type":"object","additionalProperties":true,"properties":{}},"systemAdminId":{"type":"string","nullable":true,"example":null,"description":"Set only on the support account a system admin works through in this tenant."},"assignedBranchId":{"type":"string","nullable":true,"example":"uuid","description":"In user lists: the branch the user works at (the first branch among their roles)."},"isOwner":{"type":"boolean","example":false,"description":"Holds the Owner role. Only an Owner may edit, suspend or delete such a user."},"roles":{"type":"array","items":{"type":"object","properties":{"roleId":{"type":"string"},"roleName":{"type":"string"},"branchId":{"type":"string","nullable":true},"branchName":{"type":"string","nullable":true}},"required":["roleId","roleName","branchId","branchName"]}},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.206Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.206Z"}},"required":["id","tenantId","status","loginAttempts","preferredLanguage","createdAt","updatedAt"]},"CreateUserDto":{"type":"object","properties":{"email":{"type":"string","format":"email","example":"john@example.com","description":"Contact address only. Users sign in with the User ID the system gives them."},"password":{"type":"string","minLength":8,"maxLength":20,"example":"password123"},"username":{"type":"string","minLength":1,"maxLength":255,"description":"Ignored: the username is the User ID"},"fullName":{"type":"string","minLength":1,"maxLength":255,"example":"John Doe"},"phoneNumber":{"type":"string","nullable":true,"example":"+1234567890"},"avatarUrl":{"type":"string","nullable":true,"minLength":1,"maxLength":255,"example":"https://avatar.url"},"jobTitle":{"type":"string","nullable":true,"minLength":1,"maxLength":255,"example":"Manager"},"roleId":{"type":"string","format":"uuid","example":"uuid"},"branchId":{"type":"string","format":"uuid","example":"uuid"},"preferredLanguage":{"type":"string","minLength":1,"maxLength":255,"example":"EN"}},"required":["password","fullName"]},"UpdateUserDto":{"type":"object","properties":{"status":{"type":"string","enum":["ACTIVE","INACTIVE"],"description":"INACTIVE suspends the user: they cannot sign in, and a session they already have stops working. ACTIVE lets them back in."},"email":{"type":"string","format":"email","example":"john@example.com"},"password":{"type":"string","minLength":8,"maxLength":20,"example":"password123"},"username":{"type":"string","minLength":1,"maxLength":255,"description":"Ignored: the username is the User ID"},"fullName":{"type":"string","minLength":1,"maxLength":255,"example":"John Doe"},"phoneNumber":{"type":"string","nullable":true,"example":"+1234567890"},"avatarUrl":{"type":"string","nullable":true,"minLength":1,"maxLength":255,"example":"https://avatar.url"},"jobTitle":{"type":"string","nullable":true,"minLength":1,"maxLength":255,"example":"Manager"},"preferredLanguage":{"type":"string","minLength":1,"maxLength":255,"example":"en"},"roleId":{"type":"string","format":"uuid","example":"uuid","description":"Change the user's role. Replaces the role they had; the role must be this tenant's."},"branchId":{"type":"string","nullable":true,"format":"uuid","example":"uuid","description":"The branch the role applies in, sent with roleId. Null or absent: every branch."}}},"UserInfo":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"userId":{"type":"string","nullable":true,"example":"SHW0001","description":"What a user signs in with. Absent for a system_admin sign-in."},"email":{"type":"string","nullable":true,"example":"john@example.com"},"fullName":{"type":"string","example":"John Doe"},"type":{"enum":["user","system_admin"],"type":"string","example":"user"},"tenantId":{"type":"string","example":"uuid","description":"The tenant this user belongs to. Absent for a system_admin sign-in."}},"required":["id","email","fullName","type"]},"BranchAccess":{"type":"object","properties":{"branchId":{"type":"string","nullable":true,"example":"uuid","description":"Null means tenant-wide access rather than one branch."},"roles":{"example":["admin"],"type":"array","items":{"type":"string"}},"permissions":{"example":["inventory:product:read"],"description":"Permission strings in module:subject:action form.","type":"array","items":{"type":"string"}}},"required":["branchId","roles","permissions"]},"LoginResponseDto":{"type":"object","properties":{"access_token":{"type":"string","example":"jwt_token_here"},"refresh_token":{"type":"string","example":"refresh_token_here","description":"Lasts 7 days; swap it at POST /auth/refresh for a new access_token."},"user":{"$ref":"#/components/schemas/UserInfo"},"activeBranch":{"type":"string","nullable":true,"example":"uuid"},"access":{"type":"array","items":{"$ref":"#/components/schemas/BranchAccess"}}},"required":["access_token","refresh_token","user","activeBranch","access"]},"SignInDto":{"type":"object","properties":{"userId":{"type":"string","maxLength":100,"example":"SHW0001","description":"A user signs in with their User ID (letters and digits, any case). Give this, or send the User ID in `email` from an app not yet updated."},"email":{"type":"string","maxLength":255,"example":"admin@winterarc.asia","description":"A system admin signs in with their email. For a user, read as their User ID."},"password":{"type":"string","example":"password123","description":"The password of the user"},"type":{"default":"user","enum":["user","system_admin"],"type":"string","description":"The type of authentication. ( user, system_admin )"},"branchId":{"type":"string","format":"uuid","example":"123e4567-e89b-12d3-a456-426614174001","description":"The branch ID for context switching"},"timezone":{"type":"string","maxLength":64,"example":"Asia/Bangkok","description":"The device timezone: Intl.DateTimeFormat().resolvedOptions().timeZone. Send it on every sign-in. It is saved as the tenant timezone only when the tenant has none yet, so it fills in an existing tenant once and never overrides a setting."}},"required":["password"]},"RefreshResponseDto":{"type":"object","properties":{"access_token":{"type":"string","example":"jwt_token_here"},"refresh_token":{"type":"string","example":"refresh_token_here","description":"Replaces the one sent; keep this one."}},"required":["access_token","refresh_token"]},"RefreshDto":{"type":"object","properties":{"refresh_token":{"type":"string","example":"refresh_token_here"}},"required":["refresh_token"]},"ApprovalResponseDto":{"type":"object","properties":{"approval_token":{"type":"string","description":"Send as the x-approver-authorization header. Good for 5 minutes, for this permission only."},"approver":{"type":"object","properties":{"id":{"type":"string"},"fullName":{"type":"string","nullable":true}},"required":["id","fullName"]}},"required":["approval_token","approver"]},"ApproveDto":{"type":"object","properties":{"userId":{"type":"string","maxLength":100,"example":"MGR0001","description":"The manager's User ID"},"password":{"type":"string","maxLength":200,"example":"••••••"},"permission":{"type":"string","maxLength":100,"example":"pos:cash-variance:approve","description":"What is being approved"}},"required":["userId","password","permission"]},"SetActiveBranchDto":{"type":"object","properties":{"branchId":{"type":"string","nullable":true,"description":"The ID of the branch to set as active. Use null for tenant-wide access.","example":"branch-uuid-here"}},"required":["branchId"]},"SessionBranchAccessDto":{"type":"object","properties":{"branchId":{"type":"string","nullable":true,"example":"uuid","description":"Null means tenant-wide access rather than one branch."},"roles":{"example":["admin"],"type":"array","items":{"type":"string"}},"permissions":{"example":["inventory:product:read"],"description":"Permission strings in module:subject:action form.","type":"array","items":{"type":"string"}}},"required":["branchId","roles","permissions"]},"SessionUserDto":{"type":"object","properties":{"userId":{"type":"string","example":"uuid"},"username":{"type":"string","example":"johndoe"},"roles":{"example":["admin"],"type":"array","items":{"type":"string"}},"permissions":{"example":["inventory:product:read"],"description":"Flattened for the active branch.","type":"array","items":{"type":"string"}},"access":{"type":"array","items":{"$ref":"#/components/schemas/SessionBranchAccessDto"}},"isAdmin":{"type":"boolean","example":false,"description":"A system admin reads across tenants and has no tenantId."},"tenantId":{"type":"string","example":"uuid"},"branchId":{"type":"string","nullable":true,"example":"uuid"}},"required":["userId","username"]},"OnboardedTenantDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"name":{"type":"string","example":"FreshMart"},"domain":{"type":"string","nullable":true,"example":"freshmart.com"}},"required":["id","name"]},"OnboardedBranchDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"name":{"type":"string","example":"FreshMart Downtown"},"branchCode":{"type":"string","nullable":true,"example":"FM-DT"}},"required":["id","name"]},"OnboardedRoleDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Owner"}},"required":["id","name"]},"OnboardedOwnerDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"userId":{"type":"string","nullable":true,"example":"FRE0001","description":"What the owner signs in with. Give it to them with the password."},"email":{"type":"string","nullable":true,"example":"owner@freshmart.com"},"fullName":{"type":"string","nullable":true,"example":"Aung Kyaw"}},"required":["id","userId"]},"OnboardTenantResponseDto":{"type":"object","properties":{"tenant":{"$ref":"#/components/schemas/OnboardedTenantDto"},"branch":{"$ref":"#/components/schemas/OnboardedBranchDto"},"roles":{"description":"The starter roles created for this tenant.","type":"array","items":{"$ref":"#/components/schemas/OnboardedRoleDto"}},"modules":{"example":["common","iam","inventory","pos","sales"],"description":"The modules enabled for this tenant.","type":"array","items":{"type":"string"}},"owner":{"$ref":"#/components/schemas/OnboardedOwnerDto"}},"required":["tenant","branch","roles","modules","owner"]},"OnboardTenantInfoDto":{"type":"object","properties":{"name":{"type":"string","example":"Acme Corporation"},"timezone":{"type":"string","example":"Asia/Bangkok","description":"IANA timezone the business day is counted in: order numbers roll over at its midnight and reports file sales under its calendar. An outlet can override it. A browser can supply it: Intl.DateTimeFormat().resolvedOptions().timeZone."},"legalName":{"type":"string","example":"Acme Corp Ltd."},"domain":{"type":"string","example":"acme.com"},"website":{"type":"string","example":"https://acme.com"},"address":{"type":"string","example":"123 Main St"},"city":{"type":"string","example":"New York"},"state":{"type":"string","example":"NY"},"country":{"type":"string","example":"USA"},"zipCode":{"type":"string","example":"10001"}},"required":["name","timezone"]},"OnboardBranchInfoDto":{"type":"object","properties":{"name":{"type":"string","example":"Main Branch"},"branchCode":{"type":"string","example":"MB001"},"address":{"type":"string","example":"123 Main St"},"city":{"type":"string","example":"New York"},"phone":{"type":"string","example":"+1234567890"}},"required":["name"]},"OnboardOwnerInfoDto":{"type":"object","properties":{"email":{"type":"string","format":"email","example":"owner@acme.com","description":"Contact address only. The owner signs in with the User ID returned."},"password":{"type":"string","minLength":8,"maxLength":20,"example":"password123"},"username":{"type":"string","description":"Ignored: the username is the User ID"},"fullName":{"type":"string","example":"John Owner"},"phoneNumber":{"type":"string","example":"+1234567890"},"jobTitle":{"type":"string","example":"CEO"}},"required":["password","fullName"]},"OnboardTenantDto":{"type":"object","properties":{"tenant":{"$ref":"#/components/schemas/OnboardTenantInfoDto"},"branch":{"$ref":"#/components/schemas/OnboardBranchInfoDto"},"owner":{"$ref":"#/components/schemas/OnboardOwnerInfoDto"},"modules":{"example":["inventory","sales","pos","finance","reports"],"description":"Which optional modules this tenant may build roles from. Omit to enable all. The iam and common modules are always on.","type":"array","items":{"type":"string"}}},"required":["tenant","branch","owner"]},"TenantModulesDto":{"type":"object","properties":{"modules":{"example":["common","finance","iam","inventory","pos","reports","sales"],"description":"Every module this tenant may build roles from, including the always-on iam and common.","type":"array","items":{"type":"string"}}},"required":["modules"]},"SetTenantModulesResultDto":{"type":"object","properties":{"modules":{"example":["common","finance","iam","inventory","pos","reports","sales"],"description":"Every module this tenant may build roles from, including the always-on iam and common.","type":"array","items":{"type":"string"}},"removedRolePermissions":{"type":"number","example":27,"description":"Role-permission links removed because their module was switched off."},"removedOverrides":{"type":"number","example":0,"description":"User permission overrides removed because their module was switched off."},"grantedRolePermissions":{"type":"number","example":9,"description":"Permissions added to the tenant’s starter roles for newly enabled modules, so the module is actually usable."}},"required":["modules","removedRolePermissions","removedOverrides","grantedRolePermissions"]},"SetTenantModulesDto":{"type":"object","properties":{"modules":{"example":["inventory","sales","pos","finance","reports"],"description":"The optional modules this tenant may build roles from. The iam and common modules are always on and do not need to be listed. Modules left out are disabled, and permissions from them are removed from the tenant’s roles.","type":"array","items":{"type":"string"}}},"required":["modules"]},"ResetTenantDto":{"type":"object","properties":{"parts":{"minItems":1,"example":["sales","stock"],"description":"Parts to empty: sales, stock, guest-cards, customers, menu, floor, accounting, lists. Parts they depend on are added.","type":"array","items":{"type":"string"}},"confirmName":{"type":"string","example":"Esperado Lakeview Hotel Yangon","description":"The tenant's exact name, typed to confirm."}},"required":["parts","confirmName"]},"CreateUserAsAdminDto":{"type":"object","properties":{"email":{"type":"string","format":"email","example":"john@example.com","description":"Contact address only. Users sign in with the User ID the system gives them."},"password":{"type":"string","minLength":8,"maxLength":20,"example":"password123"},"username":{"type":"string","minLength":1,"maxLength":255,"description":"Ignored: the username is the User ID"},"fullName":{"type":"string","minLength":1,"maxLength":255,"example":"John Doe"},"phoneNumber":{"type":"string","nullable":true,"example":"+1234567890"},"avatarUrl":{"type":"string","nullable":true,"minLength":1,"maxLength":255,"example":"https://avatar.url"},"jobTitle":{"type":"string","nullable":true,"minLength":1,"maxLength":255,"example":"Manager"},"roleId":{"type":"string","format":"uuid","example":"uuid"},"branchId":{"type":"string","format":"uuid","example":"uuid"},"preferredLanguage":{"type":"string","minLength":1,"maxLength":255,"example":"EN"},"tenantId":{"type":"string","format":"uuid","example":"uuid"}},"required":["password","fullName","tenantId"]},"AssignPermissionsResultDto":{"type":"object","properties":{"count":{"type":"number","example":12,"description":"Permissions newly attached to the role. Ones it already held are not counted again, so re-sending the same list writes nothing."}},"required":["count"]},"AssignPermissionToRoleDto":{"type":"object","properties":{"roleId":{"type":"string","format":"uuid","example":"uuid"},"permissionIds":{"example":["uuid1","uuid2"],"type":"array","items":{"type":"string","format":"uuid"}}},"required":["roleId","permissionIds"]},"UserRoleBranchEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"userId":{"type":"string","example":"uuid"},"roleId":{"type":"string","example":"uuid"},"branchId":{"type":"string","nullable":true,"example":"uuid","description":"Null grants the role across every branch of the tenant."}},"required":["id","tenantId","userId","roleId"]},"AssignRoleToUserDto":{"type":"object","properties":{"userId":{"type":"string","format":"uuid","example":"uuid"},"roleId":{"type":"string","format":"uuid","example":"uuid"},"tenantId":{"type":"string","format":"uuid","example":"uuid"},"branchId":{"type":"string","format":"uuid","example":"uuid"}},"required":["userId","roleId","tenantId"]},"BranchEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Main Street Branch"},"branchCode":{"type":"string","nullable":true,"example":"BR-001"},"type":{"type":"string","enum":["RETAIL","WAREHOUSE","OFFICE","CLINIC","HOTEL","RESTAURANT"],"example":"RETAIL"},"address":{"type":"string","nullable":true,"example":"456 Main St"},"city":{"type":"string","nullable":true,"example":"San Francisco"},"state":{"type":"string","nullable":true,"example":"CA"},"country":{"type":"string","nullable":true,"example":"USA"},"zipCode":{"type":"string","nullable":true,"example":"94101"},"phone":{"type":"string","nullable":true,"example":"+1987654321"},"email":{"type":"string","nullable":true,"example":"main@branch.com"},"latitude":{"type":"string","nullable":true,"example":"37.7749"},"longitude":{"type":"string","nullable":true,"example":"-122.4194"},"status":{"type":"string","enum":["ACTIVE","INACTIVE","TEMPORARILY_CLOSED","MAINTENANCE"],"example":"ACTIVE"},"openingHours":{"type":"object","example":{"mon":"08:00-18:00"}},"managerId":{"type":"string","nullable":true,"example":"uuid"},"locationId":{"type":"string","nullable":true,"example":null,"description":"The operational outlet this branch corresponds to. Branch is the permission hierarchy; Location is what transactions key off. Null until a tenant maps them."},"deletedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.281Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.281Z"}},"required":["id","tenantId","name","type","status","createdAt","updatedAt"]},"CreateBranchDto":{"type":"object","properties":{"name":{"type":"string","example":"Main Branch"},"tenantId":{"type":"string","format":"uuid","example":"uuid"},"branchCode":{"type":"string","example":"BR001"},"type":{"type":"string","enum":["RETAIL","WAREHOUSE","OFFICE","CLINIC","HOTEL","RESTAURANT"],"default":"RESTAURANT"},"address":{"type":"string","example":"123 Main St"},"city":{"type":"string","example":"New York"},"state":{"type":"string","example":"NY"},"country":{"type":"string","example":"USA"},"zipCode":{"type":"string","example":"10001"},"phone":{"type":"string","example":"+1234567890"},"email":{"type":"string","example":"branch@example.com"},"latitude":{"type":"string","example":40.7128},"longitude":{"type":"string","example":-74.006},"openingHours":{"type":"object","example":{"mon":"09:00-17:00"}}},"required":["name","tenantId"]},"UpdateBranchDto":{"type":"object","properties":{"name":{"type":"string","example":"Main Branch"},"branchCode":{"type":"string","example":"BR001"},"type":{"type":"string","enum":["RETAIL","WAREHOUSE","OFFICE","CLINIC","HOTEL","RESTAURANT"],"default":"RESTAURANT"},"address":{"type":"string","example":"123 Main St"},"city":{"type":"string","example":"New York"},"state":{"type":"string","example":"NY"},"country":{"type":"string","example":"USA"},"zipCode":{"type":"string","example":"10001"},"phone":{"type":"string","example":"+1234567890"},"email":{"type":"string","example":"branch@example.com"},"latitude":{"type":"string","example":40.7128},"longitude":{"type":"string","example":-74.006},"openingHours":{"type":"object","example":{"mon":"09:00-17:00"}}}},"RoleEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"parentId":{"type":"string","nullable":true,"example":"uuid"},"name":{"type":"string","example":"Store Manager"},"isSystemDefault":{"type":"boolean","example":false},"isOwner":{"type":"boolean","example":false,"description":"The Owner role: always holds every permission and cannot be deleted."}},"required":["id","tenantId","name","isSystemDefault","isOwner"]},"CreateRoleDto":{"type":"object","properties":{"name":{"type":"string","example":"Admin"},"tenantId":{"type":"string","format":"uuid","example":"uuid","description":"System admins only. Tenant users always create roles in their own tenant."},"parentId":{"type":"string","format":"uuid","example":"uuid"},"isSystemDefault":{"type":"boolean","default":false,"example":false}},"required":["name"]},"PermissionEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"module":{"type":"string","example":"INVENTORY"},"subject":{"type":"string","example":"PRODUCT"},"action":{"type":"string","example":"READ"},"description":{"type":"string","nullable":true,"example":"Can read products"}},"required":["id","module","subject","action"]},"UpdateRoleDto":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"example":"Night Shift Cashier"},"parentId":{"type":"string","format":"uuid","example":"uuid","nullable":true}}},"RolePermissionsResultDto":{"type":"object","properties":{"count":{"type":"number","example":12,"description":"How many permissions the role holds as a result of the call."}},"required":["count"]},"SetRolePermissionsDto":{"type":"object","properties":{"permissionIds":{"uniqueItems":true,"example":["uuid-1","uuid-2"],"description":"The complete set of permissions this role should hold. Anything not listed is removed.","type":"array","items":{"type":"string","format":"uuid"}}},"required":["permissionIds"]},"CategoryEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"parentId":{"type":"string","nullable":true,"example":"uuid"},"name":{"type":"string","example":"Electronics"},"description":{"type":"string","nullable":true,"example":"Electronic devices and accessories"},"sortOrder":{"type":"number","example":0},"deletedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.361Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.361Z"}},"required":["id","tenantId","name","sortOrder","createdAt","updatedAt"]},"CreateCategoryDto":{"type":"object","properties":{"name":{"type":"string","example":"Electronics"},"tenantId":{"type":"string","format":"uuid","example":"uuid"},"parentId":{"type":"string","format":"uuid","example":"uuid"},"description":{"type":"string","example":"Electronic devices and accessories"},"sortOrder":{"type":"number","minimum":0,"example":0}},"required":["name","tenantId"]},"UpdateCategoryDto":{"type":"object","properties":{"name":{"type":"string","example":"Electronics"},"parentId":{"type":"string","format":"uuid","example":"uuid"},"description":{"type":"string","example":"Electronic devices and accessories"},"sortOrder":{"type":"number","minimum":0,"example":0}}},"UomClassEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Weight"}},"required":["id","tenantId","name"]},"CreateUomClassDto":{"type":"object","properties":{"name":{"type":"string","example":"Weight"},"tenantId":{"type":"string","format":"uuid","example":"uuid"}},"required":["name","tenantId"]},"UpdateUomClassDto":{"type":"object","properties":{"name":{"type":"string","example":"Weight"}}},"UomEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"classId":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Kilogram"},"abbreviation":{"type":"string","example":"kg"},"conversionRateToBase":{"type":"string","example":"1.000000"}},"required":["id","classId","name","abbreviation","conversionRateToBase"]},"CreateUomDto":{"type":"object","properties":{"name":{"type":"string","example":"Kilogram"},"classId":{"type":"string","format":"uuid","example":"uuid"},"abbreviation":{"type":"string","example":"kg"},"conversionRateToBase":{"type":"string","example":"1.000000"}},"required":["name","classId","abbreviation","conversionRateToBase"]},"UpdateUomDto":{"type":"object","properties":{"name":{"type":"string","example":"Kilogram"},"classId":{"type":"string","format":"uuid","example":"uuid"},"abbreviation":{"type":"string","example":"kg"},"conversionRateToBase":{"type":"string","example":"1.000000"}}},"ProductEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"categoryId":{"type":"string","nullable":true,"example":"uuid"},"baseSku":{"type":"string","example":"SKU-IP15"},"name":{"type":"string","example":"iPhone 15"},"basePrice":{"type":"string","example":"999.0000"},"baseUomId":{"type":"string","example":"uuid"},"globalAttributes":{"type":"object","additionalProperties":true,"properties":{}},"imageUrl":{"type":"string","nullable":true,"example":"/uploads/products/iphone15.jpg"},"trackingType":{"type":"string","nullable":true,"example":"STANDARD"},"isTaxable":{"type":"boolean","nullable":true,"example":true},"isAvailable":{"type":"boolean","example":true,"description":"Can be ordered right now. False = sold out for now: still listed (show it muted) but no new order line can take it."},"taxRateIds":{"example":["uuid"],"description":"Its own taxes. Empty: a taxable product pays the shop's default taxes.","type":"array","items":{"type":"string"}},"taxRates":{"description":"Its own taxes, each in full.","example":[{"id":"uuid","name":"Commercial Tax","ratePercentage":"0.0500","isPriceInclusive":false,"appliesToServiceCharge":true}],"type":"array","items":{"type":"object"}},"taxRateId":{"type":"string","nullable":true,"example":"uuid","deprecated":true,"description":"The first of taxRateIds, for tills not yet updated."},"kind":{"type":"string","enum":["ITEM","SERVICE","RENTAL"],"example":"ITEM","description":"ITEM: goods (menu, stock). SERVICE: something a person does (SPA package, hostess). RENTAL: the use of a place (KTV room, table)."},"soldAt":{"type":"array","example":["KTV"],"description":"POS areas it is sold at. Empty: every area.","items":{"type":"string","enum":["BAR","SPA","KTV"]}},"soldBy":{"type":"string","enum":["EACH","TIME"],"example":"EACH","description":"EACH: price x quantity. TIME: price per time block."},"timeBlockMinutes":{"type":"number","nullable":true,"example":60,"description":"TIME only: minutes one unit buys (60 = per hour)."},"minimumBlocks":{"type":"number","nullable":true,"example":1,"description":"TIME only: the fewest units sold at once."},"rents":{"type":"string","nullable":true,"enum":["KTV_ROOM","SPA_ROOM","TABLE"],"example":"KTV_ROOM","description":"RENTAL only: the kind of place it rents."},"rentalPlaceIds":{"example":[],"description":"RENTAL only: the places it rents. Empty: every place of that kind.","type":"array","items":{"type":"string"}},"askWhoServed":{"type":"boolean","example":false,"description":"SERVICE only: the till asks which staff member gave it."},"chargeMode":{"type":"string","nullable":true,"enum":["PAY_FIRST","CLOCK"],"example":"PAY_FIRST","description":"RENTAL sold by TIME only. PAY_FIRST: blocks paid up front (KTV hours). CLOCK: time runs from opening until the bill closes (pool table, VIP room)."},"autoApply":{"type":"boolean","example":false,"description":"RENTAL of tables or SPA rooms only: added by itself when the place opens."},"deletedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.440Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.440Z"},"totalOnHand":{"type":"string","example":"250.0000","description":"Computed on-hand stock across active variants (scoped by locationId when provided). Only populated by list endpoints."}},"required":["id","tenantId","baseSku","name","basePrice","baseUomId","isTaxable","isAvailable","kind","soldAt","soldBy","rentalPlaceIds","askWhoServed","autoApply","createdAt","updatedAt"]},"CreateProductDto":{"type":"object","properties":{"name":{"type":"string","example":"iPhone 15"},"tenantId":{"type":"string","format":"uuid","example":"uuid"},"baseSku":{"type":"string","example":"SKU-IP15"},"basePrice":{"type":"string","example":"999.0000"},"baseUomId":{"type":"string","format":"uuid","example":"uuid"},"categoryId":{"type":"string","format":"uuid","example":"uuid"},"globalAttributes":{"type":"object","example":{}},"imageUrl":{"type":"string","example":"/uploads/products/iphone15.jpg"},"trackingType":{"type":"string","example":"STANDARD"},"isTaxable":{"type":"boolean","example":true},"isAvailable":{"type":"boolean","example":true,"default":true,"description":"Can be ordered right now. False = sold out for now: still listed (show it muted) but no new order line can take it."},"taxRateIds":{"maxItems":10,"example":["uuid"],"description":"Its own taxes, replacing any it had. Empty: the shop's default taxes. They must all be included in the price, or all added on top.","type":"array","items":{"type":"string","format":"uuid"}},"taxRateId":{"type":"string","nullable":true,"format":"uuid","example":"uuid","deprecated":true,"description":"One tax of its own, for tills not yet updated; null clears them. Ignored when taxRateIds is sent."},"kind":{"type":"string","enum":["ITEM","SERVICE","RENTAL"],"default":"ITEM","description":"ITEM: goods (menu, stock). SERVICE: something a person does (SPA package, hostess). RENTAL: the use of a place (KTV room, table)."},"soldAt":{"type":"array","uniqueItems":true,"example":["KTV"],"description":"POS areas it is sold at. Empty or left out: every area.","items":{"type":"string","enum":["BAR","SPA","KTV"]}},"soldBy":{"type":"string","enum":["EACH","TIME"],"default":"EACH","description":"EACH: price x quantity. TIME: price per time block."},"timeBlockMinutes":{"type":"number","minimum":1,"maximum":1440,"example":60,"description":"Required for TIME: minutes one unit buys (60 = per hour)."},"minimumBlocks":{"type":"number","minimum":1,"maximum":100,"example":1,"default":1,"description":"TIME only: the fewest units sold at once."},"rents":{"type":"string","enum":["KTV_ROOM","SPA_ROOM","TABLE"],"description":"Required for RENTAL: the kind of place it rents."},"rentalPlaceIds":{"uniqueItems":true,"maxItems":500,"example":[],"description":"RENTAL only: the rooms or tables it rents. Empty or left out: every place of that kind.","type":"array","items":{"type":"string","format":"uuid"}},"askWhoServed":{"type":"boolean","example":false,"description":"SERVICE only: the till asks which staff member gave it."},"chargeMode":{"type":"string","enum":["PAY_FIRST","CLOCK"],"default":"PAY_FIRST","description":"RENTAL sold by TIME only. PAY_FIRST: paid up front in blocks. CLOCK: time runs from opening until the bill closes. KTV rooms are always PAY_FIRST."},"autoApply":{"type":"boolean","example":false,"description":"RENTAL of tables or SPA rooms only: added by itself when the place opens."}},"required":["name","tenantId","baseSku","basePrice","baseUomId"]},"UpdateProductDto":{"type":"object","properties":{"name":{"type":"string","example":"iPhone 15"},"baseSku":{"type":"string","example":"SKU-IP15"},"basePrice":{"type":"string","example":"999.0000"},"baseUomId":{"type":"string","format":"uuid","example":"uuid"},"categoryId":{"type":"string","format":"uuid","example":"uuid"},"globalAttributes":{"type":"object","example":{}},"imageUrl":{"type":"string","example":"/uploads/products/iphone15.jpg"},"trackingType":{"type":"string","example":"STANDARD"},"isTaxable":{"type":"boolean","example":true},"isAvailable":{"type":"boolean","example":true,"default":true,"description":"Can be ordered right now. False = sold out for now: still listed (show it muted) but no new order line can take it."},"taxRateIds":{"maxItems":10,"example":["uuid"],"description":"Its own taxes, replacing any it had. Empty: the shop's default taxes. They must all be included in the price, or all added on top.","type":"array","items":{"type":"string","format":"uuid"}},"taxRateId":{"type":"string","nullable":true,"format":"uuid","example":"uuid","deprecated":true,"description":"One tax of its own, for tills not yet updated; null clears them. Ignored when taxRateIds is sent."},"kind":{"type":"string","enum":["ITEM","SERVICE","RENTAL"],"default":"ITEM","description":"ITEM: goods (menu, stock). SERVICE: something a person does (SPA package, hostess). RENTAL: the use of a place (KTV room, table)."},"soldAt":{"type":"array","uniqueItems":true,"example":["KTV"],"description":"POS areas it is sold at. Empty or left out: every area.","items":{"type":"string","enum":["BAR","SPA","KTV"]}},"soldBy":{"type":"string","enum":["EACH","TIME"],"default":"EACH","description":"EACH: price x quantity. TIME: price per time block."},"timeBlockMinutes":{"type":"number","minimum":1,"maximum":1440,"example":60,"description":"Required for TIME: minutes one unit buys (60 = per hour)."},"minimumBlocks":{"type":"number","minimum":1,"maximum":100,"example":1,"default":1,"description":"TIME only: the fewest units sold at once."},"rents":{"type":"string","enum":["KTV_ROOM","SPA_ROOM","TABLE"],"description":"Required for RENTAL: the kind of place it rents."},"rentalPlaceIds":{"uniqueItems":true,"maxItems":500,"example":[],"description":"RENTAL only: the rooms or tables it rents. Empty or left out: every place of that kind.","type":"array","items":{"type":"string","format":"uuid"}},"askWhoServed":{"type":"boolean","example":false,"description":"SERVICE only: the till asks which staff member gave it."},"chargeMode":{"type":"string","enum":["PAY_FIRST","CLOCK"],"default":"PAY_FIRST","description":"RENTAL sold by TIME only. PAY_FIRST: paid up front in blocks. CLOCK: time runs from opening until the bill closes. KTV rooms are always PAY_FIRST."},"autoApply":{"type":"boolean","example":false,"description":"RENTAL of tables or SPA rooms only: added by itself when the place opens."}}},"SetAvailabilityDto":{"type":"object","properties":{"isAvailable":{"type":"boolean","example":false,"description":"False marks it sold out for now; true makes it orderable again."}},"required":["isAvailable"]},"MenuItemIngredientDto":{"type":"object","properties":{"ingredientVariantId":{"type":"string","format":"uuid","example":"uuid","description":"The ingredient variant used up."},"quantity":{"type":"number","minimum":1,"example":50,"description":"How much one item uses."},"uomId":{"type":"string","format":"uuid","example":"uuid","description":"The unit of that quantity."}},"required":["ingredientVariantId","quantity","uomId"]},"MenuItemSetupViewDto":{"type":"object","properties":{"modifierGroupIds":{"type":"array","items":{"type":"string"}},"ingredients":{"type":"array","items":{"$ref":"#/components/schemas/MenuItemIngredientDto"}}},"required":["modifierGroupIds","ingredients"]},"MenuItemSetupDto":{"type":"object","properties":{"modifierGroupIds":{"description":"The add-on and choice groups offered with the item, in order. Sets exactly these; omit to leave them.","type":"array","items":{"type":"string","format":"uuid"}},"ingredients":{"description":"What one item uses up when sold (its recipe). An empty list stops tracking ingredients; omit to leave them.","type":"array","items":{"$ref":"#/components/schemas/MenuItemIngredientDto"}}}},"ProductVariantEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"productId":{"type":"string","example":"uuid"},"variantSku":{"type":"string","example":"SKU-IP15-BLK-128"},"barcode":{"type":"string","nullable":true,"example":"1234567890123"},"matrixOptions":{"type":"object","additionalProperties":true,"example":{"color":"Black","storage":"128GB"}},"priceModifier":{"type":"string","nullable":true,"example":"50.0000"},"imageUrl":{"type":"string","nullable":true,"example":"/uploads/products/iphone15-black.jpg"},"deletedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.455Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.455Z"}},"required":["id","productId","variantSku","matrixOptions","createdAt","updatedAt"]},"CreateProductVariantDto":{"type":"object","properties":{"variantSku":{"type":"string","example":"SKU-IP15-BLK-128"},"matrixOptions":{"type":"object","example":{"color":"Black","storage":"128GB"}},"barcode":{"type":"string","example":"1234567890123"},"priceModifier":{"type":"string","example":"50.0000"},"imageUrl":{"type":"string","example":"/uploads/products/iphone15-black.jpg"}},"required":["variantSku","matrixOptions"]},"UpdateProductVariantDto":{"type":"object","properties":{"variantSku":{"type":"string","example":"SKU-IP15-BLK-128"},"matrixOptions":{"type":"object","example":{"color":"Black","storage":"128GB"}},"barcode":{"type":"string","example":"1234567890123"},"priceModifier":{"type":"string","example":"50.0000"},"imageUrl":{"type":"string","example":"/uploads/products/iphone15-black.jpg"}}},"DefaultTaxRateDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Commercial tax"},"ratePercentage":{"type":"string","example":"0.0500","description":"A fraction: 0.05 is 5%."},"isPriceInclusive":{"type":"boolean","example":false},"appliesToServiceCharge":{"type":"boolean","example":true,"description":"Also charged on the service charge."}},"required":["id","name","ratePercentage","isPriceInclusive","appliesToServiceCharge"]},"VenueSettingDto":{"type":"object","properties":{"tenantId":{"type":"string","example":"uuid"},"spaEnabled":{"type":"boolean","example":true,"description":"SPA rooms can be started."},"spaMenuOrdering":{"type":"boolean","example":true,"description":"Guests may order food and drinks during a treatment."},"ktvEnabled":{"type":"boolean","example":true,"description":"KTV rooms can be started."},"ktvMenuOrdering":{"type":"boolean","example":true,"description":"Guests may order food and drinks in a KTV room."},"paymentTiming":{"type":"string","enum":["PAY_WHEN_ORDERING","PAY_AT_END"],"example":"PAY_WHEN_ORDERING","description":"PAY_WHEN_ORDERING: each start, extension and order is paid on the spot. PAY_AT_END: the bill stays open and is paid in full at close."},"roomCardOnly":{"type":"boolean","example":true,"description":"No longer used: SPA and KTV rooms take every active payment method. Kept so older tills reading it do not break."},"maxPromotionsPerItem":{"type":"number","example":1,"description":"How many promotions one item can get at once. When more are running, the highest priority wins, then the biggest saving."},"maxPromotionsPerBill":{"type":"number","nullable":true,"example":2,"description":"How many different promotions one bill can use; null for no limit. Once a bill has used them, later orders on it only get those same promotions."},"currency":{"type":"string","enum":["MMK","USD"],"example":"MMK","description":"The money customers pay in. Receipts print 100,000 MMK or $ 100,000."},"trackStock":{"type":"boolean","example":true,"description":"Sales check and deduct stock. False for a business without inventory: menu items sell without stock and the till lists them all."},"defaultTaxRateIds":{"example":["uuid"],"description":"Taxes every taxable product that has no taxes of its own. Empty: those products are not taxed.","type":"array","items":{"type":"string"}},"defaultTaxRates":{"description":"The default rates themselves, so a till can price with them.","type":"array","items":{"$ref":"#/components/schemas/DefaultTaxRateDto"}},"defaultTaxRateId":{"type":"string","nullable":true,"example":"uuid","deprecated":true,"description":"The first of defaultTaxRateIds, for tills not yet updated."},"defaultTaxRate":{"nullable":true,"deprecated":true,"description":"The first of defaultTaxRates, for tills not yet updated.","allOf":[{"$ref":"#/components/schemas/DefaultTaxRateDto"}]},"serviceChargeBps":{"type":"number","example":1000,"description":"Service charge in basis points: 1000 is 10%. Worked out by the server on what the items come to after discounts and before tax."},"serviceChargeOnBar":{"type":"boolean","example":true,"description":"Bar and table bills add it."},"serviceChargeOnSpa":{"type":"boolean","example":true,"description":"SPA bills add it."},"serviceChargeOnKtv":{"type":"boolean","example":true,"description":"KTV bills add it."},"updatedAt":{"format":"date-time","type":"string","nullable":true,"example":null,"description":"When the settings were last saved; null while still on the defaults."}},"required":["tenantId","spaEnabled","spaMenuOrdering","ktvEnabled","ktvMenuOrdering","paymentTiming","roomCardOnly","maxPromotionsPerItem","maxPromotionsPerBill","currency","trackStock","defaultTaxRateIds","defaultTaxRates","defaultTaxRateId","defaultTaxRate","serviceChargeBps","serviceChargeOnBar","serviceChargeOnSpa","serviceChargeOnKtv"]},"UpdateVenueSettingDto":{"type":"object","properties":{"spaEnabled":{"type":"boolean","example":true},"spaMenuOrdering":{"type":"boolean","example":true},"ktvEnabled":{"type":"boolean","example":true},"ktvMenuOrdering":{"type":"boolean","example":true},"paymentTiming":{"type":"string","enum":["PAY_WHEN_ORDERING","PAY_AT_END"]},"roomCardOnly":{"type":"boolean","example":true},"maxPromotionsPerItem":{"type":"number","minimum":1,"maximum":10,"example":1},"maxPromotionsPerBill":{"type":"number","nullable":true,"minimum":1,"maximum":20,"example":2,"description":"Null: no limit per bill."},"currency":{"type":"string","enum":["MMK","USD"]},"trackStock":{"type":"boolean","example":true},"defaultTaxRateIds":{"maxItems":10,"example":["uuid"],"description":"Replaces the default taxes. Empty clears them. They must all be included in the price, or all added on top.","type":"array","items":{"type":"string","format":"uuid"}},"defaultTaxRateId":{"type":"string","nullable":true,"format":"uuid","example":"uuid","deprecated":true,"description":"One default tax, for tills not yet updated; null clears them. Ignored when defaultTaxRateIds is sent."},"serviceChargeBps":{"type":"number","minimum":0,"maximum":5000,"example":1000},"serviceChargeOnBar":{"type":"boolean","example":true},"serviceChargeOnSpa":{"type":"boolean","example":true},"serviceChargeOnKtv":{"type":"boolean","example":true}}},"LocationEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"parentLocationId":{"type":"string","nullable":true,"example":"uuid"},"name":{"type":"string","example":"Main Warehouse"},"type":{"type":"string","example":"warehouse"},"deletedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.477Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.477Z"}},"required":["id","tenantId","name","type","createdAt","updatedAt"]},"CreateLocationDto":{"type":"object","properties":{"name":{"type":"string","example":"Main Warehouse"},"tenantId":{"type":"string","format":"uuid","example":"uuid"},"parentLocationId":{"type":"string","format":"uuid","example":"uuid"},"type":{"type":"string","example":"warehouse"}},"required":["name","tenantId","type"]},"UpdateLocationDto":{"type":"object","properties":{"name":{"type":"string","example":"Main Warehouse"},"parentLocationId":{"type":"string","format":"uuid","example":"uuid"},"type":{"type":"string","example":"warehouse"}}},"VendorEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Acme Supplies"},"createdAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"}},"required":["id","tenantId","name","createdAt","updatedAt"]},"CreateVendorDto":{"type":"object","properties":{"name":{"type":"string","example":"Acme Supplies"},"tenantId":{"type":"string","format":"uuid","example":"uuid"}},"required":["name","tenantId"]},"UpdateVendorDto":{"type":"object","properties":{"name":{"type":"string","example":"Acme Supplies"}}},"TransferOrderEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"sourceLocationId":{"type":"string","example":"uuid"},"transitLocationId":{"type":"string","example":"uuid"},"destinationLocationId":{"type":"string","example":"uuid"},"transferNumber":{"type":"string","example":"TO-2026-0001"},"status":{"type":"string","nullable":true,"example":"DRAFT","enum":["DRAFT","SHIPPED","PARTIALLY_RECEIVED","COMPLETED"]},"shippedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"receivedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdBy":{"type":"string","nullable":true,"example":"uuid"},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.514Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.514Z"}},"required":["id","tenantId","sourceLocationId","transitLocationId","destinationLocationId","transferNumber","createdAt","updatedAt"]},"CreateTransferOrderDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"sourceLocationId":{"type":"string","format":"uuid","example":"uuid"},"transitLocationId":{"type":"string","format":"uuid","example":"uuid"},"destinationLocationId":{"type":"string","format":"uuid","example":"uuid"},"transferNumber":{"type":"string","example":"TO-2026-0001"},"createdBy":{"type":"string","format":"uuid","example":"uuid"}},"required":["tenantId","sourceLocationId","transitLocationId","destinationLocationId","transferNumber"]},"UpdateTransferOrderDto":{"type":"object","properties":{"sourceLocationId":{"type":"string","format":"uuid","example":"uuid"},"transitLocationId":{"type":"string","format":"uuid","example":"uuid"},"destinationLocationId":{"type":"string","format":"uuid","example":"uuid"},"transferNumber":{"type":"string","example":"TO-2026-0001"},"createdBy":{"type":"string","format":"uuid","example":"uuid"}}},"TransferOrderLineEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"transferOrderId":{"type":"string","example":"uuid"},"productId":{"type":"string","example":"uuid"},"requestedQuantity":{"type":"string","example":"10.0000"},"shippedQuantity":{"type":"string","nullable":true,"example":"0.0000"},"receivedQuantity":{"type":"string","nullable":true,"example":"0.0000"},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.538Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.539Z"}},"required":["id","transferOrderId","productId","requestedQuantity","createdAt","updatedAt"]},"CreateTransferOrderLineDto":{"type":"object","properties":{"productId":{"type":"string","format":"uuid","example":"uuid"},"requestedQuantity":{"type":"string","example":"10.0000"},"shippedQuantity":{"type":"string","example":"0.0000"},"receivedQuantity":{"type":"string","example":"0.0000"}},"required":["productId","requestedQuantity"]},"UpdateTransferOrderLineDto":{"type":"object","properties":{"productId":{"type":"string","format":"uuid","example":"uuid"},"requestedQuantity":{"type":"string","example":"10.0000"},"shippedQuantity":{"type":"string","example":"0.0000"},"receivedQuantity":{"type":"string","example":"0.0000"}}},"PurchaseRequisitionEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"requestedBy":{"type":"string","example":"uuid"},"department":{"type":"string","nullable":true,"example":"Engineering"},"justification":{"type":"string","nullable":true,"example":"Urgent restock of office supplies"},"status":{"type":"string","nullable":true,"example":"PENDING_APPROVAL","enum":["PENDING_APPROVAL","APPROVED","REJECTED"]},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.559Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.560Z"}},"required":["id","tenantId","requestedBy","createdAt","updatedAt"]},"CreatePurchaseRequisitionDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"requestedBy":{"type":"string","format":"uuid","example":"uuid"},"department":{"type":"string","example":"Engineering"},"justification":{"type":"string","example":"Urgent restock of office supplies"}},"required":["tenantId","requestedBy"]},"UpdatePurchaseRequisitionDto":{"type":"object","properties":{"requestedBy":{"type":"string","format":"uuid","example":"uuid"},"department":{"type":"string","example":"Engineering"},"justification":{"type":"string","example":"Urgent restock of office supplies"}}},"PurchaseOrderEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"requisitionId":{"type":"string","nullable":true,"example":"uuid"},"vendorId":{"type":"string","example":"uuid"},"poNumber":{"type":"string","example":"PO-2026-0001"},"currency":{"type":"string","example":"USD"},"expectedDeliveryDate":{"format":"date-time","type":"string","nullable":true,"example":"2026-04-15"},"status":{"type":"string","nullable":true,"example":"DRAFT","enum":["DRAFT","ISSUED","PARTIAL_RECEIPT","FULFILLED","CLOSED"]},"totalAmount":{"type":"string","example":"15000.00"},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.574Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.574Z"}},"required":["id","tenantId","vendorId","poNumber","currency","totalAmount","createdAt","updatedAt"]},"CreatePurchaseOrderDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"vendorId":{"type":"string","format":"uuid","example":"uuid"},"poNumber":{"type":"string","example":"PO-2026-0001"},"currency":{"type":"string","minLength":3,"maxLength":3,"example":"USD"},"totalAmount":{"type":"string","example":"15000.00"},"requisitionId":{"type":"string","format":"uuid","example":"uuid"},"expectedDeliveryDate":{"type":"string","example":"2026-04-15"}},"required":["tenantId","vendorId","poNumber","currency","totalAmount"]},"UpdatePurchaseOrderDto":{"type":"object","properties":{"vendorId":{"type":"string","format":"uuid","example":"uuid"},"poNumber":{"type":"string","example":"PO-2026-0001"},"currency":{"type":"string","minLength":3,"maxLength":3,"example":"USD"},"totalAmount":{"type":"string","example":"15000.00"},"requisitionId":{"type":"string","format":"uuid","example":"uuid"},"expectedDeliveryDate":{"type":"string","example":"2026-04-15"}}},"GoodsReceivedNoteEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"purchaseOrderId":{"type":"string","example":"uuid"},"receivingLocationId":{"type":"string","example":"uuid"},"grnNumber":{"type":"string","example":"GRN-2026-0001"},"receivedBy":{"type":"string","nullable":true,"example":"uuid"},"receivedAt":{"format":"date-time","type":"string","nullable":true,"example":"2026-10-23T14:44:05.580Z"},"status":{"type":"string","nullable":true,"example":"INSPECTING","enum":["INSPECTING","ACCEPTED","REJECTED"]},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.580Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.580Z"}},"required":["id","tenantId","purchaseOrderId","receivingLocationId","grnNumber","createdAt","updatedAt"]},"CreateGoodsReceivedNoteDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"purchaseOrderId":{"type":"string","format":"uuid","example":"uuid"},"receivingLocationId":{"type":"string","format":"uuid","example":"uuid"},"grnNumber":{"type":"string","example":"GRN-2026-0001"},"receivedBy":{"type":"string","format":"uuid","example":"uuid"}},"required":["tenantId","purchaseOrderId","receivingLocationId","grnNumber"]},"UpdateGoodsReceivedNoteDto":{"type":"object","properties":{"purchaseOrderId":{"type":"string","format":"uuid","example":"uuid"},"receivingLocationId":{"type":"string","format":"uuid","example":"uuid"},"grnNumber":{"type":"string","example":"GRN-2026-0001"},"receivedBy":{"type":"string","format":"uuid","example":"uuid"}}},"GrnLineEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"grnId":{"type":"string","example":"uuid"},"poLineId":{"type":"string","example":"uuid"},"productId":{"type":"string","example":"uuid"},"receivedQuantity":{"type":"string","example":"100.0000"},"acceptedQuantity":{"type":"string","nullable":true,"example":"95.0000"},"rejectedQuantity":{"type":"string","nullable":true,"example":"5.0000"},"inventoryLedgerPosted":{"type":"boolean","nullable":true,"example":false},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.586Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.586Z"}},"required":["id","grnId","poLineId","productId","receivedQuantity","createdAt","updatedAt"]},"CreateGrnLineDto":{"type":"object","properties":{"poLineId":{"type":"string","format":"uuid","example":"uuid"},"productId":{"type":"string","format":"uuid","example":"uuid"},"receivedQuantity":{"type":"string","example":"100.0000"},"acceptedQuantity":{"type":"string","example":"95.0000"},"rejectedQuantity":{"type":"string","example":"5.0000"},"inventoryLedgerPosted":{"type":"boolean","example":false}},"required":["poLineId","productId","receivedQuantity"]},"UpdateGrnLineDto":{"type":"object","properties":{"poLineId":{"type":"string","format":"uuid","example":"uuid"},"productId":{"type":"string","format":"uuid","example":"uuid"},"receivedQuantity":{"type":"string","example":"100.0000"},"acceptedQuantity":{"type":"string","example":"95.0000"},"rejectedQuantity":{"type":"string","example":"5.0000"},"inventoryLedgerPosted":{"type":"boolean","example":false}}},"VendorInvoiceEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"vendorId":{"type":"string","example":"uuid"},"invoiceNumber":{"type":"string","example":"INV-2026-0001"},"invoiceType":{"type":"string","example":"STANDARD"},"matchedPoId":{"type":"string","nullable":true,"example":"uuid"},"matchedGrnId":{"type":"string","nullable":true,"example":"uuid"},"totalAmount":{"type":"string","example":"15000.00"},"status":{"type":"string","nullable":true,"example":"UNPAID","enum":["UNPAID","PARTIALLY_PAID","PAID"]},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.593Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.593Z"}},"required":["id","tenantId","vendorId","invoiceNumber","invoiceType","totalAmount","createdAt","updatedAt"]},"CreateVendorInvoiceDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"vendorId":{"type":"string","format":"uuid","example":"uuid"},"invoiceNumber":{"type":"string","example":"INV-2026-0001"},"invoiceType":{"type":"string","example":"STANDARD"},"totalAmount":{"type":"string","example":"15000.00"},"matchedPoId":{"type":"string","format":"uuid","example":"uuid"},"matchedGrnId":{"type":"string","format":"uuid","example":"uuid"}},"required":["tenantId","vendorId","invoiceNumber","invoiceType","totalAmount"]},"UpdateVendorInvoiceDto":{"type":"object","properties":{"vendorId":{"type":"string","format":"uuid","example":"uuid"},"invoiceNumber":{"type":"string","example":"INV-2026-0001"},"invoiceType":{"type":"string","example":"STANDARD"},"totalAmount":{"type":"string","example":"15000.00"},"matchedPoId":{"type":"string","format":"uuid","example":"uuid"},"matchedGrnId":{"type":"string","format":"uuid","example":"uuid"}}},"LandedCostAllocationEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"sourceInvoiceId":{"type":"string","example":"uuid"},"targetGrnId":{"type":"string","example":"uuid"},"targetGrnLineId":{"type":"string","example":"uuid"},"allocationMethod":{"type":"string","example":"BY_VALUE"},"allocatedAmount":{"type":"string","example":"500.00"},"glJournalPosted":{"type":"boolean","nullable":true,"example":false},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.599Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.599Z"}},"required":["id","tenantId","sourceInvoiceId","targetGrnId","targetGrnLineId","allocationMethod","allocatedAmount","createdAt","updatedAt"]},"CreateLandedCostAllocationDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"sourceInvoiceId":{"type":"string","format":"uuid","example":"uuid"},"targetGrnId":{"type":"string","format":"uuid","example":"uuid"},"targetGrnLineId":{"type":"string","format":"uuid","example":"uuid"},"allocationMethod":{"type":"string","example":"BY_VALUE"},"allocatedAmount":{"type":"string","example":"500.00"},"glJournalPosted":{"type":"boolean","example":false}},"required":["tenantId","sourceInvoiceId","targetGrnId","targetGrnLineId","allocationMethod","allocatedAmount"]},"UpdateLandedCostAllocationDto":{"type":"object","properties":{"sourceInvoiceId":{"type":"string","format":"uuid","example":"uuid"},"targetGrnId":{"type":"string","format":"uuid","example":"uuid"},"targetGrnLineId":{"type":"string","format":"uuid","example":"uuid"},"allocationMethod":{"type":"string","example":"BY_VALUE"},"allocatedAmount":{"type":"string","example":"500.00"},"glJournalPosted":{"type":"boolean","example":false}}},"CustomerEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"accountType":{"type":"string","nullable":true,"example":"RETAIL"},"name":{"type":"string","example":"Walk-In Customer"},"phone":{"type":"string","nullable":true,"example":"09123456789"},"email":{"type":"string","nullable":true,"example":"customer@example.com"},"hasCreditAccount":{"type":"boolean","nullable":true,"example":false},"maxCreditLimit":{"type":"string","nullable":true,"example":"0.0000"},"currentCreditBalance":{"type":"string","nullable":true,"example":"0.0000"},"paymentTermsDays":{"type":"number","nullable":true,"example":0},"loyaltyTier":{"type":"string","nullable":true,"example":"BRONZE"},"lifetimePointsEarned":{"type":"number","nullable":true,"example":0},"createdAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"}},"required":["id","tenantId","name","createdAt","updatedAt"]},"CreateCustomerDto":{"type":"object","properties":{"name":{"type":"string","example":"Walk-In Customer"},"tenantId":{"type":"string","format":"uuid","example":"uuid"},"phone":{"type":"string","example":"09123456789"},"email":{"type":"string","format":"email","example":"customer@example.com"},"accountType":{"type":"string","example":"RETAIL"},"hasCreditAccount":{"type":"boolean","example":false},"maxCreditLimit":{"type":"string","example":"5000.0000"},"paymentTermsDays":{"type":"number","minimum":0,"example":30},"loyaltyTier":{"type":"string","example":"BRONZE"}},"required":["name","tenantId"]},"UpdateCustomerDto":{"type":"object","properties":{"name":{"type":"string","example":"Walk-In Customer"},"phone":{"type":"string","example":"09123456789"},"email":{"type":"string","format":"email","example":"customer@example.com"},"accountType":{"type":"string","example":"RETAIL"},"hasCreditAccount":{"type":"boolean","example":false},"maxCreditLimit":{"type":"string","example":"5000.0000"},"paymentTermsDays":{"type":"number","minimum":0,"example":30},"loyaltyTier":{"type":"string","example":"BRONZE"}}},"LoyaltyLedgerEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"customerId":{"type":"string","example":"uuid"},"transactionType":{"type":"string","example":"EARN"},"points":{"type":"number","example":100},"referenceOrderId":{"type":"string","nullable":true,"example":"uuid"},"expiryDate":{"format":"date-time","type":"string","nullable":true,"example":"2026-12-31"},"createdAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"}},"required":["id","tenantId","customerId","transactionType","points","createdAt","updatedAt"]},"CreateLoyaltyLedgerDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"transactionType":{"type":"string","example":"EARN"},"points":{"type":"number","example":100},"referenceOrderId":{"type":"string","format":"uuid","example":"uuid"},"expiryDate":{"format":"date-time","type":"string","example":"2026-12-31"}},"required":["tenantId","transactionType","points"]},"UpdateLoyaltyLedgerDto":{"type":"object","properties":{"transactionType":{"type":"string","example":"EARN"},"points":{"type":"number","example":100},"referenceOrderId":{"type":"string","format":"uuid","example":"uuid"},"expiryDate":{"format":"date-time","type":"string","example":"2026-12-31"}}},"CustomerInteractionEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"customerId":{"type":"string","example":"uuid"},"agentId":{"type":"string","nullable":true,"example":"uuid"},"interactionChannel":{"type":"string","example":"EMAIL"},"interactionType":{"type":"string","example":"INQUIRY"},"summary":{"type":"string","example":"Customer asked about product availability"},"detailedNotes":{"type":"string","nullable":true,"example":"Detailed notes here..."},"externalReferenceId":{"type":"string","nullable":true,"example":"EXT-REF-001"},"interactionDate":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"}},"required":["id","tenantId","customerId","interactionChannel","interactionType","summary","interactionDate","updatedAt"]},"CreateCustomerInteractionDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"agentId":{"type":"string","format":"uuid","example":"uuid"},"interactionChannel":{"type":"string","example":"EMAIL"},"interactionType":{"type":"string","example":"INQUIRY"},"summary":{"type":"string","example":"Customer asked about product availability"},"detailedNotes":{"type":"string","example":"Detailed notes here..."},"externalReferenceId":{"type":"string","example":"EXT-REF-001"}},"required":["tenantId","interactionChannel","interactionType","summary"]},"UpdateCustomerInteractionDto":{"type":"object","properties":{"agentId":{"type":"string","format":"uuid","example":"uuid"},"interactionChannel":{"type":"string","example":"EMAIL"},"interactionType":{"type":"string","example":"INQUIRY"},"summary":{"type":"string","example":"Customer asked about product availability"},"detailedNotes":{"type":"string","example":"Detailed notes here..."},"externalReferenceId":{"type":"string","example":"EXT-REF-001"}}},"CashierDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"loginId":{"type":"object","example":"SHW0001","nullable":true,"description":"The ID the staff member signs in with."},"name":{"type":"string","example":"Aung Aung"}},"required":["id","loginId","name"]},"SalesOrderEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"customerId":{"type":"string","nullable":true,"example":"uuid"},"locationId":{"type":"string","nullable":true,"example":"uuid"},"orderNumber":{"type":"string","example":"SO-R01-20260728-0001"},"businessDate":{"type":"string","example":"2026-07-28"},"salesChannel":{"type":"string","example":"POS"},"serviceType":{"type":"string","nullable":true,"enum":["DINE_IN","TAKEAWAY","DELIVERY","COUNTER"],"example":"DINE_IN"},"posType":{"type":"string","enum":["BAR","SPA","KTV"],"example":"BAR","description":"Which POS sold it: SPA, KTV, or BAR for every other till and table."},"idempotencyKey":{"type":"string","nullable":true,"example":"idem-key-001"},"subtotal":{"type":"string","example":"100.0000"},"totalDiscount":{"type":"string","nullable":true,"example":"10.0000"},"discountReasonId":{"type":"string","nullable":true,"example":"uuid"},"totalTax":{"type":"string","nullable":true,"example":"5.0000"},"tipAmount":{"type":"string","example":"5.0000"},"serviceCharge":{"type":"string","example":"3.0000"},"serviceChargeTax":{"type":"string","example":"0.1500","description":"Tax on the service charge; part of totalTax."},"serviceChargeTaxes":{"type":"object","example":[{"taxRateId":"uuid","name":"Commercial Tax","ratePercentage":"0.05","taxAmount":"0.15"}],"description":"Each tax on the service charge."},"grandTotal":{"type":"string","example":"95.0000"},"status":{"type":"string","nullable":true,"example":"DRAFT","enum":["DRAFT","COMPLETED","ON_HOLD_CREDIT","VOIDED","PARTIALLY_REFUNDED","REFUNDED"]},"pickupNumber":{"type":"string","nullable":true,"example":"A47","description":"Display number for counter pickup"},"pickedUpAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"},"cashier":{"nullable":true,"description":"Who took the latest payment, to print as the cashier. Only on a single order.","allOf":[{"$ref":"#/components/schemas/CashierDto"}]}},"required":["id","tenantId","orderNumber","businessDate","salesChannel","posType","subtotal","tipAmount","serviceCharge","serviceChargeTax","serviceChargeTaxes","grandTotal","createdAt","updatedAt"]},"CreateSalesOrderDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"customerId":{"type":"string","format":"uuid","example":"uuid"},"locationId":{"type":"string","format":"uuid","example":"uuid"},"orderNumber":{"type":"string","example":"SO-WEB-20260728-0001","description":"Auto-generated when omitted. Supplying one risks colliding with the tenant-scoped uniqueness constraint."},"salesChannel":{"type":"string","example":"POS"},"idempotencyKey":{"type":"string","example":"idem-key-001"},"subtotal":{"type":"string","example":"100.0000"},"totalDiscount":{"type":"string","example":"10.0000"},"totalTax":{"type":"string","example":"5.0000"},"grandTotal":{"type":"string","example":"95.0000"},"status":{"type":"string","example":"DRAFT","enum":["DRAFT","COMPLETED","ON_HOLD_CREDIT","VOIDED","PARTIALLY_REFUNDED","REFUNDED"]}},"required":["tenantId","salesChannel","subtotal","grandTotal"]},"SettleOrderResponseDto":{"type":"object","properties":{"orderId":{"type":"string","example":"uuid"},"orderNumber":{"type":"string","example":"SO-R02-20260921-0001"},"grandTotal":{"type":"string","example":"100000.0000","description":"Recomputed from the lines as they stand, plus tip and service."},"totalPaid":{"type":"string","example":"100000.0000"},"change":{"type":"string","example":"0.0000"},"status":{"type":"string","example":"COMPLETED"},"cashier":{"nullable":true,"description":"Who took the payment, to print as the cashier.","allOf":[{"$ref":"#/components/schemas/CashierDto"}]}},"required":["orderId","orderNumber","grandTotal","totalPaid","change","status"]},"CheckoutPaymentDto":{"type":"object","properties":{"paymentMethodId":{"type":"string","format":"uuid","example":"uuid","description":"Payment method ID"},"amount":{"type":"string","example":"100.0000","description":"Payment amount (includes any tip). May be omitted for a guest-card tender, which then covers whatever the rest of the bill comes to - the server knows the tier discount and the client does not have to compute it."},"guestCardId":{"type":"string","format":"uuid","example":"uuid","description":"The card that was tapped. Required when the payment method is a guest card, and meaningless otherwise. The wallet behind it is charged as part of the same transaction that closes the order."},"tipAmount":{"type":"string","example":"5.0000","description":"Tip amount included in this payment"},"transactionReference":{"type":"string","example":"TXN-12345","description":"External transaction reference (card, mobile, etc.)"}},"required":["paymentMethodId"]},"SettleOrderDto":{"type":"object","properties":{"payments":{"minItems":1,"description":"How the bill is being paid. Same shape as checkout, so a split between cash and a guest card works the same way. A guest-card tender may leave its amount out and will be charged whatever the rest of the bill comes to.","type":"array","items":{"$ref":"#/components/schemas/CheckoutPaymentDto"}},"customerId":{"type":"string","format":"uuid","example":"uuid","description":"Customer the bill is being put on. Required for a CUSTOMER_CREDIT tender, and what loyalty points are awarded against."},"posSessionId":{"type":"string","format":"uuid","example":"uuid"},"tipAmount":{"type":"string","example":"5.0000","description":"Tip on the whole bill, added to the total being settled."},"serviceCharge":{"type":"string","example":"3.0000","deprecated":true,"description":"Ignored: the server adds the shop's service charge. Kept so older tills still validate."},"idempotencyKey":{"type":"string","maxLength":255,"example":"settle-order-001","description":"Reuse when retrying after a network error and the settled order is returned rather than the bill being paid twice."}},"required":["payments"]},"BillPreviewDto":{"type":"object","properties":{"orderId":{"type":"string","example":"uuid"},"subtotal":{"type":"string","example":"81000.0000","description":"Items at their prices, before discounts."},"totalDiscount":{"type":"string","example":"1000.0000","description":"Line discounts plus the bill discount asked about."},"addedTax":{"type":"string","example":"4000.0000","description":"Tax added on top of the item prices."},"serviceCharge":{"type":"string","example":"8000.0000"},"serviceChargeTax":{"type":"string","example":"400.0000"},"grandTotal":{"type":"string","example":"92400.0000","description":"What to collect, before tip and any member-card tier discount. Settle works it out the same way."}},"required":["orderId","subtotal","totalDiscount","addedTax","serviceCharge","serviceChargeTax","grandTotal"]},"UpdateSalesOrderDto":{"type":"object","properties":{"customerId":{"type":"string","format":"uuid","example":"uuid"},"locationId":{"type":"string","format":"uuid","example":"uuid"},"salesChannel":{"type":"string","example":"POS"},"status":{"type":"string","example":"DRAFT","enum":["DRAFT","COMPLETED","ON_HOLD_CREDIT","VOIDED","PARTIALLY_REFUNDED","REFUNDED"]}}},"SalesOrderLineEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"salesOrderId":{"type":"string","example":"uuid"},"variantId":{"type":"string","example":"uuid"},"quantity":{"type":"string","example":"2.0000"},"unitPrice":{"type":"string","example":"49.9900"},"lineDiscount":{"type":"string","nullable":true,"example":"0.0000"},"taxRateId":{"type":"string","nullable":true,"example":"uuid"},"taxAmount":{"type":"string","nullable":true,"example":"5.0000"},"taxInclusive":{"type":"boolean","example":false,"description":"Whether taxAmount is already inside unitPrice. When true it is not added to what is owed."},"appliedPromotionId":{"type":"string","nullable":true,"example":"uuid"},"status":{"type":"string","nullable":true,"enum":["PENDING","FIRED","READY","SERVED","VOIDED","COMPED"],"example":"PENDING"},"firedAt":{"format":"date-time","type":"string","nullable":true,"example":"2026-01-01T00:00:00.000Z"},"voidedAt":{"format":"date-time","type":"string","nullable":true,"example":"2026-01-01T00:00:00.000Z"},"voidReasonId":{"type":"string","nullable":true,"example":"uuid"},"compReasonId":{"type":"string","nullable":true,"example":"uuid"},"courseType":{"type":"string","nullable":true,"example":"MAIN"},"selectedModifiers":{"type":"object","additionalProperties":true,"properties":{},"description":"JSONB array of selected modifiers"},"seatNumber":{"type":"number","nullable":true,"example":1},"productName":{"type":"string","nullable":true,"example":"Orange juice","description":"The product name when it was sold; filled in by the server."},"variantName":{"type":"string","nullable":true,"example":"Large"},"categoryId":{"type":"string","nullable":true,"example":"uuid"},"categoryName":{"type":"string","nullable":true,"example":"Juices"},"hostessId":{"type":"string","nullable":true,"example":"uuid","description":"The hostess who gave this service, when the product asks who served."},"createdAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"}},"required":["id","salesOrderId","variantId","quantity","unitPrice","taxInclusive","selectedModifiers","createdAt","updatedAt"]},"SelectedModifierDto":{"type":"object","properties":{"modifierId":{"type":"string","format":"uuid","example":"uuid"},"name":{"type":"string","example":"Bacon"},"priceDelta":{"type":"string","example":"2.0000"}},"required":["modifierId","name","priceDelta"]},"CreateSalesOrderLineDto":{"type":"object","properties":{"variantId":{"type":"string","format":"uuid","example":"uuid"},"quantity":{"type":"string","example":"2.0000"},"unitPrice":{"type":"string","example":"49.9900"},"lineDiscount":{"type":"string","example":"0.0000"},"taxRateId":{"type":"string","format":"uuid","example":"uuid"},"taxAmount":{"type":"string","example":"0.0000"},"appliedPromotionId":{"type":"string","format":"uuid","example":"uuid"},"courseType":{"type":"string","example":"MAIN","description":"Course (APPETIZER, MAIN, DESSERT, etc.)"},"selectedModifiers":{"description":"Snapshot of modifier choices made for this line","type":"array","items":{"$ref":"#/components/schemas/SelectedModifierDto"}},"seatNumber":{"type":"number","minimum":1,"example":1}},"required":["variantId","quantity","unitPrice"]},"UpdateSalesOrderLineDto":{"type":"object","properties":{"variantId":{"type":"string","format":"uuid","example":"uuid"},"quantity":{"type":"string","example":"2.0000"},"unitPrice":{"type":"string","example":"49.9900"},"lineDiscount":{"type":"string","example":"0.0000"},"taxRateId":{"type":"string","format":"uuid","example":"uuid"},"taxAmount":{"type":"string","example":"0.0000"},"appliedPromotionId":{"type":"string","format":"uuid","example":"uuid"},"courseType":{"type":"string","example":"MAIN","description":"Course (APPETIZER, MAIN, DESSERT, etc.)"},"selectedModifiers":{"description":"Snapshot of modifier choices made for this line","type":"array","items":{"$ref":"#/components/schemas/SelectedModifierDto"}},"seatNumber":{"type":"number","minimum":1,"example":1}}},"VoidLineDto":{"type":"object","properties":{"voidReasonId":{"type":"string","format":"uuid","example":"uuid"},"notes":{"type":"string","example":"Customer changed their mind after firing"}},"required":["voidReasonId"]},"CompLineDto":{"type":"object","properties":{"compReasonId":{"type":"string","format":"uuid","example":"uuid"},"notes":{"type":"string","example":"Birthday on the house"}},"required":["compReasonId"]},"OrderPaymentEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"salesOrderId":{"type":"string","example":"uuid"},"paymentMethodId":{"type":"string","example":"uuid"},"posSessionId":{"type":"string","nullable":true,"example":"uuid"},"amount":{"type":"string","example":"100.0000"},"tipAmount":{"type":"string","example":"5.0000"},"transactionReference":{"type":"string","nullable":true,"example":"TXN-12345"},"paymentDate":{"format":"date-time","type":"string","nullable":true,"example":"2026-01-01T00:00:00.000Z"},"walletLedgerEntryId":{"type":"string","nullable":true,"example":null,"description":"The wallet debit that funded this payment, for a guest-card tender. Unique, so one ledger entry can never fund two payments."},"takenById":{"type":"string","nullable":true,"example":"uuid","description":"The staff user who took the payment."},"updatedAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"}},"required":["id","tenantId","salesOrderId","paymentMethodId","amount","tipAmount","takenById","updatedAt"]},"CreateOrderPaymentDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"paymentMethodId":{"type":"string","format":"uuid","example":"uuid"},"posSessionId":{"type":"string","format":"uuid","example":"uuid"},"amount":{"type":"string","example":"100.0000"},"tipAmount":{"type":"string","example":"5.0000"},"transactionReference":{"type":"string","example":"TXN-12345"}},"required":["tenantId","paymentMethodId","amount"]},"UpdateOrderPaymentDto":{"type":"object","properties":{"transactionReference":{"type":"string","example":"TXN-12345"}}},"CheckoutResponseDto":{"type":"object","properties":{"orderId":{"type":"string","example":"uuid"},"orderNumber":{"type":"string","example":"SO-20260402-0001"},"grandTotal":{"type":"string","example":"95.0000"},"totalPaid":{"type":"string","example":"100.0000"},"change":{"type":"string","example":"5.0000","description":"Change to return (cash overpayment)"},"status":{"type":"string","example":"COMPLETED"},"lines":{"description":"Order line items","type":"array","items":{"$ref":"#/components/schemas/SalesOrderLineEntity"}},"payments":{"description":"What was recorded against each tender. A cash row holds what was handed over, so it can exceed the bill by the change given back.","type":"array","items":{"$ref":"#/components/schemas/OrderPaymentEntity"}},"cashier":{"nullable":true,"description":"Who took the payment, to print as the cashier.","allOf":[{"$ref":"#/components/schemas/CashierDto"}]}},"required":["orderId","orderNumber","grandTotal","totalPaid","change","status","lines","payments"]},"CheckoutItemDto":{"type":"object","properties":{"variantId":{"type":"string","format":"uuid","example":"uuid","description":"Product variant ID"},"quantity":{"type":"string","example":"1.0000","description":"Quantity to purchase"},"lineDiscount":{"type":"string","example":"5.0000","description":"Per-line discount amount"}},"required":["variantId","quantity"]},"CheckoutDto":{"type":"object","properties":{"locationId":{"type":"string","format":"uuid","example":"uuid","description":"Location/store ID"},"salesChannel":{"type":"string","example":"POS","description":"Sales channel (POS, ONLINE)"},"customerId":{"type":"string","format":"uuid","example":"uuid","description":"Customer ID"},"posSessionId":{"type":"string","format":"uuid","example":"uuid","description":"POS session ID"},"serviceType":{"type":"string","enum":["DINE_IN","TAKEAWAY","DELIVERY","COUNTER"],"description":"DINE_IN, TAKEAWAY, DELIVERY, COUNTER"},"lineStatus":{"type":"string","enum":["PENDING","FIRED","READY","SERVED","VOIDED","COMPED"],"description":"Initial line status. Defaults to SERVED (instant retail). Use PENDING for counter/QSR orders that need kitchen prep — fire to KDS afterwards."},"tipAmount":{"type":"string","example":"5.0000","description":"Total tip amount on this order"},"serviceCharge":{"type":"string","example":"3.0000","deprecated":true,"description":"Ignored: the server adds the shop's service charge. Kept so older tills still validate."},"discountReasonId":{"type":"string","format":"uuid","example":"uuid","description":"Discount reason for any order-level discount"},"idempotencyKey":{"type":"string","example":"idem-key-001","description":"Idempotency key to prevent duplicate orders"},"items":{"minItems":1,"description":"Cart items","type":"array","items":{"$ref":"#/components/schemas/CheckoutItemDto"}},"payments":{"minItems":1,"description":"Payments","type":"array","items":{"$ref":"#/components/schemas/CheckoutPaymentDto"}}},"required":["locationId","salesChannel","items","payments"]},"ReceiptHeaderDto":{"type":"object","properties":{"businessName":{"type":"string","example":"Acme Corp"},"legalName":{"type":"string","nullable":true,"example":"Acme Corporation Ltd."},"logoUrl":{"type":"string","nullable":true,"example":"https://example.com/logo.png"},"address":{"type":"string","nullable":true,"example":"123 Main Street"},"city":{"type":"string","nullable":true,"example":"New York"},"state":{"type":"string","nullable":true,"example":"NY"},"country":{"type":"string","nullable":true,"example":"US"},"zipCode":{"type":"string","nullable":true,"example":"10001"},"phone":{"type":"string","nullable":true,"example":"+1-555-0100"},"email":{"type":"string","nullable":true,"example":"info@acme.com"},"website":{"type":"string","nullable":true,"example":"https://acme.com"}},"required":["businessName"]},"ReceiptOrderInfoDto":{"type":"object","properties":{"receiptNumber":{"type":"string","example":"RCP-20260402-0001"},"orderNumber":{"type":"string","example":"SO-20260402-0001"},"dateTime":{"format":"date-time","type":"string","example":"2026-04-02T10:30:00.000Z"},"salesChannel":{"type":"string","example":"POS"},"locationName":{"type":"string","nullable":true,"example":"Main Store"}},"required":["receiptNumber","orderNumber","dateTime","salesChannel"]},"ReceiptCustomerDto":{"type":"object","properties":{"name":{"type":"string","example":"John Doe"},"phone":{"type":"string","nullable":true,"example":"+1-555-0199"},"email":{"type":"string","nullable":true,"example":"john@example.com"},"loyaltyTier":{"type":"string","nullable":true,"example":"GOLD"},"pointsEarned":{"type":"number","example":95,"description":"Loyalty points earned from this order"}},"required":["name","pointsEarned"]},"ReceiptLineItemDto":{"type":"object","properties":{"productName":{"type":"string","example":"Wireless Mouse"},"variantSku":{"type":"string","example":"WM-BLK-001"},"barcode":{"type":"string","nullable":true,"example":"4901234567890"},"variantOptions":{"type":"object","example":{"color":"Black","size":"Standard"},"description":"Variant options (color, size, etc.)"},"quantity":{"type":"string","example":"2.0000"},"unitPrice":{"type":"string","example":"29.9900"},"lineDiscount":{"type":"string","example":"0.0000"},"taxAmount":{"type":"string","example":"4.2000"},"lineTotal":{"type":"string","example":"64.1800"}},"required":["productName","variantSku","quantity","unitPrice","lineDiscount","taxAmount","lineTotal"]},"ReceiptTaxSummaryLineDto":{"type":"object","properties":{"taxName":{"type":"string","example":"VAT 7%"},"ratePercentage":{"type":"string","example":"0.0700"},"taxableAmount":{"type":"string","example":"59.9800"},"taxAmount":{"type":"string","example":"4.2000"}},"required":["taxName","ratePercentage","taxableAmount","taxAmount"]},"ReceiptTotalsDto":{"type":"object","properties":{"subtotal":{"type":"string","example":"59.9800"},"totalDiscount":{"type":"string","example":"0.0000"},"totalTax":{"type":"string","example":"4.2000","description":"All tax, the tax on the service charge included."},"serviceCharge":{"type":"string","example":"6.0000"},"serviceChargeTax":{"type":"string","example":"0.3000","description":"The part of totalTax charged on the service charge."},"tipAmount":{"type":"string","example":"0.0000"},"grandTotal":{"type":"string","example":"64.1800"}},"required":["subtotal","totalDiscount","totalTax","serviceCharge","serviceChargeTax","tipAmount","grandTotal"]},"ReceiptPaymentDto":{"type":"object","properties":{"methodName":{"type":"string","example":"CASH"},"amount":{"type":"string","example":"70.0000"},"transactionReference":{"type":"string","nullable":true,"example":"TXN-12345"},"paymentDate":{"format":"date-time","type":"string","nullable":true,"example":"2026-04-02T10:30:00.000Z"}},"required":["methodName","amount"]},"ReceiptPaymentSummaryDto":{"type":"object","properties":{"payments":{"type":"array","items":{"$ref":"#/components/schemas/ReceiptPaymentDto"}},"totalPaid":{"type":"string","example":"70.0000"},"changeDue":{"type":"string","example":"5.8200"}},"required":["payments","totalPaid","changeDue"]},"ReceiptFooterDto":{"type":"object","properties":{"message":{"type":"string","example":"Thank you for your purchase!"},"returnPolicy":{"type":"string","nullable":true,"example":"Returns accepted within 30 days with receipt."}},"required":["message"]},"ReceiptResponseDto":{"type":"object","properties":{"header":{"$ref":"#/components/schemas/ReceiptHeaderDto"},"orderInfo":{"$ref":"#/components/schemas/ReceiptOrderInfoDto"},"customer":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ReceiptCustomerDto"}]},"lineItems":{"type":"array","items":{"$ref":"#/components/schemas/ReceiptLineItemDto"}},"taxSummary":{"type":"array","items":{"$ref":"#/components/schemas/ReceiptTaxSummaryLineDto"}},"totals":{"$ref":"#/components/schemas/ReceiptTotalsDto"},"paymentSummary":{"$ref":"#/components/schemas/ReceiptPaymentSummaryDto"},"footer":{"$ref":"#/components/schemas/ReceiptFooterDto"}},"required":["header","orderInfo","lineItems","taxSummary","totals","paymentSummary","footer"]},"ReturnLineResponseDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"salesOrderLineId":{"type":"string","example":"uuid"},"variantId":{"type":"string","example":"uuid"},"returnedQuantity":{"type":"string","example":"1.0000"},"unitPrice":{"type":"string","example":"29.9900"},"lineDiscount":{"type":"string","example":"0.0000"},"taxAmount":{"type":"string","example":"2.1000"},"lineRefund":{"type":"string","example":"32.0900"}},"required":["id","salesOrderLineId","variantId","returnedQuantity","unitPrice","lineDiscount","taxAmount","lineRefund"]},"ReturnResponseDto":{"type":"object","properties":{"returnId":{"type":"string","example":"uuid"},"returnNumber":{"type":"string","example":"RET-20260403-0001"},"salesOrderId":{"type":"string","example":"uuid"},"reason":{"type":"string","example":"Defective product"},"refundMethod":{"type":"string","example":"CASH","enum":["ORIGINAL_PAYMENT","STORE_CREDIT","CASH"]},"subtotalRefund":{"type":"string","example":"29.9900"},"taxRefund":{"type":"string","example":"2.1000"},"totalRefund":{"type":"string","example":"32.0900"},"orderStatus":{"type":"string","example":"PARTIALLY_REFUNDED"},"lines":{"type":"array","items":{"$ref":"#/components/schemas/ReturnLineResponseDto"}},"createdAt":{"format":"date-time","type":"string","example":"2026-04-03T10:30:00.000Z"}},"required":["returnId","returnNumber","salesOrderId","reason","refundMethod","subtotalRefund","taxRefund","totalRefund","orderStatus","lines","createdAt"]},"ReturnItemDto":{"type":"object","properties":{"salesOrderLineId":{"type":"string","format":"uuid","example":"uuid","description":"Original sales order line ID"},"returnedQuantity":{"type":"string","example":"1.0000","description":"Quantity to return"}},"required":["salesOrderLineId","returnedQuantity"]},"ProcessReturnDto":{"type":"object","properties":{"salesOrderId":{"type":"string","example":"SO-R02-20260929-0001","description":"Sales order ID or order number to return against"},"reason":{"type":"string","maxLength":500,"example":"Defective product","description":"Reason for return"},"refundMethod":{"type":"string","example":"CASH","enum":["ORIGINAL_PAYMENT","STORE_CREDIT","CASH"],"description":"How to issue the refund"},"posSessionId":{"type":"string","format":"uuid","example":"uuid","description":"POS session ID"},"items":{"minItems":1,"description":"Items to return","type":"array","items":{"$ref":"#/components/schemas/ReturnItemDto"}},"tenantId":{"type":"string"}},"required":["salesOrderId","reason","refundMethod","items","tenantId"]},"Decimal2":{"type":"object","properties":{}},"CardTierEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Silver"},"rank":{"type":"number","example":2,"description":"Display order, low to high."},"preloadAmount":{"example":"100000.0000","allOf":[{"$ref":"#/components/schemas/Decimal2"}]},"preloadFunding":{"type":"string","enum":["PURCHASED","GRANTED"],"example":"PURCHASED"},"discountBps":{"type":"number","example":500,"description":"Basis points. 500 = 5.00%."},"isPostpaid":{"type":"boolean","example":false},"customerRequirement":{"type":"string","enum":["NONE","OPTIONAL","REQUIRED"],"example":"NONE","description":"What a card of this tier needs to know about the guest. NONE: handed over with no details. OPTIONAL: linked when the desk recognises a returning guest. REQUIRED: a card cannot be issued without a customer. A postpaid tier left at NONE is allowed, and means a debt with nobody to bill."},"validityDays":{"type":"number","nullable":true,"example":30},"isActive":{"type":"boolean","example":true},"deletedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"}},"required":["id","tenantId","name","rank","preloadAmount","preloadFunding","discountBps","isPostpaid","customerRequirement","isActive","createdAt","updatedAt"]},"CreateCardTierDto":{"type":"object","properties":{"name":{"type":"string","maxLength":50,"example":"Silver"},"rank":{"type":"number","example":2,"description":"Display order, low to high."},"preloadAmount":{"type":"string","example":"100000.0000","description":"Value attached when a card of this tier is issued."},"preloadFunding":{"type":"string","enum":["PURCHASED","GRANTED"],"default":"PURCHASED","description":"PURCHASED: the guest pays for the preload and gets the unspent part back. GRANTED: the hotel gives it, and the remainder is forfeited at checkout."},"discountBps":{"type":"number","minimum":0,"maximum":10000,"example":500,"description":"Basis points, so 500 is 5.00%."},"isPostpaid":{"type":"boolean","example":false,"description":"Postpaid tiers may go negative and must be settled before checkout. Every other tier is hard-stopped at a zero balance."},"customerRequirement":{"type":"string","enum":["NONE","OPTIONAL","REQUIRED"],"default":"NONE","description":"What a card of this tier needs to know about the guest. NONE: handed over with no details. OPTIONAL: linked when the desk recognises a returning guest. REQUIRED: a card cannot be issued without a customer. A postpaid tier left at NONE is allowed, and means a debt with nobody to bill."},"validityDays":{"type":"number","minimum":1,"example":30,"description":"Null means no expiry."},"isActive":{"type":"boolean","example":true}},"required":["name"]},"UpdateCardTierDto":{"type":"object","properties":{"name":{"type":"string","maxLength":50,"example":"Silver"},"rank":{"type":"number","example":2},"preloadAmount":{"type":"string","example":"120000.0000"},"preloadFunding":{"type":"string","enum":["PURCHASED","GRANTED"]},"discountBps":{"type":"number","minimum":0,"maximum":10000,"example":700},"isPostpaid":{"type":"boolean","example":false},"customerRequirement":{"type":"string","enum":["NONE","OPTIONAL","REQUIRED"],"default":"NONE","description":"What a card of this tier needs to know about the guest. NONE: handed over with no details. OPTIONAL: linked when the desk recognises a returning guest. REQUIRED: a card cannot be issued without a customer. A postpaid tier left at NONE is allowed, and means a debt with nobody to bill."},"validityDays":{"type":"number","minimum":1,"example":30},"isActive":{"type":"boolean","example":true}}},"GuestWalletEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"walletNumber":{"type":"string","example":"W-000041"},"guestName":{"type":"string","example":"Ko Aung"},"guestPhone":{"type":"string","nullable":true,"example":"09xxxxxxxxx"},"guestIdNumber":{"type":"string","nullable":true,"example":null},"customerId":{"type":"string","nullable":true,"example":"uuid","description":"The customer this wallet belongs to, when the tier asks for one. Null for a walk-in card issued without taking details."},"tierId":{"type":"string","example":"uuid","description":"Reporting only. Behaviour reads the snapshot fields, never this tier."},"tierNameSnapshot":{"type":"string","example":"Silver"},"discountBpsSnapshot":{"type":"number","example":500},"isPostpaidSnapshot":{"type":"boolean","example":false},"preloadAmountSnapshot":{"example":"100000.0000","allOf":[{"$ref":"#/components/schemas/Decimal2"}]},"preloadFundingSnapshot":{"type":"string","enum":["PURCHASED","GRANTED"],"example":"PURCHASED"},"expiresAt":{"format":"date-time","type":"string","nullable":true,"example":null},"balance":{"example":"88600.0000","description":"Derived from the ledger.","allOf":[{"$ref":"#/components/schemas/Decimal2"}]},"purchasedBalance":{"example":"88600.0000","allOf":[{"$ref":"#/components/schemas/Decimal2"}]},"grantedBalance":{"example":"0.0000","allOf":[{"$ref":"#/components/schemas/Decimal2"}]},"sequenceNo":{"type":"number","example":4},"status":{"type":"string","enum":["ACTIVE","SUSPENDED","SETTLING","CLOSED","VOID"],"example":"ACTIVE"},"issuedAtLocationId":{"type":"string","example":"uuid"},"issuedByUserId":{"type":"string","example":"uuid"},"openedAt":{"format":"date-time","type":"string","example":"2026-09-12T20:00:00.000Z"},"closedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"closedByUserId":{"type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-09-12T20:00:00.000Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-09-12T20:00:00.000Z"}},"required":["id","tenantId","walletNumber","guestName","tierId","tierNameSnapshot","discountBpsSnapshot","isPostpaidSnapshot","preloadAmountSnapshot","preloadFundingSnapshot","balance","purchasedBalance","grantedBalance","sequenceNo","status","issuedAtLocationId","issuedByUserId","openedAt","createdAt","updatedAt"]},"IssueWalletCustomerDto":{"type":"object","properties":{"name":{"type":"string","maxLength":255,"example":"U Mg Mg"},"phone":{"type":"string","maxLength":50,"example":"09770011223","description":"Matched against existing customers: the same number is the same person, so a returning guest is linked rather than duplicated."},"email":{"type":"string","maxLength":255,"example":"guest@example.com"}},"required":["name"]},"IssueWalletCardDto":{"type":"object","properties":{"cardUid":{"type":"string","maxLength":100,"example":"04A3B2C1"},"label":{"type":"string","maxLength":50,"example":"Guest 1"},"roomNumber":{"type":"string","maxLength":20,"example":"304"}},"required":["cardUid"]},"WalletPaymentDto":{"type":"object","properties":{"paymentMethodId":{"type":"string","format":"uuid","example":"uuid"},"amount":{"type":"string","example":"100000.0000"},"reference":{"type":"string","maxLength":255,"example":"KBZ-99182736","description":"Required when the payment method is a mobile wallet."}},"required":["paymentMethodId","amount"]},"IssueWalletDto":{"type":"object","properties":{"tierId":{"type":"string","format":"uuid","example":"uuid"},"guestName":{"type":"string","maxLength":255,"example":"Ko Aung","description":"The name on the card. Optional: a tier that takes no details can be issued without one, and a linked customer lends theirs."},"guestPhone":{"type":"string","maxLength":50,"example":"09xxxxxxxxx"},"guestIdNumber":{"type":"string","maxLength":100,"example":"NRC / passport number"},"customerId":{"type":"string","format":"uuid","example":"uuid","description":"An existing customer to issue this card to. Use it or `customer`, not both."},"customer":{"description":"Details for a guest who is not on file yet. Matched on phone where one is given, so issuing a second card to the same number reuses the customer rather than making another.","allOf":[{"$ref":"#/components/schemas/IssueWalletCustomerDto"}]},"locationId":{"type":"string","format":"uuid","example":"uuid","description":"The outlet issuing the card."},"posSessionId":{"type":"string","format":"uuid","example":"uuid","description":"Required whenever money changes hands, so it reaches shift close."},"cards":{"minItems":1,"description":"One or more cards, all drawing on this single wallet.","type":"array","items":{"$ref":"#/components/schemas/IssueWalletCardDto"}},"payment":{"description":"How the guest paid for a purchased preload. Not needed for a granted one.","allOf":[{"$ref":"#/components/schemas/WalletPaymentDto"}]},"idempotencyKey":{"type":"string","maxLength":255,"example":"uuid","description":"Generate once per action and reuse it on every retry. Replaying the same key returns the original result rather than issuing twice."}},"required":["tierId","locationId","cards"]},"WalletCardSummaryDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"cardUid":{"type":"string","example":"04A3B2C1"},"label":{"type":"string","nullable":true,"example":"Guest 2"},"roomNumber":{"type":"string","nullable":true,"example":"1204"},"status":{"type":"string","enum":["ACTIVE","LOST","DAMAGED","RETURNED","DEACTIVATED"],"example":"ACTIVE"}},"required":["id","cardUid","status"]},"GuestWalletListItemDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"walletNumber":{"type":"string","example":"W-000041"},"guestName":{"type":"string","example":"Ko Aung"},"guestPhone":{"type":"string","nullable":true,"example":"09xxxxxxxxx"},"guestIdNumber":{"type":"string","nullable":true,"example":null},"customerId":{"type":"string","nullable":true,"example":"uuid","description":"The customer this wallet belongs to, when the tier asks for one. Null for a walk-in card issued without taking details."},"tierId":{"type":"string","example":"uuid","description":"Reporting only. Behaviour reads the snapshot fields, never this tier."},"tierNameSnapshot":{"type":"string","example":"Silver"},"discountBpsSnapshot":{"type":"number","example":500},"isPostpaidSnapshot":{"type":"boolean","example":false},"preloadAmountSnapshot":{"example":"100000.0000","allOf":[{"$ref":"#/components/schemas/Decimal2"}]},"preloadFundingSnapshot":{"type":"string","enum":["PURCHASED","GRANTED"],"example":"PURCHASED"},"expiresAt":{"format":"date-time","type":"string","nullable":true,"example":null},"balance":{"example":"88600.0000","description":"Derived from the ledger.","allOf":[{"$ref":"#/components/schemas/Decimal2"}]},"purchasedBalance":{"example":"88600.0000","allOf":[{"$ref":"#/components/schemas/Decimal2"}]},"grantedBalance":{"example":"0.0000","allOf":[{"$ref":"#/components/schemas/Decimal2"}]},"sequenceNo":{"type":"number","example":4},"status":{"type":"string","enum":["ACTIVE","SUSPENDED","SETTLING","CLOSED","VOID"],"example":"ACTIVE"},"issuedAtLocationId":{"type":"string","example":"uuid"},"issuedByUserId":{"type":"string","example":"uuid"},"openedAt":{"format":"date-time","type":"string","example":"2026-09-12T20:00:00.000Z"},"closedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"closedByUserId":{"type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-09-12T20:00:00.000Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-09-12T20:00:00.000Z"},"cards":{"description":"Every card on the wallet, active ones first, then newest first. Cards that were returned, lost or deactivated stay here with their status.","type":"array","items":{"$ref":"#/components/schemas/WalletCardSummaryDto"}}},"required":["id","tenantId","walletNumber","guestName","tierId","tierNameSnapshot","discountBpsSnapshot","isPostpaidSnapshot","preloadAmountSnapshot","preloadFundingSnapshot","balance","purchasedBalance","grantedBalance","sequenceNo","status","issuedAtLocationId","issuedByUserId","openedAt","createdAt","updatedAt","cards"]},"GuestCardEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"walletId":{"type":"string","example":"uuid"},"cardUid":{"type":"string","example":"04A3B2C1","description":"The card’s permanent serial, read from the reader."},"label":{"type":"string","nullable":true,"example":"Guest 2"},"roomNumber":{"type":"string","nullable":true,"example":"304","description":"The room this card was encoded for on the door-lock system. Display only."},"status":{"type":"string","enum":["ACTIVE","LOST","DAMAGED","RETURNED","DEACTIVATED"],"example":"ACTIVE"},"issuedAt":{"format":"date-time","type":"string","example":"2026-09-12T20:00:00.000Z"},"issuedByUserId":{"type":"string","example":"uuid"},"deactivatedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"replacedByCardId":{"type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-09-12T20:00:00.000Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-09-12T20:00:00.000Z"}},"required":["id","tenantId","walletId","cardUid","status","issuedAt","issuedByUserId","createdAt","updatedAt"]},"WalletLedgerEntryEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"walletId":{"type":"string","example":"uuid"},"sequenceNo":{"type":"number","example":4,"description":"Gap-free per wallet."},"entryType":{"type":"string","enum":["TOP_UP","PRELOAD_GRANT","SPEND","SPEND_REVERSAL","REFUND_OUT","SETTLEMENT_COLLECTION","GRANT_FORFEIT","ADJUSTMENT_CREDIT","ADJUSTMENT_DEBIT"],"example":"TOP_UP"},"amount":{"example":"-11400.0000","description":"Signed: credits positive, debits negative.","allOf":[{"$ref":"#/components/schemas/Decimal2"}]},"purchasedDelta":{"example":"-11400.0000","allOf":[{"$ref":"#/components/schemas/Decimal2"}]},"grantedDelta":{"example":"0.0000","allOf":[{"$ref":"#/components/schemas/Decimal2"}]},"balanceAfter":{"example":"88600.0000","allOf":[{"$ref":"#/components/schemas/Decimal2"}]},"guestCardId":{"type":"string","nullable":true,"example":"uuid"},"locationId":{"type":"string","example":"uuid"},"posSessionId":{"type":"string","nullable":true,"example":"uuid"},"staffUserId":{"type":"string","example":"uuid"},"approvedByUserId":{"type":"string","nullable":true,"example":null},"sourceModule":{"type":"string","nullable":true,"example":"GUEST_CARD"},"sourceRecordId":{"type":"string","nullable":true,"example":null},"correctsEntryId":{"type":"string","nullable":true,"example":null},"reference":{"type":"string","nullable":true,"example":"KBZ-99182736"},"idempotencyKey":{"type":"string","nullable":true,"example":"uuid"},"businessDate":{"type":"string","example":"2026-09-12"},"notes":{"type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-09-12T22:00:00.000Z"}},"required":["id","tenantId","walletId","sequenceNo","entryType","amount","purchasedDelta","grantedDelta","balanceAfter","locationId","staffUserId","businessDate","createdAt"]},"WalletAuditDto":{"type":"object","properties":{"walletId":{"type":"string","example":"uuid"},"cached":{"type":"string","example":"42000.0000","description":"What the wallet row claims."},"replayed":{"type":"string","example":"42000.0000","description":"What replaying every entry produces. The authority."},"entryCount":{"type":"number","example":14},"sequenceNo":{"type":"number","example":14,"description":"The wallet’s sequence number. Entries counted short of it means a row was removed, which the append-only trigger should make impossible."},"matches":{"type":"boolean","example":true,"description":"False when the balances disagree or the sequence has a gap. Either is worth shouting about."}},"required":["walletId","cached","replayed","entryCount","sequenceNo","matches"]},"TopUpWalletDto":{"type":"object","properties":{"amount":{"type":"string","example":"60000.0000"},"paymentMethodId":{"type":"string","format":"uuid","example":"uuid"},"posSessionId":{"type":"string","format":"uuid","example":"uuid"},"locationId":{"type":"string","format":"uuid","example":"uuid"},"reference":{"type":"string","maxLength":255,"example":"KBZ-99182736","description":"Mandatory for a mobile wallet transfer; the save is refused without it."},"guestCardId":{"type":"string","format":"uuid","example":"uuid"},"idempotencyKey":{"type":"string","maxLength":255,"example":"uuid"},"notes":{"type":"string","example":"Topped up at the cash desk"}},"required":["amount","paymentMethodId","posSessionId","locationId"]},"SettlementBlockerDto":{"type":"object","properties":{"type":{"type":"string","example":"OPEN_ORDER"},"id":{"type":"string","example":"uuid"},"label":{"type":"string","example":"order SO-R01-20260912-0042"}},"required":["type","id","label"]},"SettlementQuoteDto":{"type":"object","properties":{"walletId":{"type":"string","example":"uuid"},"walletNumber":{"type":"string","example":"W-000041"},"guestName":{"type":"string","example":"Ko Aung"},"status":{"type":"string","enum":["ACTIVE","SUSPENDED","SETTLING","CLOSED","VOID"]},"balance":{"type":"string","example":"15000.0000"},"purchasedBalance":{"type":"string","example":"15000.0000"},"grantedBalance":{"type":"string","example":"0.0000"},"action":{"type":"string","example":"REFUND_DUE","enum":["REFUND_DUE","COLLECT_DUE","READY_TO_CLOSE"],"description":"Drive the settlement screen off this rather than the balance: a positive balance may be entirely promotional value, which looks refundable and is not."},"refundable":{"type":"string","example":"15000.0000","description":"The guest’s own money, to be handed back."},"forfeitable":{"type":"string","example":"0.0000","description":"Promotional value, written off rather than paid out."},"collectable":{"type":"string","example":"0.0000","description":"Owed by the guest on a postpaid card."},"blockers":{"description":"Business still open. Must be empty before the wallet can close.","type":"array","items":{"$ref":"#/components/schemas/SettlementBlockerDto"}}},"required":["walletId","walletNumber","guestName","status","balance","purchasedBalance","grantedBalance","action","refundable","forfeitable","collectable","blockers"]},"SettlementTenderDto":{"type":"object","properties":{"paymentMethodId":{"type":"string","format":"uuid","example":"uuid"},"reference":{"type":"string","maxLength":255,"example":"KBZ-99182736","description":"Required for a mobile wallet transfer."}},"required":["paymentMethodId"]},"SettlementCollectionDto":{"type":"object","properties":{"paymentMethodId":{"type":"string","format":"uuid","example":"uuid"},"reference":{"type":"string","maxLength":255,"example":"KBZ-99182736","description":"Required for a mobile wallet transfer."},"amount":{"type":"string","example":"45000.0000","description":"Must match the outstanding amount exactly. Part payment does not close an account: the requirement is that a guest cannot check out until it is clear."}},"required":["paymentMethodId","amount"]},"SettleWalletDto":{"type":"object","properties":{"posSessionId":{"type":"string","format":"uuid","example":"uuid"},"locationId":{"type":"string","format":"uuid","example":"uuid"},"refund":{"description":"How unspent money is being handed back. Required when the quote says REFUND_DUE with a refundable amount, and needs a manager’s approval.","allOf":[{"$ref":"#/components/schemas/SettlementTenderDto"}]},"collect":{"description":"Money taken to clear a postpaid card. Required when the quote says COLLECT_DUE.","allOf":[{"$ref":"#/components/schemas/SettlementCollectionDto"}]},"idempotencyKey":{"type":"string","maxLength":255,"example":"uuid"},"notes":{"type":"string","example":"Checked out at 01:15"}},"required":["posSessionId","locationId"]},"RefundWalletDto":{"type":"object","properties":{"amount":{"type":"string","example":"20000.0000","description":"How much to hand back. Cannot exceed the guest’s own money - promotional value is never paid out in cash."},"paymentMethodId":{"type":"string","format":"uuid","example":"uuid"},"posSessionId":{"type":"string","format":"uuid","example":"uuid"},"locationId":{"type":"string","format":"uuid","example":"uuid"},"reference":{"type":"string","maxLength":255,"example":"KBZ-99182736"},"idempotencyKey":{"type":"string","maxLength":255,"example":"uuid"},"notes":{"type":"string","example":"Guest asked for cash back"}},"required":["amount","paymentMethodId","posSessionId","locationId"]},"LinkCardDto":{"type":"object","properties":{"walletId":{"type":"string","format":"uuid","example":"uuid"},"cardUid":{"type":"string","maxLength":100,"example":"04A3B2C1","description":"The card’s serial as read by the reader. We never write to a card."},"label":{"type":"string","maxLength":50,"example":"Guest 2"},"roomNumber":{"type":"string","maxLength":20,"example":"304","description":"The room this card was encoded for on the door-lock system. Recorded for the desk’s benefit only; it grants nothing."}},"required":["walletId","cardUid"]},"CardWalletSummaryDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"walletNumber":{"type":"string","example":"W-000123"},"guestName":{"type":"string","example":"Aung Aung"},"guestPhone":{"type":"string","nullable":true,"example":"09 7xx xxx xxx"},"status":{"type":"string","enum":["ACTIVE","SUSPENDED","SETTLING","CLOSED","VOID"],"example":"ACTIVE"}},"required":["id","walletNumber","guestName","status"]},"GuestCardListItemDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"walletId":{"type":"string","example":"uuid"},"cardUid":{"type":"string","example":"04A3B2C1","description":"The card’s permanent serial, read from the reader."},"label":{"type":"string","nullable":true,"example":"Guest 2"},"roomNumber":{"type":"string","nullable":true,"example":"304","description":"The room this card was encoded for on the door-lock system. Display only."},"status":{"type":"string","enum":["ACTIVE","LOST","DAMAGED","RETURNED","DEACTIVATED"],"example":"ACTIVE"},"issuedAt":{"format":"date-time","type":"string","example":"2026-09-12T20:00:00.000Z"},"issuedByUserId":{"type":"string","example":"uuid"},"deactivatedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"replacedByCardId":{"type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-09-12T20:00:00.000Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-09-12T20:00:00.000Z"},"wallet":{"$ref":"#/components/schemas/CardWalletSummaryDto"}},"required":["id","tenantId","walletId","cardUid","status","issuedAt","issuedByUserId","createdAt","updatedAt","wallet"]},"ReplaceCardDto":{"type":"object","properties":{"newCardUid":{"type":"string","maxLength":100,"example":"04A3B2C9"},"label":{"type":"string","maxLength":50,"example":"Guest 2"},"roomNumber":{"type":"string","maxLength":20,"example":"304"}},"required":["newCardUid"]},"DailyCashReasonRowDto":{"type":"object","properties":{"reason":{"type":"string","enum":["WALLET_TOP_UP","WALLET_REFUND","WALLET_SETTLEMENT","PAID_IN","PAID_OUT","DROP","FLOAT_ADJUSTMENT"],"example":"WALLET_TOP_UP"},"direction":{"type":"string","enum":["IN","OUT"],"example":"IN"},"count":{"type":"number","example":14},"amount":{"type":"string","example":"350000.0000"}},"required":["reason","direction","count","amount"]},"DailyCashReportDto":{"type":"object","properties":{"businessDate":{"type":"string","example":"2026-09-12"},"locationIds":{"nullable":true,"example":["uuid"],"description":"The outlets the figures cover, or null when they cover every outlet the caller may see. An empty array means an outlet was asked for that the caller may not read, and the figures are correctly all zero.","type":"array","items":{"type":"string"}},"depositsIn":{"type":"string","example":"350000.0000","description":"Money taken in and held for guests. Not revenue."},"refundsOut":{"type":"string","example":"20000.0000"},"settlementsIn":{"type":"string","example":"15000.0000","description":"Collected at checkout from wallets that went into debt."},"netDeposits":{"type":"string","example":"345000.0000","description":"depositsIn + settlementsIn - refundsOut."},"salesTendered":{"type":"string","example":"1250000.0000","description":"Tendered against actual sales, card redemptions included. Never added to the deposit figures: a top-up is money held, not money earned."},"byReason":{"type":"array","items":{"$ref":"#/components/schemas/DailyCashReasonRowDto"}}},"required":["businessDate","depositsIn","refundsOut","settlementsIn","netDeposits","salesTendered","byReason"]},"OutletRevenueRowDto":{"type":"object","properties":{"locationId":{"type":"string","nullable":true,"example":"uuid"},"orderCount":{"type":"number","example":128},"subtotal":{"type":"string","example":"1000000.0000"},"totalDiscount":{"type":"string","example":"25000.0000"},"totalTax":{"type":"string","example":"50000.0000"},"serviceCharge":{"type":"string","example":"100000.0000"},"grandTotal":{"type":"string","example":"1125000.0000"}},"required":["orderCount","subtotal","totalDiscount","totalTax","serviceCharge","grandTotal"]},"LiabilityByTierRowDto":{"type":"object","properties":{"tenantId":{"type":"string","example":"uuid","description":"Carried so a system admin reading every tenant sees one hotel’s Gold tier apart from another’s rather than added together."},"tier":{"type":"string","example":"Gold"},"walletCount":{"type":"number","example":12},"balance":{"type":"string","example":"480000.0000"}},"required":["tenantId","tier","walletCount","balance"]},"OutstandingLiabilityDto":{"type":"object","properties":{"walletCount":{"type":"number","example":37},"total":{"type":"string","example":"1480000.0000"},"purchased":{"type":"string","example":"1300000.0000","description":"Owed to guests and refundable in cash - a real debt."},"granted":{"type":"string","example":"180000.0000","description":"The property’s own giveaway, most of which is never redeemed - a marketing cost rather than a debt."},"byTier":{"type":"array","items":{"$ref":"#/components/schemas/LiabilityByTierRowDto"}}},"required":["walletCount","total","purchased","granted","byTier"]},"OpenWalletRowDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"walletNumber":{"type":"string","example":"GW-20260912-0007"},"guestName":{"type":"string","nullable":true,"example":"Daw Hla"},"guestPhone":{"type":"string","nullable":true,"example":"09-770000000"},"status":{"type":"string","enum":["ACTIVE","SUSPENDED","SETTLING","CLOSED","VOID"],"example":"ACTIVE"},"balance":{"type":"string","example":"42000.0000"},"tierNameSnapshot":{"type":"string","example":"Gold"},"openedAt":{"format":"date-time","type":"string","example":"2026-09-05T11:02:00.000Z"},"ageDays":{"type":"number","example":7,"description":"Whole days since it opened. A wallet open a month is not a guest still here; it is an account somebody forgot to close."}},"required":["id","tenantId","walletNumber","status","balance","tierNameSnapshot","openedAt","ageDays"]},"NegativeBalanceRowDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"walletNumber":{"type":"string","example":"GW-20260912-0007"},"guestName":{"type":"string","nullable":true,"example":"Daw Hla"},"guestPhone":{"type":"string","nullable":true,"example":"09-770000000"},"tierNameSnapshot":{"type":"string","example":"Platinum"},"balance":{"type":"string","example":"-18000.0000"},"status":{"type":"string","enum":["ACTIVE","SUSPENDED","SETTLING","CLOSED","VOID"],"example":"ACTIVE"},"openedAt":{"format":"date-time","type":"string","example":"2026-09-05T11:02:00.000Z"}},"required":["id","tenantId","walletNumber","tierNameSnapshot","balance","status","openedAt"]},"RefundsByStaffRowDto":{"type":"object","properties":{"staffUserId":{"type":"string","example":"uuid"},"staffName":{"type":"string","nullable":true,"example":"Ko Aung"},"approvedByUserId":{"type":"string","nullable":true,"example":"uuid"},"approverName":{"type":"string","nullable":true,"example":"Daw Mya"},"refundCount":{"type":"number","example":4},"total":{"type":"string","example":"65000.0000","description":"Stored negative in the ledger; reported as the amount handed over."}},"required":["staffUserId","refundCount","total"]},"TierUsageRowDto":{"type":"object","properties":{"tenantId":{"type":"string","example":"uuid"},"tier":{"type":"string","example":"Gold","description":"The snapshot name, so a tier renamed last month does not retrospectively rewrite what was sold under the old one."},"count":{"type":"number","example":96},"total":{"type":"string","example":"820000.0000"}},"required":["tenantId","tier","count","total"]},"LostCardWalletDto":{"type":"object","properties":{"walletNumber":{"type":"string","example":"GW-20260912-0007"},"guestName":{"type":"string","nullable":true,"example":"Daw Hla"},"status":{"type":"string","enum":["ACTIVE","SUSPENDED","SETTLING","CLOSED","VOID"],"example":"ACTIVE"}},"required":["walletNumber","status"]},"LostCardRowDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"cardUid":{"type":"string","example":"04A1B2C3D4E5F6"},"label":{"type":"string","nullable":true,"example":"Card 12"},"roomNumber":{"type":"string","nullable":true,"example":"702"},"deactivatedAt":{"format":"date-time","type":"string","nullable":true,"example":"2026-09-12T18:20:00.000Z"},"replacedByCardId":{"type":"string","nullable":true,"example":"uuid","description":"The card issued in its place, if one was."},"wallet":{"$ref":"#/components/schemas/LostCardWalletDto"}},"required":["id","tenantId","cardUid","wallet"]},"ShiftRegisterDto":{"type":"object","properties":{"code":{"type":"string","example":"R01"},"name":{"type":"string","example":"Front desk"}},"required":["code","name"]},"ShiftCashierDto":{"type":"object","properties":{"fullName":{"type":"string","nullable":true,"example":"Ko Aung"},"username":{"type":"string","example":"koaung"}},"required":["username"]},"ShiftReconciliationRowDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"openedAt":{"format":"date-time","type":"string","example":"2026-09-12T08:00:00.000Z"},"closedAt":{"format":"date-time","type":"string","nullable":true,"example":"2026-09-12T20:00:00.000Z"},"openingCashFloat":{"type":"string","example":"100000.0000"},"expectedClosingCash":{"type":"string","nullable":true,"example":"450000.0000","description":"Counts top-ups and refunds as well as sales: those notes are in the same drawer, and ignoring them would report a variance the size of the day’s deposits. Null until the shift is closed."},"actualClosingCash":{"type":"string","nullable":true,"example":"449000.0000"},"cashVariance":{"type":"string","nullable":true,"example":"-1000.0000"},"status":{"type":"string","enum":["OPEN","CLOSED","AUDITED"],"example":"CLOSED"},"varianceApprovedByUserId":{"type":"string","nullable":true,"example":"uuid"},"varianceApprovedAt":{"format":"date-time","type":"string","nullable":true,"example":"2026-09-12T20:10:00.000Z"},"register":{"$ref":"#/components/schemas/ShiftRegisterDto"},"cashier":{"$ref":"#/components/schemas/ShiftCashierDto"},"cashierName":{"type":"string","example":"Ko Aung"},"varianceNeedsAttention":{"type":"boolean","example":true,"description":"A non-zero variance on a closed shift that nobody approved - the one row on this report somebody has to act on."}},"required":["id","tenantId","openedAt","openingCashFloat","status","register","cashier","cashierName","varianceNeedsAttention"]},"WalletAuditProblemDto":{"type":"object","properties":{"walletId":{"type":"string","example":"uuid"},"walletNumber":{"type":"string","example":"GW-20260912-0007"},"cachedBalance":{"type":"string","example":"42000.0000"},"replayedBalance":{"type":"string","example":"41000.0000"},"entryCount":{"type":"number","example":14},"sequenceNo":{"type":"number","example":14},"problems":{"type":"array","example":["BALANCE_MISMATCH"],"description":"BALANCE_MISMATCH: the cached balance is not what the entries replay to. SEQUENCE_GAP: an entry was removed, which the append-only trigger should make impossible. CHAIN_BROKEN: some entry’s balanceAfter does not follow from the one before it.","items":{"type":"string","enum":["BALANCE_MISMATCH","SEQUENCE_GAP","CHAIN_BROKEN"]}}},"required":["walletId","walletNumber","cachedBalance","replayedBalance","entryCount","sequenceNo","problems"]},"TenantAuditResultDto":{"type":"object","properties":{"tenantId":{"type":"string","example":"uuid"},"businessDate":{"type":"string","example":"2026-09-12"},"walletsChecked":{"type":"number","example":312},"ledgerTotal":{"type":"string","example":"1480000.0000","description":"Every ledger entry ever written, summed."},"balanceTotal":{"type":"string","example":"1480000.0000","description":"Every wallet’s cached balance, summed."},"balances":{"type":"boolean","example":true,"description":"Whether those two agree. The equation this report exists for."},"discrepancies":{"description":"Recorded, never repaired: a silent correction would destroy the evidence that something wrote a wrong number.","type":"array","items":{"$ref":"#/components/schemas/WalletAuditProblemDto"}}},"required":["tenantId","businessDate","walletsChecked","ledgerTotal","balanceTotal","balances","discrepancies"]},"DiscrepancyWalletDto":{"type":"object","properties":{"walletNumber":{"type":"string","example":"GW-20260912-0007"},"guestName":{"type":"string","nullable":true,"example":"Daw Hla"},"status":{"type":"string","enum":["ACTIVE","SUSPENDED","SETTLING","CLOSED","VOID"],"example":"ACTIVE"}},"required":["walletNumber","status"]},"LedgerDiscrepancyDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"walletId":{"type":"string","example":"uuid"},"cachedBalance":{"type":"string","example":"42000.0000"},"replayedBalance":{"type":"string","example":"41000.0000"},"entryCount":{"type":"number","example":14},"sequenceNo":{"type":"number","example":14},"kind":{"type":"string","example":"BALANCE_MISMATCH","description":"Comma-separated when a wallet failed more than one check."},"businessDate":{"type":"string","example":"2026-09-12"},"detectedAt":{"format":"date-time","type":"string","example":"2026-09-12T23:05:00.000Z"},"resolvedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"notes":{"type":"string","nullable":true,"example":"Traced to a double-posted top-up."},"wallet":{"$ref":"#/components/schemas/DiscrepancyWalletDto"}},"required":["id","tenantId","walletId","cachedBalance","replayedBalance","entryCount","sequenceNo","kind","businessDate","detectedAt","wallet"]},"ResolveDiscrepancyResultDto":{"type":"object","properties":{"count":{"type":"number","example":1,"description":"Rows marked resolved. Zero means it was already dealt with, or is not this tenant’s to resolve."}},"required":["count"]},"PosRegisterEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"locationId":{"type":"string","example":"uuid"},"code":{"type":"string","example":"R01"},"name":{"type":"string","example":"Register 1"},"macAddress":{"type":"string","nullable":true,"example":"AA:BB:CC:DD:EE:FF"},"sellsAt":{"type":"array","example":["BAR"],"description":"What this POS device sells: BAR (restaurant), KTV, SPA. The POS shows only those screens.","items":{"type":"string","enum":["BAR","SPA","KTV"]}},"shiftRule":{"type":"string","enum":["PER_LOGIN","DAILY"],"example":"PER_LOGIN","description":"PER_LOGIN: the shift opens at login and closes at logout. DAILY: logged in once a day - the shift is due 24 hours after it opened."},"checkoutPrinterIds":{"example":["uuid"],"description":"Printers assigned for the checkout bill. Empty means the outlet's CHECKOUT printers are used.","type":"array","items":{"type":"string"}},"financePrinterIds":{"example":["uuid"],"description":"Printers assigned for the finance copy. Empty means the outlet's FINANCE printers are used.","type":"array","items":{"type":"string"}},"createdAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"}},"required":["id","tenantId","locationId","code","name","sellsAt","shiftRule","checkoutPrinterIds","financePrinterIds","createdAt","updatedAt"]},"CreatePosRegisterDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"locationId":{"type":"string","format":"uuid","example":"uuid"},"code":{"type":"string","example":"R01","description":"Short code unique within the tenant, embedded in every document number this register issues. Auto-assigned (R01, R02, ...) when omitted."},"name":{"type":"string","example":"Register 1"},"macAddress":{"type":"string","example":"AA:BB:CC:DD:EE:FF"},"sellsAt":{"type":"array","uniqueItems":true,"minItems":1,"default":["BAR","KTV","SPA"],"description":"What this POS device sells: BAR (restaurant), KTV, SPA - one or several.","items":{"type":"string","enum":["BAR","SPA","KTV"]}},"shiftRule":{"type":"string","enum":["PER_LOGIN","DAILY"],"default":"PER_LOGIN","description":"PER_LOGIN: shift opens at login, closes at logout. DAILY: one shift a day."},"checkoutPrinterIds":{"uniqueItems":true,"example":["uuid-front-till-printer"],"description":"Where this till prints the checkout bill. Each must be a CHECKOUT printer at the same outlet. Leave out or send [] to use the outlet's CHECKOUT printers. On an update, replaces the list.","type":"array","items":{"type":"string","format":"uuid"}},"financePrinterIds":{"uniqueItems":true,"example":["uuid-front-till-printer"],"description":"Where this till prints the finance copy. Each must be a FINANCE printer at the same outlet; one printer can serve both sectors. Leave out or send [] to use the outlet's FINANCE printers. On an update, replaces the list.","type":"array","items":{"type":"string","format":"uuid"}}},"required":["tenantId","locationId","name"]},"StationPrinterDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Kitchen printer 1"},"ipAddress":{"type":"string","nullable":true,"example":"192.168.1.50","description":"Null for a USB or Bluetooth printer."},"port":{"type":"number","nullable":true,"example":9100},"isActive":{"type":"boolean","example":true}},"required":["id","name","isActive"]},"SectorPrintersDto":{"type":"object","properties":{"source":{"type":"string","enum":["REGISTER","LOCATION","NONE"],"example":"REGISTER","description":"REGISTER: assigned to this till. LOCATION: the till has none, so these are the outlet's active printers in the sector. NONE: nothing to print to."},"printers":{"type":"array","items":{"$ref":"#/components/schemas/StationPrinterDto"}}},"required":["source","printers"]},"RegisterPrintersDto":{"type":"object","properties":{"registerId":{"type":"string","example":"uuid"},"locationId":{"type":"string","example":"uuid"},"checkout":{"description":"Where the checkout bill (CUSTOMER / ORDER_RECEIPT copies) prints.","allOf":[{"$ref":"#/components/schemas/SectorPrintersDto"}]},"finance":{"description":"Where the FINANCE copy prints.","allOf":[{"$ref":"#/components/schemas/SectorPrintersDto"}]}},"required":["registerId","locationId","checkout","finance"]},"UpdatePosRegisterDto":{"type":"object","properties":{"locationId":{"type":"string","format":"uuid","example":"uuid"},"code":{"type":"string","example":"R01","description":"Short code unique within the tenant, embedded in every document number this register issues. Auto-assigned (R01, R02, ...) when omitted."},"name":{"type":"string","example":"Register 1"},"macAddress":{"type":"string","example":"AA:BB:CC:DD:EE:FF"},"sellsAt":{"type":"array","uniqueItems":true,"minItems":1,"default":["BAR","KTV","SPA"],"description":"What this POS device sells: BAR (restaurant), KTV, SPA - one or several.","items":{"type":"string","enum":["BAR","SPA","KTV"]}},"shiftRule":{"type":"string","enum":["PER_LOGIN","DAILY"],"default":"PER_LOGIN","description":"PER_LOGIN: shift opens at login, closes at logout. DAILY: one shift a day."},"checkoutPrinterIds":{"uniqueItems":true,"example":["uuid-front-till-printer"],"description":"Where this till prints the checkout bill. Each must be a CHECKOUT printer at the same outlet. Leave out or send [] to use the outlet's CHECKOUT printers. On an update, replaces the list.","type":"array","items":{"type":"string","format":"uuid"}},"financePrinterIds":{"uniqueItems":true,"example":["uuid-front-till-printer"],"description":"Where this till prints the finance copy. Each must be a FINANCE printer at the same outlet; one printer can serve both sectors. Leave out or send [] to use the outlet's FINANCE printers. On an update, replaces the list.","type":"array","items":{"type":"string","format":"uuid"}}}},"PosSessionEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"registerId":{"type":"string","example":"uuid"},"cashierId":{"type":"string","example":"uuid"},"openedAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"},"closedAt":{"format":"date-time","type":"string","nullable":true,"example":"2026-01-01T23:59:59.000Z"},"openingCashFloat":{"type":"string","example":"500.0000"},"expectedClosingCash":{"type":"string","nullable":true,"example":"1500.0000"},"actualClosingCash":{"type":"string","nullable":true,"example":"1490.0000"},"cashVariance":{"type":"string","nullable":true,"example":"-10.0000"},"status":{"type":"string","nullable":true,"example":"OPEN","enum":["OPEN","CLOSED","AUDITED"]},"varianceApprovedByUserId":{"type":"string","nullable":true,"example":"2026-01-01T00:00:00.000Z","description":"Manager who signed off a drawer that did not balance."},"varianceApprovedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","tenantId","registerId","cashierId","openedAt","openingCashFloat","updatedAt"]},"CreatePosSessionDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"registerId":{"type":"string","format":"uuid","example":"uuid"},"cashierId":{"type":"string","format":"uuid","example":"uuid"},"openingCashFloat":{"type":"string","example":"500.0000"},"expectedClosingCash":{"type":"string","example":"1500.0000"},"actualClosingCash":{"type":"string","example":"1490.0000"},"cashVariance":{"type":"string","example":"-10.0000"},"closedAt":{"format":"date-time","type":"string","example":"2026-01-01T23:59:59.000Z"},"status":{"type":"string","example":"OPEN","enum":["OPEN","CLOSED","AUDITED"]}},"required":["tenantId","registerId","cashierId","openingCashFloat"]},"OpenShiftDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"openedAt":{"format":"date-time","type":"string"},"openingCashFloat":{"type":"string","example":"50000.0000"},"cashierId":{"type":"string","example":"uuid"},"cashierName":{"type":"string","nullable":true,"example":"Ma Aye"}},"required":["id","openedAt","openingCashFloat","cashierId"]},"CurrentShiftDto":{"type":"object","properties":{"registerId":{"type":"string","example":"uuid"},"registerName":{"type":"string","example":"Front desk"},"shiftRule":{"type":"string","enum":["PER_LOGIN","DAILY"]},"sellsAt":{"type":"array","description":"The screens this POS device shows","items":{"type":"string","enum":["BAR","SPA","KTV"]}},"shift":{"nullable":true,"description":"Null: no shift is open","allOf":[{"$ref":"#/components/schemas/OpenShiftDto"}]},"dueAt":{"format":"date-time","type":"string","nullable":true,"description":"A daily shift is due a day after it opened; a per-login one has no due time."},"overdue":{"type":"boolean","example":false,"description":"Past its due time: takes no money until closed"}},"required":["registerId","registerName","shiftRule","sellsAt","overdue"]},"UpdatePosSessionDto":{"type":"object","properties":{"registerId":{"type":"string","format":"uuid","example":"uuid"},"cashierId":{"type":"string","format":"uuid","example":"uuid"}}},"PaymentMethodSummaryDto":{"type":"object","properties":{"methodName":{"type":"string","example":"CASH"},"transactionCount":{"type":"number","example":5},"totalAmount":{"type":"string","example":"750.0000"}},"required":["methodName","transactionCount","totalAmount"]},"EndOfDaySummaryDto":{"type":"object","properties":{"sessionId":{"type":"string","example":"uuid"},"registerName":{"type":"string","example":"Register 1"},"cashierName":{"type":"string","nullable":true,"example":"John Doe"},"openedAt":{"format":"date-time","type":"string","example":"2026-04-03T08:00:00.000Z"},"closedAt":{"format":"date-time","type":"string","nullable":true,"example":"2026-04-03T20:00:00.000Z"},"openingCashFloat":{"type":"string","example":"500.0000"},"expectedClosingCash":{"type":"string","example":"1480.0000"},"actualClosingCash":{"type":"string","nullable":true,"example":"1500.0000"},"cashVariance":{"type":"string","nullable":true,"example":"20.0000"},"totalSales":{"type":"string","example":"2500.0000"},"totalRefunds":{"type":"string","example":"120.0000"},"netTotal":{"type":"string","example":"2380.0000"},"salesCount":{"type":"number","example":15},"refundCount":{"type":"number","example":2},"nonSalesCashIn":{"example":"1450000.0000","description":"Cash into the drawer that was not a sale - guest-card top-ups, paid-ins. Included in the expected count but deliberately absent from totalSales, because a deposit is money owed back, not revenue.","type":"array","items":{"$ref":"#/components/schemas/PaymentMethodSummaryDto"}},"nonSalesCashOut":{"type":"string","example":"85000.0000","description":"Cash out of the drawer that was not a refund of a sale - card refunds, paid-outs."},"status":{"type":"string","example":"CLOSED"},"paymentBreakdown":{"type":"array","items":{"$ref":"#/components/schemas/PaymentMethodSummaryDto"}}},"required":["sessionId","registerName","openedAt","openingCashFloat","expectedClosingCash","totalSales","totalRefunds","netTotal","salesCount","refundCount","nonSalesCashIn","nonSalesCashOut","status","paymentBreakdown"]},"ClosePosSessionDto":{"type":"object","properties":{"actualClosingCash":{"type":"string","example":"1500.0000","description":"The cash counted in the drawer. Left out: the shift closes without a count."}}},"PaymentMethodEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Cash"},"kind":{"type":"string","enum":["CASH","CARD","MOBILE_WALLET","BANK_TRANSFER","CUSTOMER_CREDIT","GUEST_CARD","VOUCHER","OTHER"],"example":"CASH","description":"What this tender is. Behaviour keys off this, never off the name."},"isActive":{"type":"boolean","example":true},"glAccountId":{"type":"string","nullable":true,"example":"uuid"},"createdAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"}},"required":["id","tenantId","name","kind","isActive","createdAt","updatedAt"]},"CreatePaymentMethodDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"name":{"type":"string","example":"Cash","description":"The tenant’s own label. Unique within a tenant."},"kind":{"type":"string","enum":["CASH","CARD","MOBILE_WALLET","BANK_TRANSFER","CUSTOMER_CREDIT","GUEST_CARD","VOUCHER","OTHER"],"default":"OTHER","description":"What this tender is. Drives behaviour: CASH counts towards the drawer at shift close, CUSTOMER_CREDIT runs the credit-limit check, GUEST_CARD debits a wallet. Defaults to OTHER, which records the payment and nothing more."},"isActive":{"type":"boolean","example":true,"default":true},"glAccountId":{"type":"string","format":"uuid","example":"uuid"}},"required":["tenantId","name"]},"UpdatePaymentMethodDto":{"type":"object","properties":{"name":{"type":"string","example":"Cash","description":"The tenant’s own label. Unique within a tenant."},"kind":{"type":"string","enum":["CASH","CARD","MOBILE_WALLET","BANK_TRANSFER","CUSTOMER_CREDIT","GUEST_CARD","VOUCHER","OTHER"],"default":"OTHER","description":"What this tender is. Drives behaviour: CASH counts towards the drawer at shift close, CUSTOMER_CREDIT runs the credit-limit check, GUEST_CARD debits a wallet. Defaults to OTHER, which records the payment and nothing more."},"isActive":{"type":"boolean","example":true,"default":true},"glAccountId":{"type":"string","format":"uuid","example":"uuid"}}},"CashMovementEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"posSessionId":{"type":"string","example":"uuid"},"locationId":{"type":"string","example":"uuid"},"businessDate":{"type":"string","example":"2026-09-12"},"direction":{"type":"string","enum":["IN","OUT"],"example":"IN"},"reason":{"type":"string","enum":["WALLET_TOP_UP","WALLET_REFUND","WALLET_SETTLEMENT","PAID_IN","PAID_OUT","DROP","FLOAT_ADJUSTMENT"],"example":"WALLET_TOP_UP"},"paymentMethodId":{"type":"string","example":"uuid"},"amount":{"example":"100000.0000","description":"Always positive; direction carries the sign.","allOf":[{"$ref":"#/components/schemas/Decimal2"}]},"reference":{"type":"string","nullable":true,"example":"KBZ-99182736"},"sourceModule":{"type":"string","nullable":true,"example":"GUEST_CARD"},"sourceRecordId":{"type":"string","nullable":true,"example":"uuid"},"staffUserId":{"type":"string","example":"uuid"},"approvedByUserId":{"type":"string","nullable":true,"example":null},"notes":{"type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-09-12T20:00:00.000Z"}},"required":["id","tenantId","posSessionId","locationId","businessDate","direction","reason","paymentMethodId","amount","staffUserId","createdAt"]},"RecordCashMovementDto":{"type":"object","properties":{"posSessionId":{"type":"string","format":"uuid","example":"uuid"},"locationId":{"type":"string","format":"uuid","example":"uuid"},"direction":{"type":"string","enum":["IN","OUT"],"example":"OUT"},"reason":{"type":"string","enum":["WALLET_TOP_UP","WALLET_REFUND","WALLET_SETTLEMENT","PAID_IN","PAID_OUT","DROP","FLOAT_ADJUSTMENT"],"example":"PAID_OUT","description":"Wallet reasons are written by the guest-card flows themselves; record PAID_IN, PAID_OUT, DROP and FLOAT_ADJUSTMENT here."},"paymentMethodId":{"type":"string","format":"uuid","example":"uuid"},"amount":{"type":"string","example":"25000.0000","description":"Always positive; direction says which way it went."},"reference":{"type":"string","maxLength":255,"example":"KBZ-99182736"},"notes":{"type":"string","example":"Paid the laundry supplier"}},"required":["posSessionId","locationId","direction","reason","paymentMethodId","amount"]},"OutletSettingLocationDto":{"type":"object","properties":{"name":{"type":"string","example":"Sky Bar"},"type":{"type":"string","example":"OUTLET"}},"required":["name","type"]},"OutletSettingWithLocationDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"locationId":{"type":"string","example":"uuid"},"serviceChargeBps":{"type":"number","example":1000,"description":"Basis points, so 1000 is 10.00%. While this row exists the server computes the service charge and ignores whatever the till sends."},"serviceChargeAppliesTo":{"type":"string","enum":["ALL","FNB_ONLY","ROOM_ONLY","NONE"],"example":"ALL"},"defaultTaxRateId":{"type":"string","nullable":true,"example":"uuid"},"timezone":{"type":"string","nullable":true,"example":"Asia/Bangkok","description":"Null inherits the tenant’s timezone, as almost every outlet does."},"currencyCode":{"type":"string","example":"MMK"},"createdAt":{"format":"date-time","type":"string","example":"2026-09-12T20:00:00.000Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-09-12T20:00:00.000Z"},"location":{"$ref":"#/components/schemas/OutletSettingLocationDto"}},"required":["id","tenantId","locationId","serviceChargeBps","serviceChargeAppliesTo","currencyCode","createdAt","updatedAt","location"]},"OutletSettingDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"locationId":{"type":"string","example":"uuid"},"serviceChargeBps":{"type":"number","example":1000,"description":"Basis points, so 1000 is 10.00%. While this row exists the server computes the service charge and ignores whatever the till sends."},"serviceChargeAppliesTo":{"type":"string","enum":["ALL","FNB_ONLY","ROOM_ONLY","NONE"],"example":"ALL"},"defaultTaxRateId":{"type":"string","nullable":true,"example":"uuid"},"timezone":{"type":"string","nullable":true,"example":"Asia/Bangkok","description":"Null inherits the tenant’s timezone, as almost every outlet does."},"currencyCode":{"type":"string","example":"MMK"},"createdAt":{"format":"date-time","type":"string","example":"2026-09-12T20:00:00.000Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-09-12T20:00:00.000Z"}},"required":["id","tenantId","locationId","serviceChargeBps","serviceChargeAppliesTo","currencyCode","createdAt","updatedAt"]},"UpsertOutletSettingDto":{"type":"object","properties":{"serviceChargeBps":{"type":"number","minimum":0,"maximum":10000,"example":1000,"description":"Basis points, so 1000 is 10.00%. Once set, the server computes the service charge and ignores whatever the till sends."},"serviceChargeAppliesTo":{"type":"string","enum":["ALL","FNB_ONLY","ROOM_ONLY","NONE"],"default":"ALL","description":"Properties differ on whether a spa treatment attracts the same charge as a bottle of whisky."},"defaultTaxRateId":{"type":"string","format":"uuid","example":"uuid"},"timezone":{"type":"string","example":"Asia/Bangkok","description":"Only for an outlet in a different timezone from the rest of its tenant. Leave it out to use the tenant’s timezone, which is right for almost every outlet."},"currencyCode":{"type":"string","minLength":3,"maxLength":3,"example":"MMK"}}},"PromotionItemDto":{"type":"object","properties":{"variantId":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Lager (Large)"}},"required":["variantId","name"]},"PromotionEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Happy hour drinks 20% off"},"discountType":{"type":"string","enum":["PERCENT_OFF","AMOUNT_OFF","FREE_TIME"]},"discountValue":{"type":"string","example":"20.0000"},"buyUnits":{"type":"number","nullable":true,"example":1},"freeUnits":{"type":"number","nullable":true,"example":1},"appliesTo":{"type":"string","enum":["ALL_ITEMS","CATEGORIES","ITEMS"]},"productGroups":{"type":"array","items":{"type":"string","enum":["FOOD_DRINK","HOSTESS","SPA_PACKAGE","ROOM_TIME"]}},"categoryIds":{"type":"array","items":{"type":"string"}},"variantIds":{"type":"array","items":{"type":"string"}},"items":{"description":"The items in variantIds, with their names","type":"array","items":{"$ref":"#/components/schemas/PromotionItemDto"}},"posTypes":{"type":"array","items":{"type":"string","enum":["BAR","SPA","KTV"]}},"locationIds":{"type":"array","items":{"type":"string"}},"startsOn":{"type":"string","nullable":true,"example":"2026-10-01"},"endsOn":{"type":"string","nullable":true,"example":"2026-12-31"},"daysOfWeek":{"example":[1,2,3,4,5],"type":"array","items":{"type":"number"}},"startTime":{"type":"string","nullable":true,"example":"17:00"},"endTime":{"type":"string","nullable":true,"example":"19:00"},"priorityLevel":{"type":"number","example":0},"isActive":{"type":"boolean","example":true},"runningNow":{"type":"boolean","example":true,"description":"Switched on and inside its dates, days and hours right now."},"createdAt":{"format":"date-time","type":"string","example":"2026-10-04T10:00:00.000Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-04T10:00:00.000Z"}},"required":["id","tenantId","name","discountType","discountValue","buyUnits","freeUnits","appliesTo","productGroups","categoryIds","variantIds","items","posTypes","locationIds","startsOn","endsOn","daysOfWeek","startTime","endTime","priorityLevel","isActive","runningNow","createdAt","updatedAt"]},"CreatePromotionDto":{"type":"object","properties":{"name":{"type":"string","maxLength":255,"example":"Happy hour drinks 20% off"},"discountType":{"type":"string","enum":["PERCENT_OFF","AMOUNT_OFF","FREE_TIME"],"example":"PERCENT_OFF"},"discountValue":{"type":"number","minimum":0.0001,"example":20,"description":"PERCENT_OFF: the percent (20 = 20%, at most 100). AMOUNT_OFF: money off each item. Required for both; not used by FREE_TIME."},"buyUnits":{"type":"number","minimum":1,"maximum":100,"example":1,"description":"FREE_TIME: units of time bought for each lot of free units (\"1\" in \"1 hour + 1 hour free\")."},"freeUnits":{"type":"number","minimum":1,"maximum":100,"example":1,"description":"FREE_TIME: units given free for each lot bought."},"appliesTo":{"type":"string","enum":["ALL_ITEMS","CATEGORIES","ITEMS"],"example":"CATEGORIES","description":"ALL_ITEMS: everything sold, or only the groups in productGroups. CATEGORIES: the categories in categoryIds and everything under them. ITEMS: the variants in variantIds."},"productGroups":{"type":"array","uniqueItems":true,"example":["FOOD_DRINK"],"description":"For ALL_ITEMS: only these groups (food & drink, hostess, SPA packages, room & table time). Empty or left out: everything sold.","items":{"type":"string","enum":["FOOD_DRINK","HOSTESS","SPA_PACKAGE","ROOM_TIME"]}},"categoryIds":{"uniqueItems":true,"maxItems":200,"example":["uuid"],"type":"array","items":{"type":"string","format":"uuid"}},"variantIds":{"uniqueItems":true,"maxItems":500,"example":[],"type":"array","items":{"type":"string","format":"uuid"}},"posTypes":{"type":"array","uniqueItems":true,"example":["BAR"],"description":"Only at these POS. Empty or left out: every POS.","items":{"type":"string","enum":["BAR","SPA","KTV"]}},"locationIds":{"uniqueItems":true,"maxItems":100,"example":[],"description":"Only at these outlets. Empty or left out: every outlet.","type":"array","items":{"type":"string","format":"uuid"}},"startsOn":{"type":"string","nullable":true,"pattern":"DATE","example":"2026-10-01","description":"First business date, YYYY-MM-DD. Null: already started."},"endsOn":{"type":"string","nullable":true,"pattern":"DATE","example":"2026-12-31","description":"Last business date, included. Null: no end."},"daysOfWeek":{"uniqueItems":true,"example":[1,2,3,4,5],"description":"Days it runs, 0-6 with Sunday as 0. Empty: every day.","type":"array","items":{"type":"number","maximum":6,"minimum":0}},"startTime":{"type":"string","nullable":true,"pattern":"TIME","example":"17:00","description":"Daily window start, HH:mm on the outlet clock. Send both times or neither (all day). An end before the start runs past midnight."},"endTime":{"type":"string","nullable":true,"pattern":"TIME","example":"19:00"},"priorityLevel":{"type":"number","minimum":0,"maximum":1000,"example":0,"description":"Higher wins when more promotions apply than the limit allows."},"isActive":{"type":"boolean","example":true,"description":"Off: kept but never applied."}},"required":["name","discountType","appliesTo"]},"AppliedPromotionDto":{"type":"object","properties":{"promotionId":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Happy hour drinks 20% off"},"amount":{"type":"string","example":"2000.0000"}},"required":["promotionId","name","amount"]},"PreviewLineDto":{"type":"object","properties":{"variantId":{"type":"string","example":"uuid"},"quantity":{"type":"string","example":"2.0000"},"unitPrice":{"type":"string","example":"5000.0000"},"discount":{"type":"string","example":"2000.0000","description":"Taken off this line"},"total":{"type":"string","example":"8000.0000","description":"Before tax"},"promotions":{"type":"array","items":{"$ref":"#/components/schemas/AppliedPromotionDto"}}},"required":["variantId","quantity","unitPrice","discount","total","promotions"]},"PromotionPreviewResultDto":{"type":"object","properties":{"maxPromotionsPerItem":{"type":"number","example":1,"description":"Promotions one item can get at once"},"maxPromotionsPerBill":{"type":"number","nullable":true,"example":null,"description":"Different promotions one bill can use; null for no limit"},"lines":{"type":"array","items":{"$ref":"#/components/schemas/PreviewLineDto"}},"totalDiscount":{"type":"string","example":"2000.0000"}},"required":["maxPromotionsPerItem","maxPromotionsPerBill","lines","totalDiscount"]},"PreviewItemDto":{"type":"object","properties":{"variantId":{"type":"string","format":"uuid","example":"uuid"},"quantity":{"type":"number","minimum":0.0001,"example":2},"unitPrice":{"type":"number","minimum":0,"example":25000,"description":"The price the till shows for one, e.g. a KTV hour at the peak rate. Left out: the catalogue price. Only for the preview; sales are priced on the server."}},"required":["variantId","quantity"]},"PromotionPreviewDto":{"type":"object","properties":{"locationId":{"type":"string","format":"uuid","example":"uuid","description":"The outlet selling."},"posType":{"type":"string","enum":["BAR","SPA","KTV"],"example":"BAR"},"salesOrderId":{"type":"string","format":"uuid","example":"uuid","description":"The open bill these items would join, so a per-bill limit counts the promotions it already used."},"items":{"minItems":1,"maxItems":100,"type":"array","items":{"$ref":"#/components/schemas/PreviewItemDto"}}},"required":["posType","items"]},"UpdatePromotionDto":{"type":"object","properties":{"name":{"type":"string","maxLength":255,"example":"Happy hour drinks 20% off"},"discountType":{"type":"string","enum":["PERCENT_OFF","AMOUNT_OFF","FREE_TIME"],"example":"PERCENT_OFF"},"discountValue":{"type":"number","minimum":0.0001,"example":20,"description":"PERCENT_OFF: the percent (20 = 20%, at most 100). AMOUNT_OFF: money off each item. Required for both; not used by FREE_TIME."},"buyUnits":{"type":"number","minimum":1,"maximum":100,"example":1,"description":"FREE_TIME: units of time bought for each lot of free units (\"1\" in \"1 hour + 1 hour free\")."},"freeUnits":{"type":"number","minimum":1,"maximum":100,"example":1,"description":"FREE_TIME: units given free for each lot bought."},"appliesTo":{"type":"string","enum":["ALL_ITEMS","CATEGORIES","ITEMS"],"example":"CATEGORIES","description":"ALL_ITEMS: everything sold, or only the groups in productGroups. CATEGORIES: the categories in categoryIds and everything under them. ITEMS: the variants in variantIds."},"productGroups":{"type":"array","uniqueItems":true,"example":["FOOD_DRINK"],"description":"For ALL_ITEMS: only these groups (food & drink, hostess, SPA packages, room & table time). Empty or left out: everything sold.","items":{"type":"string","enum":["FOOD_DRINK","HOSTESS","SPA_PACKAGE","ROOM_TIME"]}},"categoryIds":{"uniqueItems":true,"maxItems":200,"example":["uuid"],"type":"array","items":{"type":"string","format":"uuid"}},"variantIds":{"uniqueItems":true,"maxItems":500,"example":[],"type":"array","items":{"type":"string","format":"uuid"}},"posTypes":{"type":"array","uniqueItems":true,"example":["BAR"],"description":"Only at these POS. Empty or left out: every POS.","items":{"type":"string","enum":["BAR","SPA","KTV"]}},"locationIds":{"uniqueItems":true,"maxItems":100,"example":[],"description":"Only at these outlets. Empty or left out: every outlet.","type":"array","items":{"type":"string","format":"uuid"}},"startsOn":{"type":"string","nullable":true,"pattern":"DATE","example":"2026-10-01","description":"First business date, YYYY-MM-DD. Null: already started."},"endsOn":{"type":"string","nullable":true,"pattern":"DATE","example":"2026-12-31","description":"Last business date, included. Null: no end."},"daysOfWeek":{"uniqueItems":true,"example":[1,2,3,4,5],"description":"Days it runs, 0-6 with Sunday as 0. Empty: every day.","type":"array","items":{"type":"number","maximum":6,"minimum":0}},"startTime":{"type":"string","nullable":true,"pattern":"TIME","example":"17:00","description":"Daily window start, HH:mm on the outlet clock. Send both times or neither (all day). An end before the start runs past midnight."},"endTime":{"type":"string","nullable":true,"pattern":"TIME","example":"19:00"},"priorityLevel":{"type":"number","minimum":0,"maximum":1000,"example":0,"description":"Higher wins when more promotions apply than the limit allows."},"isActive":{"type":"boolean","example":true,"description":"Off: kept but never applied."}}},"InventoryLedgerEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"locationId":{"type":"string","example":"uuid"},"variantId":{"type":"string","example":"uuid"},"transactionType":{"type":"string","example":"GRN_RECEIPT"},"referenceId":{"type":"string","example":"uuid"},"quantity":{"type":"string","example":"100.0000"},"unitCost":{"type":"string","example":"25.5000"},"serialNumber":{"type":"string","nullable":true,"example":"SN-001"},"batchNumber":{"type":"string","nullable":true,"example":"BATCH-001"},"manufacturingDate":{"format":"date-time","type":"string","nullable":true,"example":"2025-01-01"},"expiryDate":{"format":"date-time","type":"string","nullable":true,"example":"2027-01-01"},"createdAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"},"createdBy":{"type":"string","nullable":true,"example":"uuid"},"locationName":{"type":"string","nullable":true,"example":"Main kitchen","description":"In lists only."},"productName":{"type":"string","nullable":true,"example":"Fresh milk","description":"In lists only."},"variantSku":{"type":"string","nullable":true,"example":"MILK-1L","description":"In lists only."}},"required":["id","tenantId","locationId","variantId","transactionType","referenceId","quantity","unitCost","createdAt"]},"CreateInventoryLedgerDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"locationId":{"type":"string","format":"uuid","example":"uuid"},"variantId":{"type":"string","format":"uuid","example":"uuid"},"transactionType":{"type":"string","example":"GRN_RECEIPT"},"referenceId":{"type":"string","format":"uuid","example":"uuid"},"quantity":{"type":"string","example":"100.0000"},"unitCost":{"type":"string","example":"25.5000"},"serialNumber":{"type":"string","example":"SN-001"},"batchNumber":{"type":"string","example":"BATCH-001"},"manufacturingDate":{"format":"date-time","type":"string","example":"2025-01-01"},"expiryDate":{"format":"date-time","type":"string","example":"2027-01-01"},"createdBy":{"type":"string","format":"uuid","example":"uuid"}},"required":["tenantId","locationId","variantId","transactionType","referenceId","quantity","unitCost"]},"WriteOffInventoryDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"variantId":{"type":"string","format":"uuid","example":"uuid"},"locationId":{"type":"string","format":"uuid","example":"uuid"},"quantity":{"type":"string","example":"5.0000","description":"Quantity to write off (positive number, will be deducted)"},"reason":{"type":"string","example":"Expired batch BATCH-001"},"batchNumber":{"type":"string","example":"BATCH-001"},"unitCost":{"type":"string","example":"25.5000"}},"required":["tenantId","variantId","locationId","quantity","reason"]},"InventoryBalanceDto":{"type":"object","properties":{"variantId":{"type":"string","example":"uuid"},"locationId":{"type":"string","example":"uuid"},"balance":{"type":"string","example":"48.0000","description":"Zero when the variant has never moved at that location."}},"required":["variantId","locationId","balance"]},"ExchangeRateEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"baseCurrency":{"type":"string","example":"USD"},"targetCurrency":{"type":"string","example":"EUR"},"rate":{"type":"string","example":"1.0850"},"effectiveFrom":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"},"effectiveTo":{"format":"date-time","type":"string","nullable":true,"example":"2026-12-31T00:00:00.000Z"},"createdAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"}},"required":["id","tenantId","baseCurrency","targetCurrency","rate","effectiveFrom","createdAt","updatedAt"]},"CreateExchangeRateDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"baseCurrency":{"type":"string","example":"USD"},"targetCurrency":{"type":"string","example":"EUR"},"rate":{"type":"string","example":"1.0850"},"effectiveFrom":{"format":"date-time","type":"string","example":"2026-01-01"},"effectiveTo":{"format":"date-time","type":"string","example":"2026-12-31"}},"required":["tenantId","baseCurrency","targetCurrency","rate","effectiveFrom"]},"UpdateExchangeRateDto":{"type":"object","properties":{"baseCurrency":{"type":"string","example":"USD"},"targetCurrency":{"type":"string","example":"EUR"},"rate":{"type":"string","example":"1.0850"},"effectiveFrom":{"format":"date-time","type":"string","example":"2026-01-01"},"effectiveTo":{"format":"date-time","type":"string","example":"2026-12-31"}}},"TaxRateEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"name":{"type":"string","example":"VAT Standard"},"ratePercentage":{"type":"string","example":"15.0000"},"isPriceInclusive":{"type":"boolean","nullable":true,"example":true},"appliesToServiceCharge":{"type":"boolean","example":false},"deletedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"glLiabilityAccountId":{"type":"string","nullable":true,"example":"uuid"},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.150Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.150Z"}},"required":["id","tenantId","name","ratePercentage","appliesToServiceCharge","createdAt","updatedAt"]},"CreateTaxRateDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"name":{"type":"string","example":"VAT Standard"},"ratePercentage":{"type":"string","example":"0.0500","description":"A fraction between 0 and 1: 0.05 is 5%."},"isPriceInclusive":{"type":"boolean","example":true},"appliesToServiceCharge":{"type":"boolean","example":false,"default":false,"description":"Also charged on the service charge, not only on the items."},"glLiabilityAccountId":{"type":"string","format":"uuid","example":"uuid"}},"required":["tenantId","name","ratePercentage"]},"UpdateTaxRateDto":{"type":"object","properties":{"name":{"type":"string","example":"VAT Standard"},"ratePercentage":{"type":"string","example":"0.0500","description":"A fraction between 0 and 1: 0.05 is 5%."},"isPriceInclusive":{"type":"boolean","example":true},"appliesToServiceCharge":{"type":"boolean","example":false,"default":false,"description":"Also charged on the service charge, not only on the items."},"glLiabilityAccountId":{"type":"string","format":"uuid","example":"uuid"}}},"AccountingPeriodEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"periodName":{"type":"string","example":"Q1 2026"},"startDate":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"},"endDate":{"format":"date-time","type":"string","example":"2026-03-31T00:00:00.000Z"},"status":{"type":"string","nullable":true,"example":"OPEN","enum":["OPEN","CLOSED","LOCKED_FOR_AUDIT"]},"createdAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"}},"required":["id","tenantId","periodName","startDate","endDate","createdAt","updatedAt"]},"CreateAccountingPeriodDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"periodName":{"type":"string","example":"Q1 2026"},"startDate":{"format":"date-time","type":"string","example":"2026-01-01"},"endDate":{"format":"date-time","type":"string","example":"2026-03-31"},"status":{"type":"string","example":"OPEN","enum":["OPEN","CLOSED","LOCKED_FOR_AUDIT"]}},"required":["tenantId","periodName","startDate","endDate"]},"UpdateAccountingPeriodDto":{"type":"object","properties":{"periodName":{"type":"string","example":"Q1 2026"},"startDate":{"format":"date-time","type":"string","example":"2026-01-01"},"endDate":{"format":"date-time","type":"string","example":"2026-03-31"},"status":{"type":"string","example":"OPEN","enum":["OPEN","CLOSED","LOCKED_FOR_AUDIT"]}}},"ChartOfAccountEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"parentAccountId":{"type":"string","nullable":true,"example":"uuid"},"accountCode":{"type":"string","example":"1000"},"accountName":{"type":"string","example":"Cash and Cash Equivalents"},"accountType":{"type":"string","example":"ASSET"},"isReconcilable":{"type":"boolean","nullable":true,"example":true},"createdAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"}},"required":["id","tenantId","accountCode","accountName","accountType","createdAt","updatedAt"]},"CreateChartOfAccountDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"parentAccountId":{"type":"string","format":"uuid","example":"uuid"},"accountCode":{"type":"string","example":"1000"},"accountName":{"type":"string","example":"Cash and Cash Equivalents"},"accountType":{"type":"string","example":"ASSET"},"isReconcilable":{"type":"boolean","example":true}},"required":["tenantId","accountCode","accountName","accountType"]},"UpdateChartOfAccountDto":{"type":"object","properties":{"parentAccountId":{"type":"string","format":"uuid","example":"uuid"},"accountCode":{"type":"string","example":"1000"},"accountName":{"type":"string","example":"Cash and Cash Equivalents"},"accountType":{"type":"string","example":"ASSET"},"isReconcilable":{"type":"boolean","example":true}}},"JournalEntryEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"periodId":{"type":"string","example":"uuid"},"entryDate":{"format":"date-time","type":"string","example":"2026-01-15T00:00:00.000Z"},"description":{"type":"string","nullable":true,"example":"Monthly payroll entry"},"sourceModule":{"type":"string","nullable":true,"example":"payroll"},"sourceRecordId":{"type":"string","nullable":true,"example":"uuid"},"status":{"type":"string","nullable":true,"example":"DRAFT","enum":["DRAFT","POSTED","VOIDED"]},"postedAt":{"format":"date-time","type":"string","nullable":true,"example":"2026-01-15T00:00:00.000Z"},"postedBy":{"type":"string","nullable":true,"example":"uuid"},"createdAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"}},"required":["id","tenantId","periodId","entryDate","createdAt","updatedAt"]},"CreateJournalEntryDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"periodId":{"type":"string","format":"uuid","example":"uuid"},"description":{"type":"string","example":"Monthly payroll entry"},"sourceModule":{"type":"string","example":"payroll"},"sourceRecordId":{"type":"string","format":"uuid","example":"uuid"},"status":{"type":"string","example":"DRAFT","enum":["DRAFT","POSTED","VOIDED"]},"postedBy":{"type":"string","format":"uuid","example":"uuid"}},"required":["tenantId","periodId"]},"UpdateJournalEntryDto":{"type":"object","properties":{"periodId":{"type":"string","format":"uuid","example":"uuid"},"description":{"type":"string","example":"Monthly payroll entry"},"sourceModule":{"type":"string","example":"payroll"},"sourceRecordId":{"type":"string","format":"uuid","example":"uuid"},"status":{"type":"string","example":"DRAFT","enum":["DRAFT","POSTED","VOIDED"]},"postedBy":{"type":"string","format":"uuid","example":"uuid"}}},"JournalLineEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"journalEntryId":{"type":"string","example":"uuid"},"accountId":{"type":"string","example":"uuid"},"transactionCurrency":{"type":"string","example":"USD"},"transactionDebit":{"type":"string","nullable":true,"example":"1000.0000"},"transactionCredit":{"type":"string","nullable":true,"example":"0.0000"},"exchangeRate":{"type":"string","nullable":true,"example":"1.0000"},"baseDebit":{"type":"string","nullable":true,"example":"1000.0000"},"baseCredit":{"type":"string","nullable":true,"example":"0.0000"}},"required":["id","journalEntryId","accountId","transactionCurrency"]},"CreateJournalLineDto":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","example":"uuid"},"transactionCurrency":{"type":"string","example":"USD"},"transactionDebit":{"type":"string","example":"1000.0000"},"transactionCredit":{"type":"string","example":"0.0000"},"exchangeRate":{"type":"string","example":"1.0000"},"baseDebit":{"type":"string","example":"1000.0000"},"baseCredit":{"type":"string","example":"0.0000"}},"required":["accountId","transactionCurrency"]},"UpdateJournalLineDto":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","example":"uuid"},"transactionCurrency":{"type":"string","example":"USD"},"transactionDebit":{"type":"string","example":"1000.0000"},"transactionCredit":{"type":"string","example":"0.0000"},"exchangeRate":{"type":"string","example":"1.0000"},"baseDebit":{"type":"string","example":"1000.0000"},"baseCredit":{"type":"string","example":"0.0000"}}},"BankStatementEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"glAccountId":{"type":"string","example":"uuid"},"statementDate":{"format":"date-time","type":"string","example":"2026-01-31T00:00:00.000Z"},"openingBalance":{"type":"string","nullable":true,"example":"10000.0000"},"closingBalance":{"type":"string","nullable":true,"example":"12500.0000"},"createdAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"}},"required":["id","tenantId","glAccountId","statementDate","createdAt","updatedAt"]},"CreateBankStatementDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"glAccountId":{"type":"string","format":"uuid","example":"uuid"},"statementDate":{"format":"date-time","type":"string","example":"2026-01-31"},"openingBalance":{"type":"string","example":"10000.0000"},"closingBalance":{"type":"string","example":"12500.0000"}},"required":["tenantId","glAccountId","statementDate"]},"UpdateBankStatementDto":{"type":"object","properties":{"glAccountId":{"type":"string","format":"uuid","example":"uuid"},"statementDate":{"format":"date-time","type":"string","example":"2026-01-31"},"openingBalance":{"type":"string","example":"10000.0000"},"closingBalance":{"type":"string","example":"12500.0000"}}},"BankStatementLineEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"statementId":{"type":"string","example":"uuid"},"transactionDate":{"format":"date-time","type":"string","example":"2026-01-15T00:00:00.000Z"},"description":{"type":"string","example":"Wire transfer from client"},"referenceNumber":{"type":"string","nullable":true,"example":"REF-001"},"amount":{"type":"string","example":"500.0000"},"status":{"type":"string","nullable":true,"example":"UNMATCHED","enum":["UNMATCHED","MATCHED"]}},"required":["id","statementId","transactionDate","description","amount"]},"CreateBankStatementLineDto":{"type":"object","properties":{"transactionDate":{"format":"date-time","type":"string","example":"2026-01-15"},"description":{"type":"string","example":"Wire transfer from client"},"referenceNumber":{"type":"string","example":"REF-001"},"amount":{"type":"string","example":"500.0000"},"status":{"type":"string","example":"UNMATCHED","enum":["UNMATCHED","MATCHED"]}},"required":["transactionDate","description","amount"]},"UpdateBankStatementLineDto":{"type":"object","properties":{"transactionDate":{"format":"date-time","type":"string","example":"2026-01-15"},"description":{"type":"string","example":"Wire transfer from client"},"referenceNumber":{"type":"string","example":"REF-001"},"amount":{"type":"string","example":"500.0000"},"status":{"type":"string","example":"UNMATCHED","enum":["UNMATCHED","MATCHED"]}}},"ReconciliationMatchEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"statementLineId":{"type":"string","example":"uuid"},"journalLineId":{"type":"string","example":"uuid"},"matchedBy":{"type":"string","nullable":true,"example":"uuid"},"matchedAt":{"format":"date-time","type":"string","example":"2026-01-15T00:00:00.000Z"}},"required":["id","statementLineId","journalLineId","matchedAt"]},"CreateReconciliationMatchDto":{"type":"object","properties":{"statementLineId":{"type":"string","format":"uuid","example":"uuid"},"journalLineId":{"type":"string","format":"uuid","example":"uuid"},"matchedBy":{"type":"string","format":"uuid","example":"uuid"}},"required":["statementLineId","journalLineId"]},"UpdateReconciliationMatchDto":{"type":"object","properties":{"statementLineId":{"type":"string","format":"uuid","example":"uuid"},"journalLineId":{"type":"string","format":"uuid","example":"uuid"},"matchedBy":{"type":"string","format":"uuid","example":"uuid"}}},"FixedAssetEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"assetName":{"type":"string","example":"Office Laptop"},"serialNumber":{"type":"string","nullable":true,"example":"SN-12345"},"assetAccountId":{"type":"string","nullable":true,"example":"uuid"},"depreciationExpenseAccountId":{"type":"string","nullable":true,"example":"uuid"},"accumulatedDepreciationAccountId":{"type":"string","nullable":true,"example":"uuid"},"purchaseDate":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"},"purchaseCost":{"type":"string","example":"1500.0000"},"salvageValue":{"type":"string","nullable":true,"example":"200.0000"},"usefulLifeMonths":{"type":"number","example":60},"depreciationMethod":{"type":"string","nullable":true,"example":"STRAIGHT_LINE"},"status":{"type":"string","nullable":true,"example":"ACTIVE","enum":["ACTIVE","FULLY_DEPRECIATED","DISPOSED"]},"createdAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"}},"required":["id","tenantId","assetName","purchaseDate","purchaseCost","usefulLifeMonths","createdAt","updatedAt"]},"CreateFixedAssetDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"assetName":{"type":"string","example":"Office Laptop"},"serialNumber":{"type":"string","example":"SN-12345"},"assetAccountId":{"type":"string","format":"uuid","example":"uuid"},"depreciationExpenseAccountId":{"type":"string","format":"uuid","example":"uuid"},"accumulatedDepreciationAccountId":{"type":"string","format":"uuid","example":"uuid"},"purchaseDate":{"format":"date-time","type":"string","example":"2026-01-01"},"purchaseCost":{"type":"string","example":"1500.0000"},"salvageValue":{"type":"string","example":"200.0000"},"usefulLifeMonths":{"type":"number","example":60},"depreciationMethod":{"type":"string","example":"STRAIGHT_LINE"},"status":{"type":"string","example":"ACTIVE","enum":["ACTIVE","FULLY_DEPRECIATED","DISPOSED"]}},"required":["tenantId","assetName","purchaseDate","purchaseCost","usefulLifeMonths"]},"UpdateFixedAssetDto":{"type":"object","properties":{"assetName":{"type":"string","example":"Office Laptop"},"serialNumber":{"type":"string","example":"SN-12345"},"assetAccountId":{"type":"string","format":"uuid","example":"uuid"},"depreciationExpenseAccountId":{"type":"string","format":"uuid","example":"uuid"},"accumulatedDepreciationAccountId":{"type":"string","format":"uuid","example":"uuid"},"purchaseDate":{"format":"date-time","type":"string","example":"2026-01-01"},"purchaseCost":{"type":"string","example":"1500.0000"},"salvageValue":{"type":"string","example":"200.0000"},"usefulLifeMonths":{"type":"number","example":60},"depreciationMethod":{"type":"string","example":"STRAIGHT_LINE"},"status":{"type":"string","example":"ACTIVE","enum":["ACTIVE","FULLY_DEPRECIATED","DISPOSED"]}}},"DepreciationScheduleEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"assetId":{"type":"string","example":"uuid"},"scheduledDate":{"format":"date-time","type":"string","example":"2026-02-01T00:00:00.000Z"},"depreciationAmount":{"type":"string","example":"21.67"},"isPosted":{"type":"boolean","nullable":true,"example":false},"postedJournalEntryId":{"type":"string","nullable":true,"example":"uuid"}},"required":["id","assetId","scheduledDate","depreciationAmount"]},"CreateDepreciationScheduleDto":{"type":"object","properties":{"scheduledDate":{"format":"date-time","type":"string","example":"2026-02-01"},"depreciationAmount":{"type":"string","example":"21.67"},"isPosted":{"type":"boolean","example":false},"postedJournalEntryId":{"type":"string","format":"uuid","example":"uuid"}},"required":["scheduledDate","depreciationAmount"]},"UpdateDepreciationScheduleDto":{"type":"object","properties":{"scheduledDate":{"format":"date-time","type":"string","example":"2026-02-01"},"depreciationAmount":{"type":"string","example":"21.67"},"isPosted":{"type":"boolean","example":false},"postedJournalEntryId":{"type":"string","format":"uuid","example":"uuid"}}},"UploadResponseDto":{"type":"object","properties":{"id":{"type":"string","example":"550e8400-e29b-41d4-a716-446655440000"},"url":{"type":"string","example":"/uploads/tenant-uuid/branch-uuid/products/iphone15-1712345678000-123456789.jpg"},"originalName":{"type":"string","example":"iphone15.jpg"},"filename":{"type":"string","example":"iphone15-1712345678000-123456789.jpg"},"folder":{"type":"string","example":"products"},"mimeType":{"type":"string","example":"image/jpeg"},"size":{"type":"number","example":204800,"description":"File size in bytes"},"createdAt":{"format":"date-time","type":"string","example":"2026-04-06T12:00:00.000Z"}},"required":["id","url","originalName","filename","folder","mimeType","size","createdAt"]},"ModifierGroupEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Choose protein"},"minSelection":{"type":"number","example":0},"maxSelection":{"type":"number","nullable":true,"example":1},"isRequired":{"type":"boolean","example":false},"deletedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.465Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.466Z"}},"required":["id","tenantId","name","minSelection","isRequired","createdAt","updatedAt"]},"CreateModifierGroupDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"name":{"type":"string","example":"Choose protein"},"minSelection":{"type":"number","minimum":0,"example":0},"maxSelection":{"type":"number","minimum":1,"example":1},"isRequired":{"type":"boolean","example":false}},"required":["tenantId","name"]},"UpdateModifierGroupDto":{"type":"object","properties":{"name":{"type":"string","example":"Choose protein"},"minSelection":{"type":"number","minimum":0,"example":0},"maxSelection":{"type":"number","minimum":1,"example":1},"isRequired":{"type":"boolean","example":false}}},"AttachModifierGroupDto":{"type":"object","properties":{"productId":{"type":"string","format":"uuid","example":"uuid"},"sortOrder":{"type":"number","minimum":0,"example":0}},"required":["productId"]},"ModifierEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"modifierGroupId":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Bacon"},"priceDelta":{"type":"string","example":"2.0000"},"sortOrder":{"type":"number","example":0},"isDefault":{"type":"boolean","example":false},"deletedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.471Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.471Z"}},"required":["id","modifierGroupId","name","priceDelta","sortOrder","isDefault","createdAt","updatedAt"]},"CreateModifierDto":{"type":"object","properties":{"name":{"type":"string","example":"Bacon"},"priceDelta":{"type":"number","example":2},"sortOrder":{"type":"number","minimum":0,"example":0},"isDefault":{"type":"boolean","example":false}},"required":["name"]},"UpdateModifierDto":{"type":"object","properties":{"name":{"type":"string","example":"Bacon"},"priceDelta":{"type":"number","example":2},"sortOrder":{"type":"number","minimum":0,"example":0},"isDefault":{"type":"boolean","example":false}}},"RecipeEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"variantId":{"type":"string","example":"uuid"},"yield":{"type":"string","example":"1.0000"},"notes":{"type":"string","nullable":true,"example":"Mix dry, then wet, then bake."},"isActive":{"type":"boolean","example":true},"deletedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.485Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.485Z"}},"required":["id","tenantId","variantId","yield","isActive","createdAt","updatedAt"]},"CreateRecipeIngredientDto":{"type":"object","properties":{"ingredientVariantId":{"type":"string","format":"uuid","example":"uuid"},"quantity":{"type":"number","minimum":0,"example":1.5},"uomId":{"type":"string","format":"uuid","example":"uuid"},"isOptional":{"type":"boolean","example":false},"notes":{"type":"string","example":"Use room-temperature butter"}},"required":["ingredientVariantId","quantity","uomId"]},"CreateRecipeDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"variantId":{"type":"string","format":"uuid","example":"uuid"},"yield":{"type":"number","minimum":0,"example":1},"notes":{"type":"string","example":"Mix everything and bake."},"isActive":{"type":"boolean","example":true},"ingredients":{"minItems":1,"type":"array","items":{"$ref":"#/components/schemas/CreateRecipeIngredientDto"}}},"required":["tenantId","variantId","ingredients"]},"UpdateRecipeDto":{"type":"object","properties":{"yield":{"type":"number","minimum":0,"example":1},"notes":{"type":"string","example":"Updated notes."},"isActive":{"type":"boolean","example":true},"ingredients":{"description":"When provided, replaces the entire ingredient list with this set.","type":"array","items":{"$ref":"#/components/schemas/CreateRecipeIngredientDto"}}}},"BundleEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"productId":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Burger Combo"},"description":{"type":"string","nullable":true,"example":"Burger + fries + drink"},"isActive":{"type":"boolean","example":true},"deletedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.496Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.496Z"}},"required":["id","tenantId","productId","name","isActive","createdAt","updatedAt"]},"CreateBundleComponentDto":{"type":"object","properties":{"variantId":{"type":"string","format":"uuid","example":"uuid"},"quantity":{"type":"number","minimum":0,"example":1},"swapGroupId":{"type":"string","example":"side","description":"Components sharing a swapGroupId can be substituted at order time"}},"required":["variantId"]},"CreateBundleDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"productId":{"type":"string","format":"uuid","example":"uuid","description":"The parent product representing this combo SKU"},"name":{"type":"string","example":"Burger Combo"},"description":{"type":"string","example":"Burger + fries + drink"},"isActive":{"type":"boolean","example":true},"components":{"minItems":1,"type":"array","items":{"$ref":"#/components/schemas/CreateBundleComponentDto"}}},"required":["tenantId","productId","name","components"]},"UpdateBundleDto":{"type":"object","properties":{"name":{"type":"string","example":"Burger Combo"},"description":{"type":"string","example":"Updated description"},"isActive":{"type":"boolean","example":true},"components":{"description":"When provided, replaces the entire component list with this set.","type":"array","items":{"$ref":"#/components/schemas/CreateBundleComponentDto"}}}},"PricingScheduleEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Happy Hour"},"startsAt":{"format":"date-time","type":"string","nullable":true,"example":"2026-10-23T14:44:06.510Z"},"endsAt":{"format":"date-time","type":"string","nullable":true,"example":"2026-10-23T14:44:06.510Z"},"daysOfWeek":{"example":[1,2,3,4,5],"description":"0=Sun … 6=Sat","type":"array","items":{"type":"number"}},"startTime":{"type":"string","nullable":true,"example":"17:00"},"endTime":{"type":"string","nullable":true,"example":"19:00"},"priority":{"type":"number","example":0},"isActive":{"type":"boolean","example":true},"deletedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.511Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.511Z"}},"required":["id","tenantId","name","daysOfWeek","priority","isActive","createdAt","updatedAt"]},"CreatePricingRuleDto":{"type":"object","properties":{"variantId":{"type":"string","format":"uuid","example":"uuid"},"categoryId":{"type":"string","format":"uuid","example":"uuid"},"adjustmentType":{"enum":["PERCENT_OFF","AMOUNT_OFF","FIXED_PRICE"],"type":"string"},"adjustmentValue":{"type":"number","example":10}},"required":["adjustmentType","adjustmentValue"]},"CreatePricingScheduleDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"name":{"type":"string","example":"Happy Hour"},"startsAt":{"type":"string","example":"2026-01-01T00:00:00Z"},"endsAt":{"type":"string","example":"2026-12-31T23:59:59Z"},"daysOfWeek":{"uniqueItems":true,"example":[1,2,3,4,5],"description":"Days of week, 0=Sun … 6=Sat","type":"array","items":{"type":"number","maximum":6,"minimum":0}},"startTime":{"type":"string","pattern":"/^([01]\\d|2[0-3]):[0-5]\\d$/","example":"17:00","description":"24h HH:MM"},"endTime":{"type":"string","pattern":"/^([01]\\d|2[0-3]):[0-5]\\d$/","example":"19:00","description":"24h HH:MM"},"priority":{"type":"number","example":0},"isActive":{"type":"boolean","example":true},"rules":{"type":"array","items":{"$ref":"#/components/schemas/CreatePricingRuleDto"}}},"required":["tenantId","name"]},"UpdatePricingScheduleDto":{"type":"object","properties":{"name":{"type":"string","example":"Happy Hour"},"startsAt":{"type":"string","example":"2026-01-01T00:00:00Z"},"endsAt":{"type":"string","example":"2026-12-31T23:59:59Z"},"daysOfWeek":{"uniqueItems":true,"example":[1,2,3,4,5],"description":"Days of week, 0=Sun … 6=Sat","type":"array","items":{"type":"number","maximum":6,"minimum":0}},"startTime":{"type":"string","pattern":"/^([01]\\d|2[0-3]):[0-5]\\d$/","example":"17:00","description":"24h HH:MM"},"endTime":{"type":"string","pattern":"/^([01]\\d|2[0-3]):[0-5]\\d$/","example":"19:00","description":"24h HH:MM"},"priority":{"type":"number","example":0},"isActive":{"type":"boolean","example":true},"rules":{"type":"array","items":{"$ref":"#/components/schemas/CreatePricingRuleDto"}}}},"DiningZoneEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Patio"},"layoutSvg":{"type":"string","nullable":true,"example":"<svg>...</svg>"},"sortOrder":{"type":"number","example":0},"deletedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.521Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.521Z"}},"required":["id","tenantId","name","sortOrder","createdAt","updatedAt"]},"CreateDiningZoneDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"name":{"type":"string","example":"Patio"},"layoutSvg":{"type":"string","example":"<svg>...</svg>"},"sortOrder":{"type":"number","minimum":0,"example":0}},"required":["tenantId","name"]},"UpdateDiningZoneDto":{"type":"object","properties":{"name":{"type":"string","example":"Patio"},"layoutSvg":{"type":"string","example":"<svg>...</svg>"},"sortOrder":{"type":"number","minimum":0,"example":0}}},"ActiveTableSessionEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"salesOrderId":{"type":"string","nullable":true,"example":"uuid"},"guestCount":{"type":"number","example":4},"sessionState":{"type":"string","nullable":true,"enum":["SEATED","ORDERING","SERVED","PAYMENT_PENDING","CLOSED"],"example":"SEATED"},"openedAt":{"format":"date-time","type":"string","example":"2026-09-19T06:32:00.000Z","description":"When the party was seated, in UTC. Render the clock time in the tenant timezone."},"seatedSeconds":{"type":"number","example":59280,"description":"Seconds since openedAt, measured on the server as the response was built. A badge that ticks should count up from openedAt itself rather than reuse this snapshot, which ages the moment it is sent."},"itemCount":{"type":"number","example":12,"description":"Units ordered: the sum of line quantities, not the number of lines. Voided lines are excluded; comped lines are counted."}},"required":["id","guestCount","openedAt","seatedSeconds","itemCount"]},"DiningTableEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"zoneId":{"type":"string","example":"uuid"},"tableNumber":{"type":"string","example":"T-12"},"maxSeats":{"type":"number","example":4},"posX":{"type":"string","nullable":true,"example":"120.50"},"posY":{"type":"string","nullable":true,"example":"85.00"},"shape":{"type":"string","nullable":true,"example":"RECTANGLE"},"status":{"type":"string","nullable":true,"enum":["AVAILABLE","OCCUPIED","DIRTY","RESERVED"],"example":"AVAILABLE"},"deletedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.547Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.547Z"},"activeSession":{"nullable":true,"description":"The open session on this table, or null when nobody is seated. Carries the guest count, item count and seated duration the floor-plan card shows.","allOf":[{"$ref":"#/components/schemas/ActiveTableSessionEntity"}]}},"required":["id","tenantId","zoneId","tableNumber","maxSeats","createdAt","updatedAt"]},"CreateDiningTableDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"zoneId":{"type":"string","format":"uuid","example":"uuid"},"tableNumber":{"type":"string","example":"T-12"},"maxSeats":{"type":"number","minimum":1,"maximum":50,"example":4},"posX":{"type":"number","example":120.5},"posY":{"type":"number","example":85},"shape":{"type":"string","example":"RECTANGLE"},"status":{"type":"string","enum":["AVAILABLE","OCCUPIED","DIRTY","RESERVED"]}},"required":["tenantId","zoneId","tableNumber","maxSeats"]},"UpdateDiningTableDto":{"type":"object","properties":{"zoneId":{"type":"string","format":"uuid","example":"uuid"},"tableNumber":{"type":"string","example":"T-12"},"maxSeats":{"type":"number","minimum":1,"maximum":50,"example":4},"posX":{"type":"number","example":120.5},"posY":{"type":"number","example":85},"shape":{"type":"string","example":"RECTANGLE"},"status":{"type":"string","enum":["AVAILABLE","OCCUPIED","DIRTY","RESERVED"]}}},"UpdateDiningTableStatusDto":{"type":"object","properties":{"status":{"type":"string","enum":["AVAILABLE","OCCUPIED","DIRTY","RESERVED"]}},"required":["status"]},"SectionEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"locationId":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Section A"},"color":{"type":"string","nullable":true,"example":"#FF5733"},"deletedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.563Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.563Z"}},"required":["id","tenantId","locationId","name","createdAt","updatedAt"]},"CreateSectionDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"locationId":{"type":"string","format":"uuid","example":"uuid"},"name":{"type":"string","example":"Section A"},"color":{"type":"string","example":"#FF5733"}},"required":["tenantId","locationId","name"]},"UpdateSectionDto":{"type":"object","properties":{"locationId":{"type":"string","format":"uuid","example":"uuid"},"name":{"type":"string","example":"Section A"},"color":{"type":"string","example":"#FF5733"}}},"AttachTableDto":{"type":"object","properties":{"tableId":{"type":"string","format":"uuid","example":"uuid"}},"required":["tableId"]},"SectionAssignmentEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"sectionId":{"type":"string","example":"uuid"},"userId":{"type":"string","example":"uuid"},"startsAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.564Z"},"endsAt":{"format":"date-time","type":"string","nullable":true,"example":null,"description":"When null, this assignment is currently active"},"notes":{"type":"string","nullable":true,"example":"Lunch shift coverage"},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.564Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.564Z"}},"required":["id","sectionId","userId","startsAt","createdAt","updatedAt"]},"CreateSectionAssignmentDto":{"type":"object","properties":{"userId":{"type":"string","format":"uuid","example":"uuid"},"startsAt":{"type":"string","example":"2026-05-05T11:00:00Z"},"endsAt":{"type":"string","example":"2026-05-05T15:00:00Z","description":"When omitted, the assignment is open-ended (currently active)"},"notes":{"type":"string","example":"Lunch shift coverage"}},"required":["userId","startsAt"]},"UpdateSectionAssignmentDto":{"type":"object","properties":{"endsAt":{"type":"string","example":"2026-05-05T15:00:00Z"},"notes":{"type":"string","example":"Updated notes"}}},"KitchenPrinterEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"locationId":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Hot Line Printer"},"ipAddress":{"type":"string","nullable":true,"example":"192.168.1.50"},"port":{"type":"number","nullable":true,"example":9100},"sectors":{"type":"array","example":["KDS"],"description":"Where this printer serves: a KDS station, the till, the office.","items":{"type":"string","enum":["KDS","CHECKOUT","FINANCE"]}},"isActive":{"type":"boolean","example":true},"deletedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.583Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.584Z"}},"required":["id","tenantId","locationId","name","sectors","isActive","createdAt","updatedAt"]},"CreateKitchenPrinterDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"locationId":{"type":"string","format":"uuid","example":"uuid"},"name":{"type":"string","example":"Hot Line Printer"},"ipAddress":{"type":"string","nullable":true,"example":"192.168.1.50","description":"Network printers only. Leave out, or send empty or null, for a USB or Bluetooth printer."},"port":{"type":"number","nullable":true,"minimum":1,"maximum":65535,"example":9100},"sectors":{"type":"array","uniqueItems":true,"minItems":1,"example":["CHECKOUT","FINANCE"],"description":"Where this printer serves: KDS (a kitchen station), CHECKOUT (the till), FINANCE (the office copy). Defaults to [KDS].","items":{"type":"string","enum":["KDS","CHECKOUT","FINANCE"]}},"isActive":{"type":"boolean","example":true}},"required":["tenantId","locationId","name"]},"PrinterCategoryDto":{"type":"object","properties":{"printerId":{"type":"string","example":"uuid"},"categoryId":{"type":"string","example":"uuid"},"category":{"$ref":"#/components/schemas/CategoryEntity"}},"required":["printerId","categoryId","category"]},"KitchenPrinterDetailDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"locationId":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Hot Line Printer"},"ipAddress":{"type":"string","nullable":true,"example":"192.168.1.50"},"port":{"type":"number","nullable":true,"example":9100},"sectors":{"type":"array","example":["KDS"],"description":"Where this printer serves: a KDS station, the till, the office.","items":{"type":"string","enum":["KDS","CHECKOUT","FINANCE"]}},"isActive":{"type":"boolean","example":true},"deletedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.583Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.584Z"},"categories":{"description":"Categories routed to this printer for prints outside the KDS flow. KDS tickets print at their station's printers instead.","type":"array","items":{"$ref":"#/components/schemas/PrinterCategoryDto"}}},"required":["id","tenantId","locationId","name","sectors","isActive","createdAt","updatedAt","categories"]},"UpdateKitchenPrinterDto":{"type":"object","properties":{"locationId":{"type":"string","format":"uuid","example":"uuid"},"name":{"type":"string","example":"Hot Line Printer"},"ipAddress":{"type":"string","nullable":true,"example":"192.168.1.50","description":"Network printers only. Leave out, or send empty or null, for a USB or Bluetooth printer."},"port":{"type":"number","nullable":true,"minimum":1,"maximum":65535,"example":9100},"sectors":{"type":"array","uniqueItems":true,"minItems":1,"example":["CHECKOUT","FINANCE"],"description":"Where this printer serves: KDS (a kitchen station), CHECKOUT (the till), FINANCE (the office copy). Defaults to [KDS].","items":{"type":"string","enum":["KDS","CHECKOUT","FINANCE"]}},"isActive":{"type":"boolean","example":true}}},"AttachCategoryDto":{"type":"object","properties":{"categoryId":{"type":"string","format":"uuid","example":"uuid"}},"required":["categoryId"]},"DiscountReasonEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"code":{"type":"string","example":"SENIOR_15"},"name":{"type":"string","example":"Senior citizen 15% off"},"description":{"type":"string","nullable":true,"example":"Applies to customers 65 and older"},"isActive":{"type":"boolean","example":true},"requiresManagerOverride":{"type":"boolean","example":false},"deletedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.601Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.601Z"}},"required":["id","tenantId","code","name","isActive","requiresManagerOverride","createdAt","updatedAt"]},"CreateDiscountReasonDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"code":{"type":"string","maxLength":50,"pattern":"/^[A-Z0-9_]+$/","example":"SENIOR_15"},"name":{"type":"string","example":"Senior citizen 15% off"},"description":{"type":"string","example":"Applies to customers 65 and older"},"isActive":{"type":"boolean","example":true},"requiresManagerOverride":{"type":"boolean","example":false}},"required":["tenantId","code","name"]},"UpdateDiscountReasonDto":{"type":"object","properties":{"name":{"type":"string","example":"Senior citizen 15% off"},"description":{"type":"string","example":"Applies to customers 65 and older"},"isActive":{"type":"boolean","example":true},"requiresManagerOverride":{"type":"boolean","example":false}}},"VoidReasonEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"code":{"type":"string","example":"CUSTOMER_CHANGED_MIND"},"name":{"type":"string","example":"Customer changed their mind"},"description":{"type":"string","nullable":true,"example":"Used when the customer modifies their order before service"},"isActive":{"type":"boolean","example":true},"requiresManagerOverride":{"type":"boolean","example":false},"deletedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.642Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.642Z"}},"required":["id","tenantId","code","name","isActive","requiresManagerOverride","createdAt","updatedAt"]},"CreateVoidReasonDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"code":{"type":"string","maxLength":50,"pattern":"/^[A-Z0-9_]+$/","example":"CUSTOMER_CHANGED_MIND"},"name":{"type":"string","example":"Customer changed their mind"},"description":{"type":"string","example":"Used when the customer modifies their order before service"},"isActive":{"type":"boolean","example":true},"requiresManagerOverride":{"type":"boolean","example":false}},"required":["tenantId","code","name"]},"UpdateVoidReasonDto":{"type":"object","properties":{"name":{"type":"string","example":"Customer changed their mind"},"description":{"type":"string","example":"Used when the customer modifies their order before service"},"isActive":{"type":"boolean","example":true},"requiresManagerOverride":{"type":"boolean","example":false}}},"TableSessionEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"tableId":{"type":"string","example":"uuid"},"waiterId":{"type":"string","nullable":true,"example":"uuid"},"guestCount":{"type":"number","example":4},"openedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.677Z"},"closedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"salesOrderId":{"type":"string","nullable":true,"example":"uuid"},"sessionState":{"type":"string","nullable":true,"enum":["SEATED","ORDERING","SERVED","PAYMENT_PENDING","CLOSED"],"example":"SEATED"},"posRegisterId":{"type":"string","nullable":true,"example":"uuid"},"openedByPosSessionId":{"type":"string","nullable":true,"example":"uuid"},"cashier":{"nullable":true,"description":"At checkout: who took the payment, to print as the cashier.","allOf":[{"$ref":"#/components/schemas/CashierDto"}]}},"required":["id","tenantId","tableId","guestCount","openedAt"]},"PickedRoomChargeDto":{"type":"object","properties":{"variantId":{"type":"string","format":"uuid","example":"uuid","description":"A charge for this place (GET /v1/products?placeId=<room or table>)."},"units":{"type":"number","minimum":1,"example":2,"description":"For a charge sold by time and paid first: how many units. Left out: enough for the booked time."}},"required":["variantId"]},"OpenTableSessionDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid","description":"Tenant ID"},"tableId":{"type":"string","format":"uuid","example":"uuid","description":"Dining table to seat at"},"locationId":{"type":"string","format":"uuid","example":"uuid","description":"Location for the underlying SalesOrder (typically the restaurant location)"},"guestCount":{"type":"number","minimum":1,"example":4},"waiterId":{"type":"string","format":"uuid","example":"uuid","description":"Assigned waiter"},"posRegisterId":{"type":"string","format":"uuid","example":"uuid","description":"POS terminal opening this session"},"openedByPosSessionId":{"type":"string","format":"uuid","example":"uuid","description":"Cashier shift (PosSession) under which this is opened"},"salesChannel":{"type":"string","example":"POS","description":"Sales channel for the underlying order (default: POS)"},"roomCharges":{"maxItems":20,"description":"Table charges the waiter picked (e.g. a pool table clock). Those set to add automatically (e.g. a service charge or VIP room fee) are added without being sent.","type":"array","items":{"$ref":"#/components/schemas/PickedRoomChargeDto"}}},"required":["tenantId","tableId","locationId","guestCount"]},"UpdateTableSessionDto":{"type":"object","properties":{"guestCount":{"type":"number","minimum":1,"example":4},"waiterId":{"type":"string","format":"uuid","example":"uuid"}}},"UpdateSessionStateDto":{"type":"object","properties":{"sessionState":{"type":"string","enum":["SEATED","ORDERING","SERVED","PAYMENT_PENDING","CLOSED"]}}},"TableSessionLineResultDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"salesOrderId":{"type":"string","example":"uuid"},"variantId":{"type":"string","example":"uuid"},"quantity":{"type":"string","example":"2.0000"},"unitPrice":{"type":"string","example":"5.0000"},"status":{"type":"string","nullable":true,"example":"PENDING"},"seatNumber":{"type":"number","nullable":true,"example":3}},"required":["id","salesOrderId","variantId","quantity","unitPrice"]},"AddSessionLineDto":{"type":"object","properties":{"variantId":{"type":"string","format":"uuid","example":"uuid","description":"Product variant to add"},"quantity":{"type":"number","minimum":0.0001,"example":1},"unitPrice":{"type":"number","minimum":0,"example":9.5,"description":"Unit price at time of order"},"lineDiscount":{"type":"number","minimum":0,"example":0},"taxRateId":{"type":"string","format":"uuid","example":"uuid","deprecated":true,"description":"Ignored: the server taxes the line from the product's taxes."},"taxAmount":{"type":"number","minimum":0,"example":0,"deprecated":true,"description":"Ignored: the server taxes the line from the product's taxes."},"courseType":{"type":"string","example":"STARTER","description":"Course type (STARTER, MAIN, DESSERT, etc.)"},"seatNumber":{"type":"number","minimum":1,"example":1,"description":"Seat number to allocate this line to"},"selectedModifiers":{"description":"Selected modifiers (JSON)","example":[{"modifierId":"uuid","name":"Extra cheese","priceDelta":1.5}],"type":"array","items":{"type":"object"}}},"required":["variantId","quantity","unitPrice"]},"TableChargeOfferDto":{"type":"object","properties":{"variantId":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Pool table"},"unitPrice":{"type":"string","example":"3000.0000"},"soldBy":{"type":"string","enum":["EACH","TIME"]},"timeBlockMinutes":{"type":"number","nullable":true,"example":30},"minimumBlocks":{"type":"number","nullable":true,"example":1},"chargeMode":{"type":"string","nullable":true,"enum":["PAY_FIRST","CLOCK"]},"autoApply":{"type":"boolean","example":false}},"required":["variantId","name","unitPrice","soldBy","autoApply"]},"RunningTableChargeDto":{"type":"object","properties":{"variantId":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Pool table"},"startedAt":{"format":"date-time","type":"string","example":"2026-10-07T12:00:00.000Z"}},"required":["variantId","name","startedAt"]},"TableChargesDto":{"type":"object","properties":{"offered":{"description":"The charges this table offers","type":"array","items":{"$ref":"#/components/schemas/TableChargeOfferDto"}},"running":{"description":"Clocks running on this bill","type":"array","items":{"$ref":"#/components/schemas/RunningTableChargeDto"}}},"required":["offered","running"]},"StopTableChargeDto":{"type":"object","properties":{"variantId":{"type":"string","format":"uuid","example":"uuid","description":"The charge whose clock to stop. Left out: every running clock."}}},"SessionSeatAllocationEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"sessionId":{"type":"string","example":"uuid"},"salesOrderLineId":{"type":"string","example":"uuid"},"seatNumber":{"type":"number","example":1}},"required":["id","sessionId","salesOrderLineId","seatNumber"]},"AllocateSeatDto":{"type":"object","properties":{"salesOrderLineId":{"type":"string","format":"uuid","example":"uuid","description":"Sales order line to allocate"},"seatNumber":{"type":"number","minimum":1,"example":1,"description":"Seat number within the session"}},"required":["salesOrderLineId","seatNumber"]},"CheckoutSessionDto":{"type":"object","properties":{"posSessionId":{"type":"string","format":"uuid","example":"uuid","description":"The shift taking the money - the cashier paying the bill. Left out: the shift that opened the table."},"payments":{"type":"array","items":{"$ref":"#/components/schemas/CheckoutPaymentDto"}},"tipAmount":{"type":"number","minimum":0,"example":5,"description":"Total tip amount"},"serviceCharge":{"type":"number","minimum":0,"example":2.5,"deprecated":true,"description":"Ignored: the server adds the shop's service charge. Kept so older tills still validate."},"discountReasonId":{"type":"string","format":"uuid","example":"uuid","description":"Discount reason if discount applied"},"totalDiscount":{"type":"number","minimum":0,"example":0,"description":"Order-level discount amount"}},"required":["payments"]},"KdsTicketEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"sessionId":{"type":"string","nullable":true,"example":"uuid","description":"Set for dine-in tickets"},"salesOrderId":{"type":"string","nullable":true,"example":"uuid","description":"Set for counter/QSR tickets (no table session)"},"stationId":{"type":"string","example":"uuid"},"ticketNumber":{"type":"string","example":"KDS-20260506-0001"},"courseType":{"type":"string","nullable":true,"example":"MAIN"},"firedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.655Z"},"startedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"bumpedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"status":{"type":"string","nullable":true,"enum":["PENDING","PREPARING","READY","EXPEDITED"],"example":"PENDING"},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.655Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.655Z"},"sentById":{"type":"string","nullable":true,"example":"uuid","description":"The staff user who sent the order to the kitchen."},"sentFrom":{"type":"string","nullable":true,"example":"STAFF","description":"STAFF from a till, TABLET from a room tablet."},"deviceName":{"type":"string","nullable":true,"example":"Room 3 tablet","description":"The tablet's name, when a room tablet sent it."}},"required":["id","tenantId","stationId","ticketNumber","firedAt","createdAt","updatedAt"]},"FireTicketsResultDto":{"type":"object","properties":{"tickets":{"type":"array","items":{"$ref":"#/components/schemas/KdsTicketEntity"}},"unroutedLineIds":{"example":["uuid"],"description":"Order lines that matched no station routing rule.","type":"array","items":{"type":"string"}}},"required":["tickets","unroutedLineIds"]},"FireTicketsDto":{"type":"object","properties":{"sessionId":{"type":"string","format":"uuid","example":"uuid","description":"Table session to fire (dine-in flow). Either sessionId or salesOrderId is required."},"salesOrderId":{"type":"string","format":"uuid","example":"uuid","description":"Sales order to fire (counter/QSR flow). Either sessionId or salesOrderId is required."}}},"KdsTicketStationDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Hot line"},"displayColor":{"type":"string","nullable":true,"example":"#FF5733"},"printerIds":{"example":["uuid-printer-1","uuid-led-1"],"description":"The printers at this station, in the order they were added.","type":"array","items":{"type":"string"}},"printerId":{"type":"string","nullable":true,"example":"uuid","deprecated":true,"description":"The first of printerIds, for clients that expect one."},"printers":{"description":"Every printer at the station, oldest first. A ticket goes to all of them.","type":"array","items":{"$ref":"#/components/schemas/StationPrinterDto"}},"printer":{"nullable":true,"deprecated":true,"description":"The first of printers, for clients that expect one.","allOf":[{"$ref":"#/components/schemas/StationPrinterDto"}]}},"required":["id","name","printerIds","printers"]},"TicketLineProductDto":{"type":"object","properties":{"categoryId":{"type":"string","nullable":true,"example":"uuid"},"name":{"type":"string","example":"Fried rice"}},"required":["name"]},"TicketLineVariantDto":{"type":"object","properties":{"product":{"$ref":"#/components/schemas/TicketLineProductDto"}},"required":["product"]},"TicketSalesOrderLineDto":{"type":"object","properties":{"variantId":{"type":"string","example":"uuid"},"variant":{"$ref":"#/components/schemas/TicketLineVariantDto"}},"required":["variantId","variant"]},"KdsTicketLineViewDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"ticketId":{"type":"string","example":"uuid"},"salesOrderLineId":{"type":"string","example":"uuid"},"productName":{"type":"string","example":"Cheeseburger"},"quantity":{"type":"string","example":"1.0000"},"seatNumber":{"type":"number","nullable":true,"example":1},"kitchenModifiers":{"type":"string","nullable":true,"example":"No onions"},"status":{"type":"string","nullable":true,"enum":["PENDING","PREPARING","READY"],"example":"PENDING"},"bumpedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.657Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.657Z"},"salesOrderLine":{"description":"The product the line was routed by. productName on the line is the name as printed; this is the live one.","allOf":[{"$ref":"#/components/schemas/TicketSalesOrderLineDto"}]}},"required":["id","ticketId","salesOrderLineId","productName","quantity","createdAt","updatedAt","salesOrderLine"]},"TicketTableDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tableNumber":{"type":"string","example":"T12"}},"required":["id","tableNumber"]},"TicketSessionDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"guestCount":{"type":"number","example":4},"table":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/TicketTableDto"}]}},"required":["id","guestCount"]},"TicketPlaceDto":{"type":"object","properties":{"kind":{"type":"string","enum":["TABLE","SPA_ROOM","KTV_ROOM","COUNTER"]},"number":{"type":"object","example":"T12","nullable":true,"description":"The table or room number. Null at the counter."},"name":{"type":"object","example":"VIP Suite","nullable":true,"description":"The room's name, when it has one."},"guestCount":{"type":"object","example":4,"nullable":true}},"required":["kind"]},"KdsTicketViewDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"sessionId":{"type":"string","nullable":true,"example":"uuid","description":"Set for dine-in tickets"},"salesOrderId":{"type":"string","nullable":true,"example":"uuid","description":"Set for counter/QSR tickets (no table session)"},"stationId":{"type":"string","example":"uuid"},"ticketNumber":{"type":"string","example":"KDS-20260506-0001"},"courseType":{"type":"string","nullable":true,"example":"MAIN"},"firedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.655Z"},"startedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"bumpedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"status":{"type":"string","nullable":true,"enum":["PENDING","PREPARING","READY","EXPEDITED"],"example":"PENDING"},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.655Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.655Z"},"sentById":{"type":"string","nullable":true,"example":"uuid","description":"The staff user who sent the order to the kitchen."},"sentFrom":{"type":"string","nullable":true,"example":"STAFF","description":"STAFF from a till, TABLET from a room tablet."},"deviceName":{"type":"string","nullable":true,"example":"Room 3 tablet","description":"The tablet's name, when a room tablet sent it."},"station":{"description":"The station the ticket was routed to, with its printers.","allOf":[{"$ref":"#/components/schemas/KdsTicketStationDto"}]},"kdsTicketLines":{"type":"array","items":{"$ref":"#/components/schemas/KdsTicketLineViewDto"}},"session":{"nullable":true,"description":"The table session, for dine-in tickets. Null at the counter.","allOf":[{"$ref":"#/components/schemas/TicketSessionDto"}]},"place":{"description":"Where the order is going: table, SPA room, KTV room or counter.","allOf":[{"$ref":"#/components/schemas/TicketPlaceDto"}]},"orderNumber":{"type":"string","nullable":true,"example":"SO-R01-20261008-0012"},"serviceType":{"type":"string","nullable":true,"enum":["DINE_IN","TAKEAWAY","DELIVERY","COUNTER"]},"posType":{"type":"string","nullable":true,"enum":["BAR","SPA","KTV"]},"pickupNumber":{"type":"string","nullable":true,"example":"A12"},"sentBy":{"nullable":true,"description":"The staff member who sent the order to the kitchen.","allOf":[{"$ref":"#/components/schemas/CashierDto"}]}},"required":["id","tenantId","stationId","ticketNumber","firedAt","createdAt","updatedAt","station","kdsTicketLines","place"]},"CloseOldTicketsDto":{"type":"object","properties":{"olderThanHours":{"type":"number","minimum":1,"maximum":2160,"example":12,"description":"Tickets sent to the kitchen longer ago than this are closed."}},"required":["olderThanHours"]},"KdsTicketLineEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"ticketId":{"type":"string","example":"uuid"},"salesOrderLineId":{"type":"string","example":"uuid"},"productName":{"type":"string","example":"Cheeseburger"},"quantity":{"type":"string","example":"1.0000"},"seatNumber":{"type":"number","nullable":true,"example":1},"kitchenModifiers":{"type":"string","nullable":true,"example":"No onions"},"status":{"type":"string","nullable":true,"enum":["PENDING","PREPARING","READY"],"example":"PENDING"},"bumpedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.657Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.657Z"}},"required":["id","ticketId","salesOrderLineId","productName","quantity","createdAt","updatedAt"]},"KdsStationEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"locationId":{"type":"string","nullable":true,"example":"uuid"},"name":{"type":"string","example":"Hot line"},"displayColor":{"type":"string","nullable":true,"example":"#FF5733"},"printerIds":{"example":["uuid-printer-1","uuid-led-1"],"description":"The printers at this station, in the order they were added.","type":"array","items":{"type":"string"}},"printerId":{"type":"string","nullable":true,"example":"uuid","deprecated":true,"description":"The first of printerIds, for clients that expect one."},"routingRules":{"type":"object","description":"Routing rules: { categoryIds: string[] }","example":{"categoryIds":["uuid-1","uuid-2"]}},"deletedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.694Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.694Z"}},"required":["id","tenantId","name","printerIds","routingRules","createdAt","updatedAt"]},"KdsRoutingRulesDto":{"type":"object","properties":{"categoryIds":{"example":["uuid-cat-1","uuid-cat-2"],"description":"Category IDs that route to this station","type":"array","items":{"type":"string","format":"uuid"}}}},"CreateKdsStationDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"locationId":{"type":"string","format":"uuid","example":"uuid"},"name":{"type":"string","example":"Hot line"},"displayColor":{"type":"string","example":"#FF5733"},"printerIds":{"uniqueItems":true,"example":["uuid-printer-1","uuid-led-1"],"description":"The printers standing at this station, e.g. two printers, or a printer and an LED board. Tickets grouped here go to all of them. Each must be in the KDS sector. Leave it out or send [] for a screen-only station.","type":"array","items":{"type":"string","format":"uuid"}},"printerId":{"type":"string","nullable":true,"format":"uuid","example":"uuid","deprecated":true,"description":"Older clients: a single printer. Ignored when printerIds is sent; null clears the station's printers."},"routingRules":{"$ref":"#/components/schemas/KdsRoutingRulesDto"}},"required":["tenantId","name"]},"UpdateKdsStationDto":{"type":"object","properties":{"locationId":{"type":"string","format":"uuid","example":"uuid"},"name":{"type":"string","example":"Hot line"},"displayColor":{"type":"string","example":"#FF5733"},"printerIds":{"uniqueItems":true,"example":["uuid-printer-1","uuid-led-1"],"description":"The printers standing at this station, e.g. two printers, or a printer and an LED board. Tickets grouped here go to all of them. Each must be in the KDS sector. Leave it out or send [] for a screen-only station.","type":"array","items":{"type":"string","format":"uuid"}},"printerId":{"type":"string","nullable":true,"format":"uuid","example":"uuid","deprecated":true,"description":"Older clients: a single printer. Ignored when printerIds is sent; null clears the station's printers."},"routingRules":{"$ref":"#/components/schemas/KdsRoutingRulesDto"}}},"ReservationEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"locationId":{"type":"string","example":"uuid"},"customerId":{"type":"string","nullable":true,"example":"uuid"},"guestName":{"type":"string","example":"Jane Doe"},"guestPhone":{"type":"string","nullable":true,"example":"+1-555-0100"},"guestEmail":{"type":"string","nullable":true,"example":"jane@example.com"},"partySize":{"type":"number","example":4},"reservedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.747Z"},"estimatedDurationMins":{"type":"number","example":90},"preferredZoneId":{"type":"string","nullable":true,"example":"uuid"},"assignedTableId":{"type":"string","nullable":true,"example":"uuid"},"tableSessionId":{"type":"string","nullable":true,"example":"uuid"},"specialRequests":{"type":"string","nullable":true,"example":"High chair needed"},"notes":{"type":"string","nullable":true,"example":null},"status":{"type":"string","nullable":true,"enum":["PENDING","CONFIRMED","SEATED","NO_SHOW","CANCELED","COMPLETED"],"example":"PENDING"},"seatedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"canceledAt":{"format":"date-time","type":"string","nullable":true,"example":null},"deletedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.748Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.748Z"}},"required":["id","tenantId","locationId","guestName","partySize","reservedAt","estimatedDurationMins","createdAt","updatedAt"]},"CreateReservationDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"locationId":{"type":"string","format":"uuid","example":"uuid"},"customerId":{"type":"string","format":"uuid","example":"uuid"},"guestName":{"type":"string","example":"Jane Doe"},"guestPhone":{"type":"string","example":"+1-555-0100"},"guestEmail":{"type":"string","format":"email","example":"jane@example.com"},"partySize":{"type":"number","minimum":1,"example":4},"reservedAt":{"type":"string","example":"2026-05-10T19:00:00Z"},"estimatedDurationMins":{"type":"number","minimum":15,"example":90,"description":"Default 90 minutes"},"preferredZoneId":{"type":"string","format":"uuid","example":"uuid"},"assignedTableId":{"type":"string","format":"uuid","example":"uuid"},"specialRequests":{"type":"string","example":"High chair, window seat"},"notes":{"type":"string","example":"Birthday celebration"}},"required":["tenantId","locationId","guestName","partySize","reservedAt"]},"UpdateReservationDto":{"type":"object","properties":{"locationId":{"type":"string","format":"uuid","example":"uuid"},"customerId":{"type":"string","format":"uuid","example":"uuid"},"guestName":{"type":"string","example":"Jane Doe"},"guestPhone":{"type":"string","example":"+1-555-0100"},"guestEmail":{"type":"string","format":"email","example":"jane@example.com"},"partySize":{"type":"number","minimum":1,"example":4},"reservedAt":{"type":"string","example":"2026-05-10T19:00:00Z"},"estimatedDurationMins":{"type":"number","minimum":15,"example":90,"description":"Default 90 minutes"},"preferredZoneId":{"type":"string","format":"uuid","example":"uuid"},"assignedTableId":{"type":"string","format":"uuid","example":"uuid"},"specialRequests":{"type":"string","example":"High chair, window seat"},"notes":{"type":"string","example":"Birthday celebration"}}},"ReservationConflictWarningDto":{"type":"object","properties":{"reservationId":{"type":"string","example":"uuid"},"guestName":{"type":"string","example":"Daw Hla"},"reservedAt":{"format":"date-time","type":"string","example":"2026-09-12T19:30:00.000Z"}},"required":["reservationId","guestName","reservedAt"]},"ConfirmReservationResultDto":{"type":"object","properties":{"reservation":{"$ref":"#/components/schemas/ReservationEntity"},"conflicts":{"description":"Empty when nothing else wants that table.","type":"array","items":{"$ref":"#/components/schemas/ReservationConflictWarningDto"}}},"required":["reservation","conflicts"]},"SeatReservationResultDto":{"type":"object","properties":{"reservation":{"$ref":"#/components/schemas/ReservationEntity"},"tableSession":{"$ref":"#/components/schemas/TableSessionEntity"}},"required":["reservation","tableSession"]},"SeatReservationDto":{"type":"object","properties":{"tableId":{"type":"string","format":"uuid","example":"uuid","description":"Table to seat the party at"},"waiterId":{"type":"string","format":"uuid","example":"uuid"},"guestCount":{"type":"number","minimum":1,"example":4,"description":"Override partySize on session (defaults to reservation party size)"},"posRegisterId":{"type":"string","format":"uuid","example":"uuid"},"openedByPosSessionId":{"type":"string","format":"uuid","example":"uuid"}},"required":["tableId"]},"WaitlistEntryEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"locationId":{"type":"string","example":"uuid"},"customerId":{"type":"string","nullable":true,"example":"uuid"},"guestName":{"type":"string","example":"John Smith"},"guestPhone":{"type":"string","nullable":true,"example":"+1-555-0100"},"partySize":{"type":"number","example":2},"joinedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.779Z"},"estimatedWaitMins":{"type":"number","nullable":true,"example":25},"preferredZoneId":{"type":"string","nullable":true,"example":"uuid"},"assignedTableId":{"type":"string","nullable":true,"example":"uuid"},"tableSessionId":{"type":"string","nullable":true,"example":"uuid"},"notifiedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"seatedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"canceledAt":{"format":"date-time","type":"string","nullable":true,"example":null},"notes":{"type":"string","nullable":true,"example":null},"status":{"type":"string","nullable":true,"enum":["WAITING","NOTIFIED","SEATED","CANCELED","NO_SHOW"],"example":"WAITING"},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.779Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.779Z"}},"required":["id","tenantId","locationId","guestName","partySize","joinedAt","createdAt","updatedAt"]},"CreateWaitlistEntryDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"locationId":{"type":"string","format":"uuid","example":"uuid"},"customerId":{"type":"string","format":"uuid","example":"uuid"},"guestName":{"type":"string","example":"John Smith"},"guestPhone":{"type":"string","example":"+1-555-0100"},"partySize":{"type":"number","minimum":1,"example":2},"estimatedWaitMins":{"type":"number","minimum":0,"example":25},"preferredZoneId":{"type":"string","format":"uuid","example":"uuid"},"notes":{"type":"string","example":"Window seat preferred"}},"required":["tenantId","locationId","guestName","partySize"]},"UpdateWaitlistEntryDto":{"type":"object","properties":{"locationId":{"type":"string","format":"uuid","example":"uuid"},"customerId":{"type":"string","format":"uuid","example":"uuid"},"guestName":{"type":"string","example":"John Smith"},"guestPhone":{"type":"string","example":"+1-555-0100"},"partySize":{"type":"number","minimum":1,"example":2},"estimatedWaitMins":{"type":"number","minimum":0,"example":25},"preferredZoneId":{"type":"string","format":"uuid","example":"uuid"},"notes":{"type":"string","example":"Window seat preferred"}}},"SeatWaitlistResultDto":{"type":"object","properties":{"entry":{"$ref":"#/components/schemas/WaitlistEntryEntity"},"tableSession":{"$ref":"#/components/schemas/TableSessionEntity"}},"required":["entry","tableSession"]},"SeatWaitlistDto":{"type":"object","properties":{"tableId":{"type":"string","format":"uuid","example":"uuid"},"waiterId":{"type":"string","format":"uuid","example":"uuid"},"guestCount":{"type":"number","minimum":1,"example":2},"posRegisterId":{"type":"string","format":"uuid","example":"uuid"},"openedByPosSessionId":{"type":"string","format":"uuid","example":"uuid"}},"required":["tableId"]},"TipPoolEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"locationId":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Friday Dinner Pool"},"periodStart":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.805Z"},"periodEnd":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.805Z"},"distributionMethod":{"type":"string","enum":["EQUAL","BY_HOURS","MANUAL"],"example":"BY_HOURS"},"totalTips":{"type":"string","example":"500.0000"},"totalServiceCharge":{"type":"string","example":"120.0000"},"includeServiceCharge":{"type":"boolean","example":false},"serviceChargeShareBps":{"type":"number","example":0},"totalDistributable":{"type":"string","example":"500.0000"},"status":{"type":"string","nullable":true,"enum":["OPEN","SETTLED"],"example":"OPEN"},"settledAt":{"format":"date-time","type":"string","nullable":true,"example":null},"settledBy":{"type":"string","nullable":true,"example":"uuid"},"notes":{"type":"string","nullable":true,"example":null},"deletedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.806Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.806Z"}},"required":["id","tenantId","locationId","name","periodStart","periodEnd","distributionMethod","totalTips","totalServiceCharge","includeServiceCharge","serviceChargeShareBps","totalDistributable","createdAt","updatedAt"]},"CreateTipPoolDto":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid","example":"uuid"},"locationId":{"type":"string","format":"uuid","example":"uuid"},"name":{"type":"string","example":"Friday Dinner Pool"},"periodStart":{"type":"string","example":"2026-05-06T17:00:00Z"},"periodEnd":{"type":"string","example":"2026-05-06T23:00:00Z"},"distributionMethod":{"type":"string","enum":["EQUAL","BY_HOURS","MANUAL"],"example":"BY_HOURS"},"includeServiceCharge":{"type":"boolean","example":false},"serviceChargeShareBps":{"type":"number","minimum":0,"maximum":10000,"example":5000,"description":"Basis points (5000 = 50%) of service charge that feeds the pool"},"notes":{"type":"string","example":"Closing manager: Alice"}},"required":["tenantId","locationId","name","periodStart","periodEnd","distributionMethod"]},"UpdateTipPoolDto":{"type":"object","properties":{"name":{"type":"string","example":"Friday Dinner Pool"},"periodStart":{"type":"string","example":"2026-05-06T17:00:00Z"},"periodEnd":{"type":"string","example":"2026-05-06T23:00:00Z"},"distributionMethod":{"type":"string","enum":["EQUAL","BY_HOURS","MANUAL"],"example":"BY_HOURS"},"includeServiceCharge":{"type":"boolean","example":false},"serviceChargeShareBps":{"type":"number","minimum":0,"maximum":10000,"example":5000,"description":"Basis points (5000 = 50%) of service charge that feeds the pool"},"notes":{"type":"string","example":"Closing manager: Alice"}}},"TipPoolAllocationEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"poolId":{"type":"string","example":"uuid"},"userId":{"type":"string","example":"uuid"},"role":{"type":"string","nullable":true,"example":"SERVER"},"hoursWorked":{"type":"string","nullable":true,"example":"8.00"},"weight":{"type":"string","example":"1.0000"},"amount":{"type":"string","example":"125.0000"},"notes":{"type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.808Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.809Z"}},"required":["id","poolId","userId","weight","amount","createdAt","updatedAt"]},"CreateAllocationDto":{"type":"object","properties":{"userId":{"type":"string","format":"uuid","example":"uuid"},"role":{"type":"string","example":"SERVER"},"hoursWorked":{"type":"number","minimum":0,"example":8},"weight":{"type":"number","minimum":0,"example":1},"amount":{"type":"number","minimum":0,"example":0,"description":"Manual amount (used when distributionMethod = MANUAL)"},"notes":{"type":"string","example":null}},"required":["userId"]},"UpdateAllocationDto":{"type":"object","properties":{"role":{"type":"string","example":"SERVER"},"hoursWorked":{"type":"number","minimum":0,"example":8},"weight":{"type":"number","minimum":0,"example":1},"amount":{"type":"number","minimum":0,"example":0},"notes":{"type":"string","example":null}}},"ShiftTemplateEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Evening"},"startTime":{"format":"date-time","type":"string","example":"1970-01-01T17:00:00.000Z","description":"Time of day only; the date part is not meaningful."},"endTime":{"format":"date-time","type":"string","example":"1970-01-01T02:00:00.000Z","description":"Time of day only. An end at or before the start means the shift runs past midnight."},"unpaidBreakMinutes":{"type":"number","example":30},"deletedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.841Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.841Z"}},"required":["id","tenantId","name","startTime","endTime","unpaidBreakMinutes","createdAt","updatedAt"]},"CreateShiftTemplateDto":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"example":"Evening"},"startTime":{"type":"string","example":"17:00","description":"24-hour HH:MM. An end at or before the start runs past midnight."},"endTime":{"type":"string","example":"02:00","description":"24-hour HH:MM."},"unpaidBreakMinutes":{"type":"number","minimum":0,"example":30,"default":0}},"required":["name","startTime","endTime"]},"UpdateShiftTemplateDto":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"example":"Evening"},"startTime":{"type":"string","example":"17:00"},"endTime":{"type":"string","example":"02:00"},"unpaidBreakMinutes":{"type":"number","minimum":0,"example":30}}},"ShiftRosterEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"locationId":{"type":"string","example":"uuid"},"userId":{"type":"string","example":"uuid"},"shiftTemplateId":{"type":"string","nullable":true,"example":"uuid"},"shiftDate":{"format":"date-time","type":"string","example":"2026-08-25"},"scheduledStart":{"format":"date-time","type":"string","example":"2026-08-25T17:00:00.000Z"},"scheduledEnd":{"format":"date-time","type":"string","example":"2026-08-26T02:00:00.000Z","description":"Absolute timestamp, so a shift past midnight needs no special case."},"status":{"type":"string","enum":["PUBLISHED","SWAP_REQUESTED","COMPLETED","ABSENT"],"example":"PUBLISHED"},"swapRequestedWithUserId":{"type":"string","nullable":true,"example":null},"swapApprovedBy":{"type":"string","nullable":true,"example":null},"notes":{"type":"string","nullable":true,"example":null},"deletedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.851Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.851Z"}},"required":["id","tenantId","locationId","userId","shiftDate","scheduledStart","scheduledEnd","status","createdAt","updatedAt"]},"CreateShiftRosterDto":{"type":"object","properties":{"locationId":{"type":"string","format":"uuid","example":"uuid"},"userId":{"type":"string","format":"uuid","example":"uuid"},"shiftDate":{"type":"string","example":"2026-08-25","description":"Calendar date, YYYY-MM-DD."},"shiftTemplateId":{"type":"string","format":"uuid","example":"uuid","description":"Take the times from this template. Omit only if supplying scheduledStart and scheduledEnd."},"scheduledStart":{"type":"string","example":"2026-08-25T17:00:00.000Z","description":"Overrides the template. Required when no template is given."},"scheduledEnd":{"type":"string","example":"2026-08-26T02:00:00.000Z"},"notes":{"type":"string","example":"Covering for Zaw"}},"required":["locationId","userId","shiftDate"]},"SkippedShiftDto":{"type":"object","properties":{"userId":{"type":"string","example":"uuid"},"shiftDate":{"type":"string","example":"2026-08-26"},"reason":{"type":"string","example":"already rostered on an overlapping shift"}},"required":["userId","shiftDate","reason"]},"ShiftRosterRunResultDto":{"type":"object","properties":{"created":{"type":"array","items":{"$ref":"#/components/schemas/ShiftRosterEntity"}},"skipped":{"description":"Days that were not rostered, and why.","type":"array","items":{"$ref":"#/components/schemas/SkippedShiftDto"}}},"required":["created","skipped"]},"CreateShiftRosterRunDto":{"type":"object","properties":{"locationId":{"type":"string","format":"uuid","example":"uuid"},"shiftTemplateId":{"type":"string","format":"uuid","example":"uuid"},"userIds":{"example":["uuid-a","uuid-b"],"type":"array","items":{"type":"string","format":"uuid"}},"fromDate":{"type":"string","example":"2026-08-25"},"toDate":{"type":"string","example":"2026-08-31"},"weekdays":{"example":[1,2,3,4,5],"description":"Days of the week to roster, 0 = Sunday. Omit to roster every day in the range.","type":"array","items":{"type":"number","maximum":6,"minimum":0}}},"required":["locationId","shiftTemplateId","userIds","fromDate","toDate"]},"UpdateShiftRosterDto":{"type":"object","properties":{"userId":{"type":"string","format":"uuid","example":"uuid"},"scheduledStart":{"type":"string","example":"2026-08-25T17:00:00.000Z"},"scheduledEnd":{"type":"string","example":"2026-08-26T02:00:00.000Z"},"status":{"type":"string","enum":["PUBLISHED","SWAP_REQUESTED","COMPLETED","ABSENT"]},"notes":{"type":"string","example":"Called in sick"}}},"RequestShiftSwapDto":{"type":"object","properties":{"swapWithUserId":{"type":"string","format":"uuid","example":"uuid","description":"The colleague asked to take the shift."}},"required":["swapWithUserId"]},"TimesheetEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"userId":{"type":"string","example":"uuid"},"shiftRosterId":{"type":"string","nullable":true,"example":"uuid"},"workDate":{"format":"date-time","type":"string","example":"2026-08-25"},"actualStart":{"format":"date-time","type":"string","nullable":true,"example":"2026-08-25T17:04:00.000Z"},"actualEnd":{"format":"date-time","type":"string","nullable":true,"example":null,"description":"Null while the shift is still in progress."},"totalWorkedMinutes":{"type":"number","example":540,"description":"Excludes the unpaid break."},"lateMinutes":{"type":"number","example":4},"overtimeMinutes":{"type":"number","example":30},"status":{"type":"string","enum":["PENDING_APPROVAL","APPROVED","REJECTED"],"example":"PENDING_APPROVAL"},"approvedBy":{"type":"string","nullable":true,"example":null},"notes":{"type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.866Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.866Z"}},"required":["id","tenantId","userId","workDate","totalWorkedMinutes","lateMinutes","overtimeMinutes","status","createdAt","updatedAt"]},"ClockInDto":{"type":"object","properties":{"shiftRosterId":{"type":"string","format":"uuid","example":"uuid","description":"The rostered shift being started. Omit for unscheduled work; lateness is then zero."},"userId":{"type":"string","format":"uuid","example":"uuid","description":"Whose attendance this is. Defaults to the caller."},"at":{"type":"string","example":"2026-08-25T17:04:00.000Z","description":"Defaults to now. Supply to record a punch after the fact."}}},"ClockOutDto":{"type":"object","properties":{"at":{"type":"string","example":"2026-08-26T02:30:00.000Z","description":"Defaults to now."},"notes":{"type":"string","example":"Stayed to close the till"}}},"WorkedHoursDto":{"type":"object","properties":{"userId":{"type":"string","example":"uuid"},"totalWorkedMinutes":{"type":"number","example":2460},"hours":{"type":"number","example":41}},"required":["userId","totalWorkedMinutes","hours"]},"DecideTimesheetDto":{"type":"object","properties":{"status":{"type":"string","enum":["APPROVED","REJECTED"],"example":"APPROVED","description":"Only approved hours count towards tip distribution by hours."}},"required":["status"]},"KtvRoomEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"locationId":{"type":"string","example":"uuid"},"roomNumber":{"type":"string","example":"A1"},"name":{"type":"string","nullable":true,"example":"Grand Room"},"capacity":{"type":"number","example":12},"rateVariantId":{"type":"string","example":"uuid","description":"The variant whose price is the hourly rate. Billing emits ordinary order lines against it, so tax, discounts and reporting need no knowledge of rooms."},"minimumMinutes":{"type":"number","example":60},"incrementMinutes":{"type":"number","example":30},"graceMinutes":{"type":"number","example":5,"description":"Minutes past a block boundary that are not charged for."},"roundingMode":{"type":"string","enum":["UP","NEAREST","DOWN"],"example":"UP"},"status":{"type":"string","enum":["AVAILABLE","OCCUPIED","CLEANING","OUT_OF_SERVICE"],"example":"AVAILABLE"},"deletedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-09-12T20:00:00.000Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-09-12T20:00:00.000Z"},"sessionPrice":{"type":"string","example":"30000","description":"Price of one hour (standard rate; peak-hour prices may apply on top). Returned by list, get, create and update."}},"required":["id","tenantId","locationId","roomNumber","capacity","rateVariantId","minimumMinutes","incrementMinutes","graceMinutes","roundingMode","status","createdAt","updatedAt"]},"CreateKtvRoomDto":{"type":"object","properties":{"locationId":{"type":"string","format":"uuid","example":"uuid","description":"The outlet the room belongs to."},"roomNumber":{"type":"string","maxLength":50,"example":"A1"},"name":{"type":"string","maxLength":100,"example":"Grand Room"},"capacity":{"type":"number","minimum":1,"example":12},"rateVariantId":{"type":"string","format":"uuid","example":"uuid","description":"Variant whose price is the hourly rate. Must be a SERVICE product - a stocked one would have its stock checked, and there are no hours in stock. Give this or sessionPrice."},"sessionPrice":{"type":"number","minimum":0,"example":30000,"description":"Price of one hour, as a plain number. The room then bills against a product of its own that this price keeps up to date; rateVariantId is not needed. Peak-hour prices set on that product still apply."},"minimumMinutes":{"type":"number","minimum":0,"example":60,"description":"Shortest let that can be charged."},"incrementMinutes":{"type":"number","minimum":1,"example":30,"description":"Time is sold in blocks of this size beyond the minimum."},"graceMinutes":{"type":"number","minimum":0,"example":5,"description":"Minutes past a block boundary that are forgiven. Must be shorter than the increment, or no overrun is ever chargeable."},"roundingMode":{"type":"string","enum":["UP","NEAREST","DOWN"],"default":"UP"}},"required":["locationId","roomNumber","capacity"]},"KtvBoardSessionDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"openedAt":{"format":"date-time","type":"string","example":"2026-09-12T20:05:00.000Z","description":"What the \"in for 1h 20m\" figure is measured from."},"guestCount":{"type":"number","example":5},"sessionState":{"type":"string","enum":["OPEN","PAUSED","PAYMENT_PENDING","CLOSED"],"example":"OPEN"},"guestWalletId":{"type":"string","nullable":true,"example":"uuid","description":"The wallet the party is drawing on, if they are using cards."},"salesOrderId":{"type":"string","nullable":true,"example":"uuid","description":"The bill this session is building. Add items with POST /v1/sales-orders/{salesOrderId}/lines and pay with /v1/sales-orders/{salesOrderId}/settle."},"plannedMinutes":{"type":"number","nullable":true,"example":180,"description":"How long the party asked for, in minutes. Null when nobody was asked."},"endsAt":{"format":"date-time","type":"string","nullable":true,"example":"2026-09-12T23:05:00.000Z","description":"When the time the party asked for runs out, or null if they did not say. Paused minutes push it back, so a room stopped for twenty minutes gets those twenty minutes back rather than losing them off the end."}},"required":["id","openedAt","guestCount","sessionState"]},"KtvRoomBoardDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"locationId":{"type":"string","example":"uuid"},"roomNumber":{"type":"string","example":"A1"},"name":{"type":"string","nullable":true,"example":"Grand Room"},"capacity":{"type":"number","example":12},"rateVariantId":{"type":"string","example":"uuid","description":"The variant whose price is the hourly rate. Billing emits ordinary order lines against it, so tax, discounts and reporting need no knowledge of rooms."},"minimumMinutes":{"type":"number","example":60},"incrementMinutes":{"type":"number","example":30},"graceMinutes":{"type":"number","example":5,"description":"Minutes past a block boundary that are not charged for."},"roundingMode":{"type":"string","enum":["UP","NEAREST","DOWN"],"example":"UP"},"status":{"type":"string","enum":["AVAILABLE","OCCUPIED","CLEANING","OUT_OF_SERVICE"],"example":"AVAILABLE"},"deletedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-09-12T20:00:00.000Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-09-12T20:00:00.000Z"},"sessionPrice":{"type":"string","example":"30000.0000","description":"Price of one hour, before any peak-hour price."},"sessions":{"description":"Empty for a room that is free or being cleaned. At most one entry in practice: a room holds one live let at a time.","type":"array","items":{"$ref":"#/components/schemas/KtvBoardSessionDto"}},"priceNow":{"type":"string","example":"35000.0000","description":"Price of an hour bought now: the peak price in peak hours."},"rateLabel":{"type":"string","example":"Peak","description":"The rate window in force now."},"rateProductId":{"type":"string","example":"uuid","description":"The product the room bills against, so a menu can leave it out."}},"required":["id","tenantId","locationId","roomNumber","capacity","rateVariantId","minimumMinutes","incrementMinutes","graceMinutes","roundingMode","status","createdAt","updatedAt","sessions","priceNow","rateLabel","rateProductId"]},"UpdateKtvRoomDto":{"type":"object","properties":{"locationId":{"type":"string","format":"uuid","example":"uuid"},"roomNumber":{"type":"string","maxLength":50,"example":"A1"},"name":{"type":"string","maxLength":100,"example":"Grand Room"},"capacity":{"type":"number","minimum":1,"example":12},"rateVariantId":{"type":"string","format":"uuid","example":"uuid"},"sessionPrice":{"type":"number","minimum":0,"example":30000,"description":"Price of one hour, as a plain number. The room then bills against a product of its own that this price keeps up to date; rateVariantId is not needed. Peak-hour prices set on that product still apply."},"minimumMinutes":{"type":"number","minimum":0,"example":60},"incrementMinutes":{"type":"number","minimum":1,"example":30},"graceMinutes":{"type":"number","minimum":0,"example":5},"roundingMode":{"type":"string","enum":["UP","NEAREST","DOWN"]},"status":{"type":"string","enum":["AVAILABLE","OCCUPIED","CLEANING","OUT_OF_SERVICE"],"description":"Use CLEANING and OUT_OF_SERVICE here; OCCUPIED is set by a let."}}},"KtvRoomSessionEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"roomId":{"type":"string","example":"uuid"},"guestWalletId":{"type":"string","nullable":true,"example":"uuid","description":"The wallet the party is drawing on, if they are using cards."},"hostUserId":{"type":"string","nullable":true,"example":"uuid"},"guestCount":{"type":"number","example":5},"openedAt":{"format":"date-time","type":"string","example":"2026-09-12T20:05:00.000Z"},"closedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"pausedMinutes":{"type":"number","example":0,"description":"Minutes the clock was stopped, deducted from the bill."},"pausedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"plannedMinutes":{"type":"number","nullable":true,"example":180,"description":"How long the party said they wanted, in minutes. Informational: the bill is still metered off the clock, so leaving early costs less and staying late costs more. Null on sessions opened before anyone was asked."},"salesOrderId":{"type":"string","nullable":true,"example":"uuid"},"sessionState":{"type":"string","enum":["OPEN","PAUSED","PAYMENT_PENDING","CLOSED"],"example":"OPEN"},"posRegisterId":{"type":"string","nullable":true,"example":"uuid"},"openedByPosSessionId":{"type":"string","nullable":true,"example":"uuid"},"minimumMinutesSnapshot":{"type":"number","example":60},"incrementMinutesSnapshot":{"type":"number","example":30},"graceMinutesSnapshot":{"type":"number","example":5},"roundingModeSnapshot":{"type":"string","enum":["UP","NEAREST","DOWN"]},"paymentTiming":{"type":"string","nullable":true,"enum":["PAY_WHEN_ORDERING","PAY_AT_END"],"description":"How this was paid, from Venue setup when it started: PAY_WHEN_ORDERING (each order by card) or PAY_AT_END (one bill, paid after close). Null on older sessions."},"createdAt":{"format":"date-time","type":"string","example":"2026-09-12T20:05:00.000Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-09-12T20:05:00.000Z"}},"required":["id","tenantId","roomId","guestCount","openedAt","pausedMinutes","sessionState","minimumMinutesSnapshot","incrementMinutesSnapshot","graceMinutesSnapshot","roundingModeSnapshot","createdAt","updatedAt"]},"RoomCardChargeDto":{"type":"object","properties":{"guestCardId":{"type":"string","format":"uuid","example":"uuid","description":"The card that was tapped. Left out to pay by cash or another way the venue takes, when rooms are not member card only."},"paymentMethodId":{"type":"string","format":"uuid","example":"uuid","description":"The guest-card payment method, or cash and the like."},"posSessionId":{"type":"string","format":"uuid","example":"uuid","description":"The till shift taking it."},"idempotencyKey":{"type":"string","maxLength":100,"example":"ktv-charge-7c1…","description":"One per tap, so a retry after a lost response charges once."}},"required":["paymentMethodId"]},"RoomChargeItemDto":{"type":"object","properties":{"variantId":{"type":"string","format":"uuid","example":"uuid"},"quantity":{"type":"number","minimum":1,"example":2},"hostessId":{"type":"string","format":"uuid","example":"uuid","description":"Who gave it: required for a service that asks who served (a hostess), refused for anything else. GET /v1/hostesses?activeOnly=true."}},"required":["variantId","quantity"]},"OpenKtvSessionDto":{"type":"object","properties":{"roomId":{"type":"string","format":"uuid","example":"uuid"},"guestCount":{"type":"number","minimum":1,"example":5,"description":"Defaults to 1."},"guestWalletId":{"type":"string","format":"uuid","example":"uuid","description":"The wallet the party will pay from. Several cards may draw on it, which is the usual arrangement for a room."},"hostUserId":{"type":"string","format":"uuid","example":"uuid","description":"Staff member hosting."},"plannedMinutes":{"type":"number","minimum":1,"example":180,"description":"How long the party asked for, in minutes. Informational only - the bill is metered off the clock, so this never changes what they are charged. It is what the board counts down to, and what tells the desk when to go and ask."},"posRegisterId":{"type":"string","format":"uuid","example":"uuid"},"openedByPosSessionId":{"type":"string","format":"uuid","example":"uuid"},"salesChannel":{"type":"string","example":"POS"},"prepay":{"description":"Pay for the booked hours now, from the tapped card, at the rate that applies now. The room is then paid as it goes: more hours and food are charged when ordered, and closing it charges nothing more. Needs `hours`. Required when the venue takes payment when ordering; refused when it takes payment at the end (then `hours` and `items` go on the bill).","allOf":[{"$ref":"#/components/schemas/RoomCardChargeDto"}]},"rentalVariantId":{"type":"string","format":"uuid","example":"uuid","description":"The rental to sell: a RENTAL product for KTV rooms that this room may use (GET /v1/products?placeId=<roomId>). Left out: the room’s own rate."},"hours":{"type":"number","minimum":1,"example":2,"description":"Units booked of the rental (hours for an hourly one): paid now with `prepay`, or put on the bill when the venue takes payment at the end."},"items":{"maxItems":50,"description":"Food and drink ordered with the room: paid by the same tap, or put on the bill when the venue takes payment at the end.","type":"array","items":{"$ref":"#/components/schemas/RoomChargeItemDto"}}},"required":["roomId"]},"QuotedSegmentDto":{"type":"object","properties":{"label":{"type":"string","example":"Peak"},"from":{"format":"date-time","type":"string","example":"2026-09-12T22:00:00.000Z"},"to":{"format":"date-time","type":"string","example":"2026-09-13T01:00:00.000Z"},"minutes":{"type":"number","example":180,"description":"Wall-clock minutes in this window."},"billableMinutes":{"type":"number","example":180,"description":"Minutes actually charged for."},"hours":{"type":"string","example":"3.0000"},"rate":{"type":"string","example":"30000.0000"},"amount":{"type":"string","example":"90000.0000"}},"required":["label","from","to","minutes","billableMinutes","hours","rate","amount"]},"KtvSessionQuoteDto":{"type":"object","properties":{"sessionId":{"type":"string","example":"uuid"},"roomId":{"type":"string","example":"uuid"},"roomNumber":{"type":"string","example":"A1"},"state":{"type":"string","enum":["OPEN","PAUSED","PAYMENT_PENDING","CLOSED"]},"openedAt":{"format":"date-time","type":"string","example":"2026-09-12T20:05:00.000Z"},"asOf":{"format":"date-time","type":"string","example":"2026-09-13T01:00:00.000Z"},"elapsedMinutes":{"type":"number","example":295},"pausedMinutes":{"type":"number","example":0},"segments":{"description":"One entry per rate window, so a receipt shows both rates rather than an average the guest cannot check.","type":"array","items":{"$ref":"#/components/schemas/QuotedSegmentDto"}},"roomCharge":{"type":"string","example":"130000.0000"},"fnbCharge":{"type":"string","example":"15000.0000"},"runningTotal":{"type":"string","example":"145000.0000"},"prepaid":{"type":"boolean","example":true,"description":"Paid as it goes: every hour and item was charged to a card when bought, so closing the room charges nothing more."},"paidTotal":{"type":"string","example":"145000.0000","description":"What the cards have paid on this bill, net of refunds."},"paymentTiming":{"type":"string","nullable":true,"enum":["PAY_WHEN_ORDERING","PAY_AT_END"]},"salesOrderId":{"type":"string","nullable":true,"example":"uuid"},"amountDue":{"type":"string","example":"145000.0000","description":"Still to pay. With PAY_AT_END, settle it after close with POST /v1/sales-orders/{salesOrderId}/settle; a member card paying gets its tier discount off this. Zero once paid."},"cashier":{"nullable":true,"description":"Who took the latest payment on the bill, to print as the cashier.","allOf":[{"$ref":"#/components/schemas/CashierDto"}]},"orderNumber":{"type":"string","nullable":true,"example":"SO-R01-20261008-0012","description":"The bill’s order number, printed as the receipt number."}},"required":["sessionId","roomId","roomNumber","state","openedAt","asOf","elapsedMinutes","pausedMinutes","segments","roomCharge","fnbCharge","runningTotal","paymentTiming","salesOrderId","amountDue"]},"KtvChargeResultDto":{"type":"object","properties":{"charged":{"type":"string","example":"42500.0000","description":"Taken from the card now. Zero when the venue takes payment at the end."},"addedToBill":{"type":"string","example":"42500.0000","description":"Put on the bill to pay at the end (PAY_AT_END)."},"balanceAfter":{"type":"string","example":"57500.0000","description":"The card balance after this charge or refund."},"quote":{"$ref":"#/components/schemas/KtvSessionQuoteDto"}},"required":["charged","balanceAfter","quote"]},"ExtendKtvSessionDto":{"type":"object","properties":{"guestCardId":{"type":"string","format":"uuid","example":"uuid","description":"The card that was tapped. Required when the venue takes payment when ordering."},"paymentMethodId":{"type":"string","format":"uuid","example":"uuid","description":"The guest-card payment method, or cash and the like with no card. Required when the venue takes payment when ordering."},"posSessionId":{"type":"string","format":"uuid","example":"uuid","description":"The till shift taking it."},"idempotencyKey":{"type":"string","maxLength":100,"example":"room-order-7c1…","description":"One per order sent, so a retry after a lost response charges or adds it once."},"hours":{"type":"number","minimum":1,"example":1,"description":"Units added of the rental (hours for an hourly one) at the rate that applies now: paid now, or put on the bill when the venue takes payment at the end."},"rentalVariantId":{"type":"string","format":"uuid","example":"uuid","description":"The rental to sell: a RENTAL product for KTV rooms that this room may use (GET /v1/products?placeId=<roomId>). Left out: the rental the room is already on."}},"required":["hours"]},"RoomChargeItemsDto":{"type":"object","properties":{"guestCardId":{"type":"string","format":"uuid","example":"uuid","description":"The card that was tapped. Required when the venue takes payment when ordering."},"paymentMethodId":{"type":"string","format":"uuid","example":"uuid","description":"The guest-card payment method, or cash and the like with no card. Required when the venue takes payment when ordering."},"posSessionId":{"type":"string","format":"uuid","example":"uuid","description":"The till shift taking it."},"idempotencyKey":{"type":"string","maxLength":100,"example":"room-order-7c1…","description":"One per order sent, so a retry after a lost response charges or adds it once."},"items":{"minItems":1,"maxItems":50,"description":"Priced on the server, from the catalogue; the till sends no prices.","type":"array","items":{"$ref":"#/components/schemas/RoomChargeItemDto"}}},"required":["items"]},"RoomGiveFreeDto":{"type":"object","properties":{"items":{"minItems":1,"maxItems":50,"description":"What the house gives. Nothing is charged to any card.","type":"array","items":{"$ref":"#/components/schemas/RoomChargeItemDto"}},"compReasonId":{"type":"string","format":"uuid","example":"uuid","description":"Why it is free: a saved discount reason. Give this or reason."},"reason":{"type":"string","maxLength":100,"example":"Birthday","description":"Why it is free, as typed. Matched to a discount reason of the same name, or saved as a new one so reports can group by it."}},"required":["items"]},"RoomFreeHoursDto":{"type":"object","properties":{"hours":{"type":"number","minimum":1,"example":1,"description":"Hours given on the house, at the rate that applies now."},"compReasonId":{"type":"string","format":"uuid","example":"uuid","description":"Why it is free: a saved discount reason. Give this or reason."},"reason":{"type":"string","maxLength":100,"example":"Ran over, on the house","description":"Why it is free, as typed. Matched to a discount reason of the same name, or saved as a new one."}},"required":["hours"]},"RoomRefundLineDto":{"type":"object","properties":{"reason":{"type":"string","maxLength":200,"example":"Wrong item tapped"}}},"SetPlannedMinutesDto":{"type":"object","properties":{"plannedMinutes":{"type":"number","nullable":true,"minimum":1,"example":240,"description":"The new planned length in minutes, measured from when the room opened - not an amount to add. Null clears it and the board stops counting down."}},"required":["plannedMinutes"]},"RoomTipDto":{"type":"object","properties":{"guestCardId":{"type":"string","format":"uuid","example":"uuid","description":"The card that was tapped. Left out to pay by cash or another way the venue takes, when rooms are not member card only."},"paymentMethodId":{"type":"string","format":"uuid","example":"uuid","description":"The guest-card payment method, or cash and the like."},"posSessionId":{"type":"string","format":"uuid","example":"uuid","description":"The till shift taking it."},"idempotencyKey":{"type":"string","maxLength":100,"example":"ktv-charge-7c1…","description":"One per tap, so a retry after a lost response charges once."},"amount":{"type":"string","example":"5000.0000"}},"required":["paymentMethodId","amount"]},"CloseKtvSessionDto":{"type":"object","properties":{"closedAt":{"type":"string","example":"2026-09-13T01:00:00.000Z","description":"Defaults to now. Cannot be before the room was taken."},"tip":{"description":"A tip, when the room was paid as it went: charged now and added to the bill. A bill paid at the end takes its tip when it is settled.","allOf":[{"$ref":"#/components/schemas/RoomTipDto"}]}}},"HostessWhereaboutsDto":{"type":"object","properties":{"roomId":{"type":"string","example":"uuid"},"roomNumber":{"type":"string","example":"K3"},"sessionId":{"type":"string","example":"uuid"},"since":{"format":"date-time","type":"string","example":"2026-10-06T14:00:00.000Z"},"until":{"format":"date-time","type":"string","nullable":true,"example":"2026-10-06T16:00:00.000Z","description":"When her paid time ends; null for a service sold each."}},"required":["roomId","roomNumber","sessionId","since"]},"HostessEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Ma Hnin"},"nickname":{"type":"string","nullable":true,"example":"Snow"},"phoneNumber":{"type":"string","nullable":true,"example":"09-123456789"},"imageUrl":{"type":"string","nullable":true},"isActive":{"type":"boolean","example":true},"inRoom":{"nullable":true,"description":"The KTV room she is in now: a room still open with her on its bill, and her paid time not yet over. Shown, not enforced - she can still be picked.","allOf":[{"$ref":"#/components/schemas/HostessWhereaboutsDto"}]},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","tenantId","name","isActive","createdAt","updatedAt"]},"CreateHostessDto":{"type":"object","properties":{"name":{"type":"string","maxLength":100,"example":"Ma Hnin"},"nickname":{"type":"string","maxLength":100,"example":"Snow","description":"What guests call her."},"phoneNumber":{"type":"string","maxLength":50,"example":"09-123456789"},"imageUrl":{"type":"string","maxLength":500,"example":"/uploads/hostesses/snow.jpg"},"isActive":{"type":"boolean","example":true,"description":"Off: kept for past bills, not offered at the till."}},"required":["name"]},"UpdateHostessDto":{"type":"object","properties":{"name":{"type":"string","maxLength":100,"example":"Ma Hnin"},"nickname":{"type":"string","maxLength":100,"example":"Snow","description":"What guests call her."},"phoneNumber":{"type":"string","maxLength":50,"example":"09-123456789"},"imageUrl":{"type":"string","maxLength":500,"example":"/uploads/hostesses/snow.jpg"},"isActive":{"type":"boolean","example":true,"description":"Off: kept for past bills, not offered at the till."}}},"CountAmountDto":{"type":"object","properties":{"count":{"type":"number","example":3},"amount":{"type":"string","example":"45000.0000"}},"required":["count","amount"]},"SummaryOrdersDto":{"type":"object","properties":{"count":{"type":"number","example":120,"description":"Orders sold, refunded ones included"},"averageNetSales":{"type":"string","example":"38500.0000"},"averageGrandTotal":{"type":"string","example":"42350.0000"},"voided":{"$ref":"#/components/schemas/CountAmountDto"}},"required":["count","averageNetSales","averageGrandTotal","voided"]},"SummarySalesDto":{"type":"object","properties":{"grossSales":{"type":"string","example":"4800000.0000","description":"Quantity x price"},"lineDiscounts":{"type":"string","example":"120000.0000"},"orderDiscounts":{"type":"string","example":"60000.0000","description":"Discounts on the whole bill"},"totalDiscounts":{"type":"string","example":"180000.0000"},"netSales":{"type":"string","example":"4620000.0000","description":"After discounts, before tax"},"serviceCharge":{"type":"string","example":"231000.0000"},"tax":{"type":"string","example":"231000.0000"},"tips":{"type":"string","example":"12000.0000"},"grandTotal":{"type":"string","example":"5094000.0000"}},"required":["grossSales","lineDiscounts","orderDiscounts","totalDiscounts","netSales","serviceCharge","tax","tips","grandTotal"]},"RefundMethodRowDto":{"type":"object","properties":{"refundMethod":{"type":"string","example":"CASH"},"count":{"type":"number","example":2},"amount":{"type":"string","example":"15000.0000"}},"required":["refundMethod","count","amount"]},"SummaryRefundsDto":{"type":"object","properties":{"count":{"type":"number","example":2},"subtotal":{"type":"string","example":"14285.7143"},"tax":{"type":"string","example":"714.2857"},"total":{"type":"string","example":"15000.0000"},"byMethod":{"type":"array","items":{"$ref":"#/components/schemas/RefundMethodRowDto"}}},"required":["count","subtotal","tax","total","byMethod"]},"PaymentMethodRowDto":{"type":"object","properties":{"paymentMethodId":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Cash"},"kind":{"type":"string","example":"CASH"},"count":{"type":"number","example":80},"amount":{"type":"string","example":"3200000.0000"}},"required":["paymentMethodId","name","kind","count","amount"]},"SummaryPaymentsDto":{"type":"object","properties":{"byMethod":{"type":"array","items":{"$ref":"#/components/schemas/PaymentMethodRowDto"}},"tendered":{"type":"string","example":"5140000.0000","description":"Everything handed over"},"changeGiven":{"type":"string","example":"46000.0000","description":"Handed back as change. Tendered less change is the grand total."}},"required":["byMethod","tendered","changeGiven"]},"SummaryDayRowDto":{"type":"object","properties":{"businessDate":{"type":"string","example":"2026-09-13"},"orderCount":{"type":"number","example":14},"netSales":{"type":"string","example":"540000.0000"},"grandTotal":{"type":"string","example":"594000.0000"},"refunds":{"type":"string","example":"0.0000","description":"Refunds made that day"}},"required":["businessDate","orderCount","netSales","grandTotal","refunds"]},"SummaryHourRowDto":{"type":"object","properties":{"hour":{"type":"number","example":21,"description":"Local hour, 0-23, of the payment"},"orderCount":{"type":"number","example":9},"netSales":{"type":"string","example":"310000.0000"},"grandTotal":{"type":"string","example":"341000.0000"}},"required":["hour","orderCount","netSales","grandTotal"]},"SummaryOutletRowDto":{"type":"object","properties":{"locationId":{"type":"string","nullable":true,"example":"uuid"},"locationName":{"type":"string","example":"KTV"},"orderCount":{"type":"number","example":40},"netSales":{"type":"string","example":"1800000.0000"},"grandTotal":{"type":"string","example":"1980000.0000"}},"required":["locationId","locationName","orderCount","netSales","grandTotal"]},"SummaryServiceTypeRowDto":{"type":"object","properties":{"serviceType":{"type":"string","example":"DINE_IN"},"orderCount":{"type":"number","example":60},"netSales":{"type":"string","example":"2400000.0000"},"grandTotal":{"type":"string","example":"2640000.0000"}},"required":["serviceType","orderCount","netSales","grandTotal"]},"SalesSummaryReportDto":{"type":"object","properties":{"from":{"type":"string","example":"2026-09-01"},"to":{"type":"string","example":"2026-09-14"},"locationIds":{"nullable":true,"description":"Outlets covered; null means every outlet you can see.","type":"array","items":{"type":"string"}},"posType":{"type":"string","nullable":true,"enum":["BAR","SPA","KTV"],"description":"The POS the report covers; null for every POS."},"orders":{"$ref":"#/components/schemas/SummaryOrdersDto"},"sales":{"$ref":"#/components/schemas/SummarySalesDto"},"refunds":{"$ref":"#/components/schemas/SummaryRefundsDto"},"netAfterRefunds":{"type":"string","example":"5079000.0000","description":"Grand total less refunds"},"voidedLines":{"description":"Lines voided on sold bills","allOf":[{"$ref":"#/components/schemas/CountAmountDto"}]},"compedLines":{"description":"Lines given away","allOf":[{"$ref":"#/components/schemas/CountAmountDto"}]},"payments":{"$ref":"#/components/schemas/SummaryPaymentsDto"},"byDay":{"type":"array","items":{"$ref":"#/components/schemas/SummaryDayRowDto"}},"byHour":{"type":"array","items":{"$ref":"#/components/schemas/SummaryHourRowDto"}},"byOutlet":{"type":"array","items":{"$ref":"#/components/schemas/SummaryOutletRowDto"}},"byServiceType":{"type":"array","items":{"$ref":"#/components/schemas/SummaryServiceTypeRowDto"}}},"required":["from","to","locationIds","orders","sales","refunds","netAfterRefunds","voidedLines","compedLines","payments","byDay","byHour","byOutlet","byServiceType"]},"BillTotalsDto":{"type":"object","properties":{"billCount":{"type":"number","example":42},"grossSales":{"type":"string","example":"2100000.0000"},"discounts":{"type":"string","example":"35000.0000"},"netSales":{"type":"string","example":"2065000.0000"},"tax":{"type":"string","example":"0.0000"},"grandTotal":{"type":"string","example":"2065000.0000"}},"required":["billCount","grossSales","discounts","netSales","tax","grandTotal"]},"BillItemDto":{"type":"object","properties":{"name":{"type":"string","example":"Thai massage 90 min"},"quantity":{"type":"string","example":"1.0000"},"netSales":{"type":"string","example":"45000.0000"}},"required":["name","quantity","netSales"]},"BillCompedItemDto":{"type":"object","properties":{"name":{"type":"string","example":"Orange juice"},"quantity":{"type":"string","example":"1.0000"},"value":{"type":"string","example":"6000.0000","description":"What it would have sold for"}},"required":["name","quantity","value"]},"NameAmountDto":{"type":"object","properties":{"name":{"type":"string","example":"Member card"},"amount":{"type":"string","example":"51000.0000"}},"required":["name","amount"]},"BillRowDto":{"type":"object","properties":{"orderId":{"type":"string","example":"uuid"},"orderNumber":{"type":"string","example":"SO-S01-20261004-0007"},"businessDate":{"type":"string","example":"2026-10-04"},"soldAt":{"format":"date-time","type":"string","example":"2026-10-04T09:12:00.000Z"},"place":{"type":"string","nullable":true,"example":"Room S2"},"guestName":{"type":"string","nullable":true,"example":"Aung Aung"},"items":{"type":"array","items":{"$ref":"#/components/schemas/BillItemDto"}},"compedItems":{"description":"Given free (FOC)","type":"array","items":{"$ref":"#/components/schemas/BillCompedItemDto"}},"grossSales":{"type":"string","example":"51000.0000"},"discounts":{"type":"string","example":"0.0000"},"netSales":{"type":"string","example":"51000.0000"},"tax":{"type":"string","example":"0.0000"},"grandTotal":{"type":"string","example":"51000.0000"},"payments":{"type":"array","items":{"$ref":"#/components/schemas/NameAmountDto"}}},"required":["orderId","orderNumber","businessDate","soldAt","place","guestName","items","compedItems","grossSales","discounts","netSales","tax","grandTotal","payments"]},"PageMetaDto":{"type":"object","properties":{"total":{"type":"number","example":42},"page":{"type":"number","example":1},"limit":{"type":"number","example":50},"totalPages":{"type":"number","example":1}},"required":["total","page","limit","totalPages"]},"PosBillsReportDto":{"type":"object","properties":{"from":{"type":"string","example":"2026-10-01"},"to":{"type":"string","example":"2026-10-04"},"posType":{"type":"string","enum":["BAR","SPA","KTV"]},"totals":{"description":"Over every bill, not one page","allOf":[{"$ref":"#/components/schemas/BillTotalsDto"}]},"bills":{"type":"array","items":{"$ref":"#/components/schemas/BillRowDto"}},"meta":{"$ref":"#/components/schemas/PageMetaDto"}},"required":["from","to","posType","totals","bills","meta"]},"BarCategoryTotalsDto":{"type":"object","properties":{"orderCount":{"type":"number","example":120},"quantity":{"type":"string","example":"640.0000"},"grossSales":{"type":"string","example":"1300000.0000"},"discounts":{"type":"string","example":"20000.0000"},"netSales":{"type":"string","example":"1280000.0000"},"refundAmount":{"type":"string","example":"5000.0000"},"compedValue":{"type":"string","example":"10000.0000"}},"required":["orderCount","quantity","grossSales","discounts","netSales","refundAmount","compedValue"]},"SubCategoryRowDto":{"type":"object","properties":{"orderCount":{"type":"number","example":18},"quantity":{"type":"string","example":"64.0000"},"grossSales":{"type":"string","example":"320000.0000"},"discounts":{"type":"string","example":"8000.0000","description":"Line and bill discounts"},"netSales":{"type":"string","example":"312000.0000"},"shareOfNetSales":{"type":"string","example":"24.10","description":"Percent of the report net sales"},"compedQuantity":{"type":"string","example":"2.0000","description":"Given free (FOC)"},"compedValue":{"type":"string","example":"10000.0000"},"categoryId":{"type":"string","nullable":true,"example":"uuid"},"categoryName":{"type":"string","example":"Draft beer"},"refundAmount":{"type":"string","example":"5000.0000"}},"required":["orderCount","quantity","grossSales","discounts","netSales","shareOfNetSales","compedQuantity","compedValue","categoryId","categoryName","refundAmount"]},"CategoryRowDto":{"type":"object","properties":{"orderCount":{"type":"number","example":18},"quantity":{"type":"string","example":"64.0000"},"grossSales":{"type":"string","example":"320000.0000"},"discounts":{"type":"string","example":"8000.0000","description":"Line and bill discounts"},"netSales":{"type":"string","example":"312000.0000"},"shareOfNetSales":{"type":"string","example":"24.10","description":"Percent of the report net sales"},"compedQuantity":{"type":"string","example":"2.0000","description":"Given free (FOC)"},"compedValue":{"type":"string","example":"10000.0000"},"categoryId":{"type":"string","nullable":true,"example":"uuid"},"categoryName":{"type":"string","example":"Draft beer"},"refundAmount":{"type":"string","example":"5000.0000"},"subCategories":{"description":"Its sub-categories, already included in this row","type":"array","items":{"$ref":"#/components/schemas/SubCategoryRowDto"}}},"required":["orderCount","quantity","grossSales","discounts","netSales","shareOfNetSales","compedQuantity","compedValue","categoryId","categoryName","refundAmount","subCategories"]},"BarCategoryReportDto":{"type":"object","properties":{"from":{"type":"string","example":"2026-10-01"},"to":{"type":"string","example":"2026-10-04"},"totals":{"$ref":"#/components/schemas/BarCategoryTotalsDto"},"categories":{"type":"array","items":{"$ref":"#/components/schemas/CategoryRowDto"}}},"required":["from","to","totals","categories"]},"SpaMenuTotalsDto":{"type":"object","properties":{"orderCount":{"type":"number","example":40},"netSales":{"type":"string","example":"1862000.0000"},"grandTotal":{"type":"string","example":"1862000.0000"}},"required":["orderCount","netSales","grandTotal"]},"SpaSectionTotalsDto":{"type":"object","properties":{"quantity":{"type":"string","example":"30.0000"},"grossSales":{"type":"string","example":"1350000.0000"},"discounts":{"type":"string","example":"0.0000"},"netSales":{"type":"string","example":"1350000.0000"},"shareOfNetSales":{"type":"string","example":"72.50"},"compedValue":{"type":"string","example":"0.0000"}},"required":["quantity","grossSales","discounts","netSales","shareOfNetSales","compedValue"]},"SpaMenuRowDto":{"type":"object","properties":{"orderCount":{"type":"number","example":18},"quantity":{"type":"string","example":"64.0000"},"grossSales":{"type":"string","example":"320000.0000"},"discounts":{"type":"string","example":"8000.0000","description":"Line and bill discounts"},"netSales":{"type":"string","example":"312000.0000"},"shareOfNetSales":{"type":"string","example":"24.10","description":"Percent of the report net sales"},"compedQuantity":{"type":"string","example":"2.0000","description":"Given free (FOC)"},"compedValue":{"type":"string","example":"10000.0000"},"variantId":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Thai massage 90 min"},"durationMinutes":{"type":"number","nullable":true,"example":90,"description":"Packages only"},"includes":{"example":["1 × Orange juice"],"description":"What a room + menu package includes","type":"array","items":{"type":"string"}}},"required":["orderCount","quantity","grossSales","discounts","netSales","shareOfNetSales","compedQuantity","compedValue","variantId","name","durationMinutes","includes"]},"SpaSectionDto":{"type":"object","properties":{"totals":{"$ref":"#/components/schemas/SpaSectionTotalsDto"},"rows":{"type":"array","items":{"$ref":"#/components/schemas/SpaMenuRowDto"}}},"required":["totals","rows"]},"SpaMenuReportDto":{"type":"object","properties":{"from":{"type":"string","example":"2026-10-01"},"to":{"type":"string","example":"2026-10-04"},"totals":{"$ref":"#/components/schemas/SpaMenuTotalsDto"},"spaMenu":{"description":"SPA menu: service packages with no food or drink included","allOf":[{"$ref":"#/components/schemas/SpaSectionDto"}]},"roomMenuPackages":{"description":"Room + menu packages: packages that include food or drink","allOf":[{"$ref":"#/components/schemas/SpaSectionDto"}]},"roomServices":{"description":"Room services: food, drinks and add-ons ordered in the room. Items included in a package are not counted again here.","allOf":[{"$ref":"#/components/schemas/SpaSectionDto"}]},"roomTime":{"description":"Older treatments billed as room time; empty once rooms have no price","allOf":[{"$ref":"#/components/schemas/SpaSectionDto"}]}},"required":["from","to","totals","spaMenu","roomMenuPackages","roomServices","roomTime"]},"KtvTotalsDto":{"type":"object","properties":{"sessionCount":{"type":"number","example":12},"hoursSold":{"type":"string","example":"30.0000"},"freeHours":{"type":"string","example":"2.0000"},"roomSales":{"type":"string","example":"900000.0000"},"fnbSales":{"type":"string","example":"350000.0000"},"discounts":{"type":"string","example":"0.0000"},"compedValue":{"type":"string","example":"60000.0000"},"netSales":{"type":"string","example":"1250000.0000"},"grandTotal":{"type":"string","example":"1250000.0000"}},"required":["sessionCount","hoursSold","freeHours","roomSales","fnbSales","discounts","compedValue","netSales","grandTotal"]},"KtvRoomSummaryDto":{"type":"object","properties":{"roomId":{"type":"string","example":"uuid"},"roomNumber":{"type":"string","example":"K1"},"roomName":{"type":"string","nullable":true,"example":"Gold"},"sessionCount":{"type":"number","example":5},"hoursSold":{"type":"string","example":"14.0000"},"freeHours":{"type":"string","example":"1.0000"},"roomSales":{"type":"string","example":"420000.0000"},"fnbSales":{"type":"string","example":"160000.0000"},"grandTotal":{"type":"string","example":"580000.0000"}},"required":["roomId","roomNumber","roomName","sessionCount","hoursSold","freeHours","roomSales","fnbSales","grandTotal"]},"KtvSessionRowDto":{"type":"object","properties":{"sessionId":{"type":"string","nullable":true,"example":"uuid"},"orderId":{"type":"string","example":"uuid"},"orderNumber":{"type":"string","example":"SO-K01-20261004-0003"},"businessDate":{"type":"string","example":"2026-10-04"},"roomNumber":{"type":"string","nullable":true,"example":"K1"},"roomName":{"type":"string","nullable":true,"example":"Gold"},"guestName":{"type":"string","nullable":true,"example":"Aung Aung"},"guestCount":{"type":"number","nullable":true,"example":6},"openedAt":{"format":"date-time","type":"string","nullable":true,"example":"2026-10-04T13:00:00.000Z"},"closedAt":{"format":"date-time","type":"string","nullable":true,"example":"2026-10-04T16:10:00.000Z"},"minutesUsed":{"type":"number","nullable":true,"example":190,"description":"Pauses left out"},"hoursSold":{"type":"string","example":"3.0000"},"freeHours":{"type":"string","example":"1.0000","description":"Hours given free"},"roomSales":{"type":"string","example":"90000.0000","description":"Net sales of room time"},"fnbSales":{"type":"string","example":"42000.0000","description":"Net sales of food and drink"},"discounts":{"type":"string","example":"0.0000"},"compedValue":{"type":"string","example":"30000.0000","description":"Value given free (FOC)"},"netSales":{"type":"string","example":"132000.0000"},"grandTotal":{"type":"string","example":"132000.0000"},"payments":{"type":"array","items":{"$ref":"#/components/schemas/NameAmountDto"}}},"required":["sessionId","orderId","orderNumber","businessDate","roomNumber","roomName","guestName","guestCount","openedAt","closedAt","minutesUsed","hoursSold","freeHours","roomSales","fnbSales","discounts","compedValue","netSales","grandTotal","payments"]},"KtvSessionReportDto":{"type":"object","properties":{"from":{"type":"string","example":"2026-10-01"},"to":{"type":"string","example":"2026-10-04"},"totals":{"description":"All sessions together","allOf":[{"$ref":"#/components/schemas/KtvTotalsDto"}]},"byRoom":{"type":"array","items":{"$ref":"#/components/schemas/KtvRoomSummaryDto"}},"sessions":{"description":"Newest first","type":"array","items":{"$ref":"#/components/schemas/KtvSessionRowDto"}}},"required":["from","to","totals","byRoom","sessions"]},"HostessTotalsDto":{"type":"object","properties":{"calls":{"type":"number","example":12},"hostesses":{"type":"number","example":4},"hours":{"type":"string","example":"20.0000"},"netSales":{"type":"string","example":"400000.0000"}},"required":["calls","hostesses","hours","netSales"]},"HostessSummaryDto":{"type":"object","properties":{"hostessId":{"type":"string","example":"uuid"},"hostessName":{"type":"string","example":"Ma Hnin"},"nickname":{"type":"string","nullable":true,"example":"Snow"},"calls":{"type":"number","example":5},"freeCalls":{"type":"number","example":1},"hours":{"type":"string","example":"8.0000"},"netSales":{"type":"string","example":"160000.0000"}},"required":["hostessId","hostessName","calls","freeCalls","hours","netSales"]},"HostessCallRowDto":{"type":"object","properties":{"businessDate":{"type":"string","example":"2026-10-06"},"soldAt":{"format":"date-time","type":"string","example":"2026-10-06T14:00:00.000Z"},"orderNumber":{"type":"string","example":"SO-K01-20261006-0003"},"roomNumber":{"type":"string","nullable":true,"example":"K3"},"hostessId":{"type":"string","example":"uuid"},"hostessName":{"type":"string","example":"Ma Hnin"},"nickname":{"type":"string","nullable":true,"example":"Snow"},"service":{"type":"string","example":"Hostess (per hour)"},"quantity":{"type":"string","example":"2.0000","description":"Units sold: hours, or calls"},"hours":{"type":"string","example":"2.0000","description":"Hours, for a service sold by time; 0 otherwise"},"free":{"type":"boolean","example":false,"description":"Given free by the house (FOC)"},"netSales":{"type":"string","example":"40000.0000","description":"0 when free"}},"required":["businessDate","soldAt","orderNumber","hostessId","hostessName","service","quantity","hours","free","netSales"]},"HostessReportDto":{"type":"object","properties":{"from":{"type":"string","example":"2026-10-01"},"to":{"type":"string","example":"2026-10-06"},"totals":{"$ref":"#/components/schemas/HostessTotalsDto"},"byHostess":{"description":"Highest sales first","type":"array","items":{"$ref":"#/components/schemas/HostessSummaryDto"}},"calls":{"description":"Newest first","type":"array","items":{"$ref":"#/components/schemas/HostessCallRowDto"}}},"required":["from","to","totals","byHostess","calls"]},"ItemTotalsDto":{"type":"object","properties":{"itemCount":{"type":"number","example":42},"quantitySold":{"type":"string","example":"860.0000"},"grossSales":{"type":"string","example":"4800000.0000"},"lineDiscounts":{"type":"string","example":"120000.0000"},"orderDiscounts":{"type":"string","example":"60000.0000"},"netSales":{"type":"string","example":"4620000.0000"},"quantityReturned":{"type":"string","example":"3.0000"},"refundAmount":{"type":"string","example":"14285.7143","description":"Before tax"},"netAfterRefunds":{"type":"string","example":"4605714.2857"},"quantityVoided":{"type":"string","example":"4.0000"},"voidedValue":{"type":"string","example":"20000.0000"},"quantityComped":{"type":"string","example":"1.0000"},"compedValue":{"type":"string","example":"8000.0000"}},"required":["itemCount","quantitySold","grossSales","lineDiscounts","orderDiscounts","netSales","quantityReturned","refundAmount","netAfterRefunds","quantityVoided","voidedValue","quantityComped","compedValue"]},"ItemCategoryRowDto":{"type":"object","properties":{"categoryId":{"type":"string","nullable":true,"example":"uuid"},"categoryName":{"type":"string","example":"Beer"},"orderCount":{"type":"number","example":55},"quantitySold":{"type":"string","example":"310.0000"},"netSales":{"type":"string","example":"1550000.0000"},"shareOfNetSales":{"type":"string","example":"33.55","description":"Percent of net sales"},"refundAmount":{"type":"string","example":"0.0000"}},"required":["categoryId","categoryName","orderCount","quantitySold","netSales","shareOfNetSales","refundAmount"]},"ItemRowDto":{"type":"object","properties":{"variantId":{"type":"string","example":"uuid"},"productId":{"type":"string","nullable":true,"example":"uuid"},"productName":{"type":"string","example":"Myanmar Beer"},"variantSku":{"type":"string","nullable":true,"example":"BEER-MM-640"},"categoryId":{"type":"string","nullable":true,"example":"uuid"},"categoryName":{"type":"string","example":"Beer"},"orderCount":{"type":"number","example":40},"quantitySold":{"type":"string","example":"120.0000"},"averagePrice":{"type":"string","example":"4750.0000","description":"Net sales per unit"},"grossSales":{"type":"string","example":"600000.0000"},"lineDiscounts":{"type":"string","example":"12000.0000"},"orderDiscounts":{"type":"string","example":"18000.0000","description":"Share of bill discounts"},"netSales":{"type":"string","example":"570000.0000"},"shareOfNetSales":{"type":"string","example":"12.34"},"quantityReturned":{"type":"string","example":"1.0000"},"refundAmount":{"type":"string","example":"4750.0000"},"netQuantity":{"type":"string","example":"119.0000"},"netAfterRefunds":{"type":"string","example":"565250.0000"},"quantityVoided":{"type":"string","example":"2.0000"},"voidedValue":{"type":"string","example":"10000.0000"},"quantityComped":{"type":"string","example":"0.0000"},"compedValue":{"type":"string","example":"0.0000"}},"required":["variantId","productId","productName","variantSku","categoryId","categoryName","orderCount","quantitySold","averagePrice","grossSales","lineDiscounts","orderDiscounts","netSales","shareOfNetSales","quantityReturned","refundAmount","netQuantity","netAfterRefunds","quantityVoided","voidedValue","quantityComped","compedValue"]},"ItemSalesReportDto":{"type":"object","properties":{"from":{"type":"string","example":"2026-09-01"},"to":{"type":"string","example":"2026-09-14"},"locationIds":{"nullable":true,"description":"Outlets covered; null means every outlet you can see.","type":"array","items":{"type":"string"}},"totals":{"description":"Across every item matching the filters, not just this page","allOf":[{"$ref":"#/components/schemas/ItemTotalsDto"}]},"categories":{"type":"array","items":{"$ref":"#/components/schemas/ItemCategoryRowDto"}},"items":{"type":"array","items":{"$ref":"#/components/schemas/ItemRowDto"}},"meta":{"$ref":"#/components/schemas/PageMetaDto"}},"required":["from","to","locationIds","totals","categories","items","meta"]},"IncomeExpenseTotalsDto":{"type":"object","properties":{"incomeCount":{"type":"number","example":2},"income":{"type":"string","example":"30000.0000"},"expenseCount":{"type":"number","example":5},"expense":{"type":"string","example":"85000.0000"},"net":{"type":"string","example":"-55000.0000"}},"required":["incomeCount","income","expenseCount","expense","net"]},"IncomeExpenseDayRowDto":{"type":"object","properties":{"businessDate":{"type":"string","example":"2026-09-13"},"income":{"type":"string","example":"0.0000"},"expense":{"type":"string","example":"25000.0000"},"net":{"type":"string","example":"-25000.0000"}},"required":["businessDate","income","expense","net"]},"IncomeExpenseMethodRowDto":{"type":"object","properties":{"paymentMethodId":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Cash"},"kind":{"type":"string","example":"CASH"},"income":{"type":"string","example":"30000.0000"},"expense":{"type":"string","example":"85000.0000"}},"required":["paymentMethodId","name","kind","income","expense"]},"IncomeExpenseOutletRowDto":{"type":"object","properties":{"locationId":{"type":"string","example":"uuid"},"locationName":{"type":"string","example":"Restaurant"},"income":{"type":"string","example":"30000.0000"},"expense":{"type":"string","example":"85000.0000"},"net":{"type":"string","example":"-55000.0000"}},"required":["locationId","locationName","income","expense","net"]},"IncomeExpenseEntryDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"businessDate":{"type":"string","example":"2026-09-13"},"createdAt":{"format":"date-time","type":"string","example":"2026-09-13T08:15:00.000Z"},"type":{"type":"string","enum":["INCOME","EXPENSE"]},"reason":{"type":"string","example":"PAID_OUT"},"amount":{"type":"string","example":"25000.0000"},"locationId":{"type":"string","example":"uuid"},"locationName":{"type":"string","example":"Restaurant"},"paymentMethodId":{"type":"string","example":"uuid"},"paymentMethodName":{"type":"string","example":"Cash"},"reference":{"type":"string","nullable":true,"example":"INV-2231"},"notes":{"type":"string","nullable":true,"example":"Ice delivery"},"posSessionId":{"type":"string","example":"uuid"},"staffName":{"type":"string","nullable":true,"example":"Ma Thida"},"approverName":{"type":"string","nullable":true,"example":"U Kyaw"}},"required":["id","businessDate","createdAt","type","reason","amount","locationId","locationName","paymentMethodId","paymentMethodName","reference","notes","posSessionId","staffName","approverName"]},"OtherIncomeExpenseReportDto":{"type":"object","properties":{"from":{"type":"string","example":"2026-09-01"},"to":{"type":"string","example":"2026-09-14"},"locationIds":{"nullable":true,"description":"Outlets covered; null means every outlet you can see.","type":"array","items":{"type":"string"}},"totals":{"$ref":"#/components/schemas/IncomeExpenseTotalsDto"},"byDay":{"type":"array","items":{"$ref":"#/components/schemas/IncomeExpenseDayRowDto"}},"byPaymentMethod":{"type":"array","items":{"$ref":"#/components/schemas/IncomeExpenseMethodRowDto"}},"byOutlet":{"type":"array","items":{"$ref":"#/components/schemas/IncomeExpenseOutletRowDto"}},"entries":{"type":"array","items":{"$ref":"#/components/schemas/IncomeExpenseEntryDto"}}},"required":["from","to","locationIds","totals","byDay","byPaymentMethod","byOutlet","entries"]},"IssuedTierRowDto":{"type":"object","properties":{"tier":{"type":"string","example":"Gold"},"count":{"type":"number","example":4},"preloadValue":{"type":"string","example":"200000.0000"}},"required":["tier","count","preloadValue"]},"IssuedDto":{"type":"object","properties":{"count":{"type":"number","example":9},"linkedToCustomer":{"type":"number","example":4,"description":"Of those, issued to a named customer rather than a walk-in"},"byTier":{"type":"array","items":{"$ref":"#/components/schemas/IssuedTierRowDto"}}},"required":["count","linkedToCustomer","byTier"]},"ClosedDto":{"type":"object","properties":{"count":{"type":"number","example":6},"settled":{"type":"number","example":5},"voided":{"type":"number","example":1}},"required":["count","settled","voided"]},"TopUpsDto":{"type":"object","properties":{"count":{"type":"number","example":12},"amount":{"type":"string","example":"1250000.0000"},"byPaymentMethod":{"type":"array","items":{"$ref":"#/components/schemas/PaymentMethodRowDto"}}},"required":["count","amount","byPaymentMethod"]},"SpendDto":{"type":"object","properties":{"count":{"type":"number","example":48},"reversals":{"type":"number","example":1},"amount":{"type":"string","example":"980000.0000","description":"Net of reversals"}},"required":["count","reversals","amount"]},"LedgerDto":{"type":"object","properties":{"topUps":{"$ref":"#/components/schemas/CountAmountDto"},"preloadGranted":{"$ref":"#/components/schemas/CountAmountDto"},"spend":{"$ref":"#/components/schemas/SpendDto"},"refunds":{"$ref":"#/components/schemas/CountAmountDto"},"settlementsCollected":{"$ref":"#/components/schemas/CountAmountDto"},"forfeited":{"description":"Promotional value written off","allOf":[{"$ref":"#/components/schemas/CountAmountDto"}]},"adjustmentsCredit":{"$ref":"#/components/schemas/CountAmountDto"},"adjustmentsDebit":{"$ref":"#/components/schemas/CountAmountDto"},"netChange":{"type":"string","example":"270000.0000","description":"Change in what guests hold"}},"required":["topUps","preloadGranted","spend","refunds","settlementsCollected","forfeited","adjustmentsCredit","adjustmentsDebit","netChange"]},"SpendOutletRowDto":{"type":"object","properties":{"locationId":{"type":"string","example":"uuid"},"locationName":{"type":"string","example":"KTV"},"count":{"type":"number","example":30},"amount":{"type":"string","example":"640000.0000"}},"required":["locationId","locationName","count","amount"]},"SpendTierRowDto":{"type":"object","properties":{"tier":{"type":"string","example":"Gold"},"amount":{"type":"string","example":"400000.0000"}},"required":["tier","amount"]},"OutstandingCardsDto":{"type":"object","properties":{"activeCards":{"type":"number","example":10},"walletsInCredit":{"type":"number","example":4},"owedToGuests":{"type":"string","example":"381250.0000","description":"Owed to guests. Matches /reports/guest-card/liability total."},"purchased":{"type":"string","example":"361250.0000","description":"Refundable in cash"},"granted":{"type":"string","example":"20000.0000","description":"Promotional"},"walletsInDebt":{"type":"number","example":1},"owedByGuests":{"type":"string","example":"96500.0000","description":"Owed by postpaid guests, as a positive amount"}},"required":["activeCards","walletsInCredit","owedToGuests","purchased","granted","walletsInDebt","owedByGuests"]},"MemberCardReportDto":{"type":"object","properties":{"from":{"type":"string","example":"2026-09-01"},"to":{"type":"string","example":"2026-09-14"},"locationIds":{"nullable":true,"description":"Outlets covered; null means every outlet you can see.","type":"array","items":{"type":"string"}},"issued":{"$ref":"#/components/schemas/IssuedDto"},"closed":{"$ref":"#/components/schemas/ClosedDto"},"topUps":{"$ref":"#/components/schemas/TopUpsDto"},"ledger":{"$ref":"#/components/schemas/LedgerDto"},"spendByOutlet":{"type":"array","items":{"$ref":"#/components/schemas/SpendOutletRowDto"}},"spendByTier":{"type":"array","items":{"$ref":"#/components/schemas/SpendTierRowDto"}},"outstanding":{"description":"As of now","allOf":[{"$ref":"#/components/schemas/OutstandingCardsDto"}]}},"required":["from","to","locationIds","issued","closed","topUps","ledger","spendByOutlet","spendByTier","outstanding"]},"PointsTypeRowDto":{"type":"object","properties":{"transactionType":{"type":"string","example":"EARN"},"entries":{"type":"number","example":60},"points":{"type":"number","example":2400000}},"required":["transactionType","entries","points"]},"PointsPeriodDto":{"type":"object","properties":{"pointsEarned":{"type":"number","example":2400000},"pointsReversed":{"type":"number","example":15000},"netPoints":{"type":"number","example":2385000},"activeMembers":{"type":"number","example":38},"newMembers":{"type":"number","example":6},"byTransactionType":{"type":"array","items":{"$ref":"#/components/schemas/PointsTypeRowDto"}}},"required":["pointsEarned","pointsReversed","netPoints","activeMembers","newMembers","byTransactionType"]},"PointsOutstandingDto":{"type":"object","properties":{"members":{"type":"number","example":120},"points":{"type":"number","example":9800000},"pointsRedeemed":{"type":"number","example":0,"description":"Always 0: redemption does not exist yet"},"pointsExpired":{"type":"number","example":0,"description":"Always 0: nothing expires points yet"}},"required":["members","points","pointsRedeemed","pointsExpired"]},"LoyaltyTierRowDto":{"type":"object","properties":{"loyaltyTier":{"type":"string","example":"BRONZE"},"members":{"type":"number","example":100}},"required":["loyaltyTier","members"]},"TopMemberRowDto":{"type":"object","properties":{"customerId":{"type":"string","example":"uuid"},"name":{"type":"string","nullable":true,"example":"U Mg Mg"},"phone":{"type":"string","nullable":true,"example":"09 7700 11223"},"loyaltyTier":{"type":"string","nullable":true,"example":"GOLD"},"pointsEarned":{"type":"number","example":180000},"pointsBalance":{"type":"number","example":420000}},"required":["customerId","name","phone","loyaltyTier","pointsEarned","pointsBalance"]},"LoyaltyPointsReportDto":{"type":"object","properties":{"from":{"type":"string","example":"2026-09-01"},"to":{"type":"string","example":"2026-09-14"},"locationIds":{"nullable":true,"description":"Outlets covered; null means every outlet you can see.","type":"array","items":{"type":"string"}},"period":{"$ref":"#/components/schemas/PointsPeriodDto"},"outstanding":{"description":"As of now","allOf":[{"$ref":"#/components/schemas/PointsOutstandingDto"}]},"byLoyaltyTier":{"type":"array","items":{"$ref":"#/components/schemas/LoyaltyTierRowDto"}},"topMembers":{"type":"array","items":{"$ref":"#/components/schemas/TopMemberRowDto"}}},"required":["from","to","locationIds","period","outstanding","byLoyaltyTier","topMembers"]},"PaymentBreakdownRowDto":{"type":"object","properties":{"paymentMethodId":{"type":"string","example":"uuid"},"method":{"type":"string","example":"CASH"},"total":{"type":"string","example":"150.0000"}},"required":["paymentMethodId","method","total"]},"DailySalesSummaryDto":{"type":"object","properties":{"locationId":{"type":"string","nullable":true,"example":"uuid","description":"The outlet asked for; null when the report covers several"},"date":{"type":"string","example":"2026-07-02"},"orderCount":{"type":"number","example":42},"subtotal":{"type":"string","example":"1000.0000"},"totalTax":{"type":"string","example":"70.0000"},"totalDiscount":{"type":"string","example":"25.0000"},"tipAmount":{"type":"string","example":"30.0000"},"serviceCharge":{"type":"string","example":"15.0000"},"grandTotal":{"type":"string","example":"1090.0000"},"averageTicket":{"type":"string","example":"25.9500"},"paymentBreakdown":{"type":"array","items":{"$ref":"#/components/schemas/PaymentBreakdownRowDto"}}},"required":["locationId","date","orderCount","subtotal","totalTax","totalDiscount","tipAmount","serviceCharge","grandTotal","averageTicket","paymentBreakdown"]},"CategorySalesRowDto":{"type":"object","properties":{"categoryId":{"type":"string","nullable":true,"example":"uuid"},"categoryName":{"type":"string","example":"Beverages"},"orderCount":{"type":"number","example":12},"totalRevenue":{"type":"string","example":"350.0000"}},"required":["categoryId","categoryName","orderCount","totalRevenue"]},"ItemSalesRowDto":{"type":"object","properties":{"variantId":{"type":"string","example":"uuid"},"productName":{"type":"string","example":"Iced Latte"},"variantSku":{"type":"string","example":"SKU-001"},"quantitySold":{"type":"string","example":"48.0000"},"totalRevenue":{"type":"string","example":"240.0000"}},"required":["variantId","productName","variantSku","quantitySold","totalRevenue"]},"HourlySalesRowDto":{"type":"object","properties":{"hour":{"type":"number","example":14},"orderCount":{"type":"number","example":8},"totalRevenue":{"type":"string","example":"180.0000"}},"required":["hour","orderCount","totalRevenue"]},"ServerPerformanceRowDto":{"type":"object","properties":{"waiterId":{"type":"string","nullable":true,"example":"uuid"},"waiterName":{"type":"string","nullable":true,"example":"Ko Aung"},"orderCount":{"type":"number","example":15},"totalRevenue":{"type":"string","example":"420.0000"},"totalTips":{"type":"string","example":"35.0000"},"averageTicket":{"type":"string","example":"28.0000"}},"required":["waiterId","waiterName","orderCount","totalRevenue","totalTips","averageTicket"]},"ZReportOrdersDto":{"type":"object","properties":{"completed":{"type":"number","example":40},"voided":{"type":"number","example":2},"refunded":{"type":"number","example":1}},"required":["completed","voided","refunded"]},"ZReportTotalsDto":{"type":"object","properties":{"subtotal":{"type":"string","example":"1000.0000"},"totalDiscount":{"type":"string","example":"25.0000"},"totalTax":{"type":"string","example":"70.0000"},"tipAmount":{"type":"string","example":"30.0000"},"serviceCharge":{"type":"string","example":"15.0000"},"grandTotal":{"type":"string","example":"1090.0000"}},"required":["subtotal","totalDiscount","totalTax","tipAmount","serviceCharge","grandTotal"]},"ZReportPaymentRowDto":{"type":"object","properties":{"paymentMethodId":{"type":"string","example":"uuid"},"method":{"type":"string","example":"CASH"},"total":{"type":"string","example":"600.0000"},"tip":{"type":"string","example":"20.0000"}},"required":["paymentMethodId","method","total","tip"]},"ZReportDto":{"type":"object","properties":{"locationId":{"type":"string","nullable":true,"example":"uuid","description":"The outlet asked for; null when the report covers several"},"date":{"type":"string","example":"2026-07-02"},"orders":{"$ref":"#/components/schemas/ZReportOrdersDto"},"totals":{"$ref":"#/components/schemas/ZReportTotalsDto"},"payments":{"type":"array","items":{"$ref":"#/components/schemas/ZReportPaymentRowDto"}},"topItems":{"type":"array","items":{"$ref":"#/components/schemas/ItemSalesRowDto"}},"byCategory":{"type":"array","items":{"$ref":"#/components/schemas/CategorySalesRowDto"}}},"required":["locationId","date","orders","totals","payments","topItems","byCategory"]},"ShiftTotalsDto":{"type":"object","properties":{"salesCount":{"type":"number","example":12,"description":"Bills paid"},"refundCount":{"type":"number","example":1},"totalSales":{"type":"string","example":"540000.0000"},"totalRefunds":{"type":"string","example":"12000.0000"},"netTotal":{"type":"string","example":"528000.0000"},"cardTopUps":{"type":"string","example":"100000.0000","description":"Guest-card top-ups taken; deposits, not sales"},"cardRefunds":{"type":"string","example":"0.0000","description":"Card balances paid back"},"payments":{"description":"Sales payments by method, net of refunds","type":"array","items":{"$ref":"#/components/schemas/NameAmountDto"}},"shifts":{"type":"number","example":14}},"required":["salesCount","refundCount","totalSales","totalRefunds","netTotal","cardTopUps","cardRefunds","payments","shifts"]},"ShiftStaffDto":{"type":"object","properties":{"salesCount":{"type":"number","example":12,"description":"Bills paid"},"refundCount":{"type":"number","example":1},"totalSales":{"type":"string","example":"540000.0000"},"totalRefunds":{"type":"string","example":"12000.0000"},"netTotal":{"type":"string","example":"528000.0000"},"cardTopUps":{"type":"string","example":"100000.0000","description":"Guest-card top-ups taken; deposits, not sales"},"cardRefunds":{"type":"string","example":"0.0000","description":"Card balances paid back"},"payments":{"description":"Sales payments by method, net of refunds","type":"array","items":{"$ref":"#/components/schemas/NameAmountDto"}},"cashierId":{"type":"string","example":"uuid"},"cashierName":{"type":"string","example":"Su Su"},"shifts":{"type":"number","example":6}},"required":["salesCount","refundCount","totalSales","totalRefunds","netTotal","cardTopUps","cardRefunds","payments","cashierId","cashierName","shifts"]},"ShiftMethodDto":{"type":"object","properties":{"name":{"type":"string","example":"Cash"},"kind":{"type":"string","example":"CASH"},"count":{"type":"number","example":40},"amount":{"type":"string","example":"320000.0000","description":"Net of refunds"}},"required":["name","kind","count","amount"]},"ShiftRowDto":{"type":"object","properties":{"salesCount":{"type":"number","example":12,"description":"Bills paid"},"refundCount":{"type":"number","example":1},"totalSales":{"type":"string","example":"540000.0000"},"totalRefunds":{"type":"string","example":"12000.0000"},"netTotal":{"type":"string","example":"528000.0000"},"cardTopUps":{"type":"string","example":"100000.0000","description":"Guest-card top-ups taken; deposits, not sales"},"cardRefunds":{"type":"string","example":"0.0000","description":"Card balances paid back"},"payments":{"description":"Sales payments by method, net of refunds","type":"array","items":{"$ref":"#/components/schemas/NameAmountDto"}},"sessionId":{"type":"string","example":"uuid"},"businessDate":{"type":"string","example":"2026-10-11","description":"The day it opened"},"registerName":{"type":"string","example":"Bar POS 1"},"locationName":{"type":"string","example":"Main outlet"},"cashierId":{"type":"string","example":"uuid"},"cashierName":{"type":"string","example":"Su Su"},"openedAt":{"format":"date-time","type":"string"},"closedAt":{"format":"date-time","type":"string","nullable":true},"status":{"type":"string","example":"CLOSED"}},"required":["salesCount","refundCount","totalSales","totalRefunds","netTotal","cardTopUps","cardRefunds","payments","sessionId","businessDate","registerName","locationName","cashierId","cashierName","openedAt","status"]},"ShiftReportDto":{"type":"object","properties":{"from":{"type":"string","example":"2026-10-01"},"to":{"type":"string","example":"2026-10-11"},"totals":{"$ref":"#/components/schemas/ShiftTotalsDto"},"byStaff":{"type":"array","items":{"$ref":"#/components/schemas/ShiftStaffDto"}},"byPaymentMethod":{"type":"array","items":{"$ref":"#/components/schemas/ShiftMethodDto"}},"shifts":{"description":"Newest first","type":"array","items":{"$ref":"#/components/schemas/ShiftRowDto"}}},"required":["from","to","totals","byStaff","byPaymentMethod","shifts"]},"CardTypeTotalDto":{"type":"object","properties":{"type":{"type":"string","enum":["TOP_UP","PRELOAD_GRANT","SPEND","SPEND_REVERSAL","REFUND_OUT","SETTLEMENT_COLLECTION","GRANT_FORFEIT","ADJUSTMENT_CREDIT","ADJUSTMENT_DEBIT"]},"count":{"type":"number","example":12},"amount":{"type":"string","example":"-240000.0000","description":"Signed: onto the card positive"}},"required":["type","count","amount"]},"CardActivityTotalsDto":{"type":"object","properties":{"entries":{"type":"number","example":120},"netChange":{"type":"string","example":"-240000.0000"},"byType":{"type":"array","items":{"$ref":"#/components/schemas/CardTypeTotalDto"}}},"required":["entries","netChange","byType"]},"CardTierTotalDto":{"type":"object","properties":{"tier":{"type":"string","example":"Gold"},"count":{"type":"number","example":30},"amount":{"type":"string","example":"-150000.0000"}},"required":["tier","count","amount"]},"CardMethodTotalDto":{"type":"object","properties":{"name":{"type":"string","example":"Cash"},"count":{"type":"number","example":8},"topUps":{"type":"string","example":"500000.0000"},"refunds":{"type":"string","example":"20000.0000","description":"Paid back to guests"},"settlements":{"type":"string","example":"0.0000","description":"Postpaid debts collected"},"net":{"type":"string","example":"480000.0000"}},"required":["name","count","topUps","refunds","settlements","net"]},"CardEntryDto":{"type":"object","properties":{"entryId":{"type":"string","example":"uuid"},"businessDate":{"type":"string","example":"2026-10-11"},"createdAt":{"format":"date-time","type":"string"},"type":{"type":"string","enum":["TOP_UP","PRELOAD_GRANT","SPEND","SPEND_REVERSAL","REFUND_OUT","SETTLEMENT_COLLECTION","GRANT_FORFEIT","ADJUSTMENT_CREDIT","ADJUSTMENT_DEBIT"]},"cardUid":{"type":"string","nullable":true,"example":"04A3B2C1"},"walletNumber":{"type":"string","example":"W-000123"},"guestName":{"type":"string","example":"Aung Aung"},"guestPhone":{"type":"string","nullable":true},"tier":{"type":"string","example":"Gold"},"locationName":{"type":"string","example":"Main outlet"},"orderNumber":{"type":"string","nullable":true,"description":"Bill paid, for spending"},"paymentMethod":{"type":"string","nullable":true,"description":"Tender, for money in or out"},"amount":{"type":"string","example":"-45000.0000","description":"Signed: onto the card positive"},"balanceAfter":{"type":"string","example":"55000.0000"},"reference":{"type":"string","nullable":true},"staffName":{"type":"string","nullable":true},"approverName":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true}},"required":["entryId","businessDate","createdAt","type","walletNumber","guestName","tier","locationName","amount","balanceAfter"]},"CardActivityReportDto":{"type":"object","properties":{"from":{"type":"string","example":"2026-10-01"},"to":{"type":"string","example":"2026-10-11"},"kind":{"type":"string","enum":["USAGE","MONEY"]},"totals":{"description":"Over every entry, not one page","allOf":[{"$ref":"#/components/schemas/CardActivityTotalsDto"}]},"byTier":{"type":"array","items":{"$ref":"#/components/schemas/CardTierTotalDto"}},"byPaymentMethod":{"description":"Top-ups and refunds only","type":"array","items":{"$ref":"#/components/schemas/CardMethodTotalDto"}},"entries":{"description":"Newest first","type":"array","items":{"$ref":"#/components/schemas/CardEntryDto"}},"meta":{"$ref":"#/components/schemas/PageMetaDto"}},"required":["from","to","kind","totals","byTier","byPaymentMethod","entries","meta"]},"KdsStationWithPrintersDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"locationId":{"type":"string","nullable":true,"example":"uuid"},"name":{"type":"string","example":"Hot line"},"displayColor":{"type":"string","nullable":true,"example":"#FF5733"},"printerIds":{"example":["uuid-printer-1","uuid-led-1"],"description":"The printers at this station, in the order they were added.","type":"array","items":{"type":"string"}},"printerId":{"type":"string","nullable":true,"example":"uuid","deprecated":true,"description":"The first of printerIds, for clients that expect one."},"routingRules":{"type":"object","description":"Routing rules: { categoryIds: string[] }","example":{"categoryIds":["uuid-1","uuid-2"]}},"deletedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.694Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:05.694Z"},"printers":{"description":"Every printer at the station, oldest first. A ticket goes to all of them.","type":"array","items":{"$ref":"#/components/schemas/StationPrinterDto"}},"printer":{"nullable":true,"deprecated":true,"description":"The first of printers, for clients that expect one.","allOf":[{"$ref":"#/components/schemas/StationPrinterDto"}]}},"required":["id","tenantId","name","printerIds","routingRules","createdAt","updatedAt","printers"]},"CounterOrderKdsTicketDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"sessionId":{"type":"string","nullable":true,"example":"uuid","description":"Set for dine-in tickets"},"salesOrderId":{"type":"string","nullable":true,"example":"uuid","description":"Set for counter/QSR tickets (no table session)"},"stationId":{"type":"string","example":"uuid"},"ticketNumber":{"type":"string","example":"KDS-20260506-0001"},"courseType":{"type":"string","nullable":true,"example":"MAIN"},"firedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.655Z"},"startedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"bumpedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"status":{"type":"string","nullable":true,"enum":["PENDING","PREPARING","READY","EXPEDITED"],"example":"PENDING"},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.655Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:06.655Z"},"sentById":{"type":"string","nullable":true,"example":"uuid","description":"The staff user who sent the order to the kitchen."},"sentFrom":{"type":"string","nullable":true,"example":"STAFF","description":"STAFF from a till, TABLET from a room tablet."},"deviceName":{"type":"string","nullable":true,"example":"Room 3 tablet","description":"The tablet's name, when a room tablet sent it."},"kdsTicketLines":{"type":"array","items":{"$ref":"#/components/schemas/KdsTicketLineEntity"}},"station":{"description":"The station the ticket was routed to, with the printers it prints at.","allOf":[{"$ref":"#/components/schemas/KdsStationWithPrintersDto"}]}},"required":["id","tenantId","stationId","ticketNumber","firedAt","createdAt","updatedAt","kdsTicketLines","station"]},"CounterOrderDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"customerId":{"type":"string","nullable":true,"example":"uuid"},"locationId":{"type":"string","nullable":true,"example":"uuid"},"orderNumber":{"type":"string","example":"SO-R01-20260728-0001"},"businessDate":{"type":"string","example":"2026-07-28"},"salesChannel":{"type":"string","example":"POS"},"serviceType":{"type":"string","nullable":true,"enum":["DINE_IN","TAKEAWAY","DELIVERY","COUNTER"],"example":"DINE_IN"},"posType":{"type":"string","enum":["BAR","SPA","KTV"],"example":"BAR","description":"Which POS sold it: SPA, KTV, or BAR for every other till and table."},"idempotencyKey":{"type":"string","nullable":true,"example":"idem-key-001"},"subtotal":{"type":"string","example":"100.0000"},"totalDiscount":{"type":"string","nullable":true,"example":"10.0000"},"discountReasonId":{"type":"string","nullable":true,"example":"uuid"},"totalTax":{"type":"string","nullable":true,"example":"5.0000"},"tipAmount":{"type":"string","example":"5.0000"},"serviceCharge":{"type":"string","example":"3.0000"},"serviceChargeTax":{"type":"string","example":"0.1500","description":"Tax on the service charge; part of totalTax."},"serviceChargeTaxes":{"type":"object","example":[{"taxRateId":"uuid","name":"Commercial Tax","ratePercentage":"0.05","taxAmount":"0.15"}],"description":"Each tax on the service charge."},"grandTotal":{"type":"string","example":"95.0000"},"status":{"type":"string","nullable":true,"example":"DRAFT","enum":["DRAFT","COMPLETED","ON_HOLD_CREDIT","VOIDED","PARTIALLY_REFUNDED","REFUNDED"]},"pickupNumber":{"type":"string","nullable":true,"example":"A47","description":"Display number for counter pickup"},"pickedUpAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-01-01T00:00:00.000Z"},"cashier":{"nullable":true,"description":"Who took the latest payment, to print as the cashier. Only on a single order.","allOf":[{"$ref":"#/components/schemas/CashierDto"}]},"salesOrderLines":{"type":"array","items":{"$ref":"#/components/schemas/SalesOrderLineEntity"}},"orderPayments":{"type":"array","items":{"$ref":"#/components/schemas/OrderPaymentEntity"}},"kdsTickets":{"type":"array","items":{"$ref":"#/components/schemas/CounterOrderKdsTicketDto"}}},"required":["id","tenantId","orderNumber","businessDate","salesChannel","posType","subtotal","tipAmount","serviceCharge","serviceChargeTax","serviceChargeTaxes","grandTotal","createdAt","updatedAt","salesOrderLines","orderPayments","kdsTickets"]},"MenuItemDto":{"type":"object","properties":{"variantId":{"type":"string","example":"uuid","description":"Send this as variantId when ordering."},"name":{"type":"string","example":"Myanmar Beer"},"price":{"type":"string","example":"3500.0000"},"imageUrl":{"type":"string","nullable":true,"example":"/uploads/..."},"isAvailable":{"type":"boolean","example":true,"description":"False = sold out for now. Show it muted; ordering it is refused."}},"required":["variantId","name","price","isAvailable"]},"MenuCategoryDto":{"type":"object","properties":{"categoryId":{"type":"string","example":"uuid"},"name":{"type":"string","example":"KTV Snacks"},"items":{"type":"array","items":{"$ref":"#/components/schemas/MenuItemDto"}}},"required":["categoryId","name","items"]},"RoomMenuDto":{"type":"object","properties":{"roomNumber":{"type":"string","example":"VIP1"},"categories":{"type":"array","items":{"$ref":"#/components/schemas/MenuCategoryDto"}}},"required":["roomNumber","categories"]},"RoomTabLineDto":{"type":"object","properties":{"name":{"type":"string","example":"Myanmar Beer"},"quantity":{"type":"string","example":"6.0000"},"unitPrice":{"type":"string","example":"3500.0000"},"lineTotal":{"type":"string","example":"21000.0000"},"status":{"type":"string","example":"PENDING","description":"PENDING and FIRED are still coming; SERVED has arrived."}},"required":["name","quantity","unitPrice","lineTotal","status"]},"RoomSessionViewDto":{"type":"object","properties":{"roomNumber":{"type":"string","example":"VIP1"},"guestCount":{"type":"number","example":6},"openedAt":{"format":"date-time","type":"string","example":"2026-09-22T20:00:00.000Z"},"endsAt":{"format":"date-time","type":"string","nullable":true,"example":"2026-09-22T23:00:00.000Z","description":"When the time the party asked for runs out. Null if they did not say. Paused time pushes it back."},"sessionState":{"type":"string","example":"OPEN"},"lines":{"description":"What is on the tab so far.","type":"array","items":{"$ref":"#/components/schemas/RoomTabLineDto"}},"fnbTotal":{"type":"string","example":"21000.0000","description":"Food and drink only. The room charge is added when they leave."},"walletBalance":{"type":"string","nullable":true,"example":"150000.0000","description":"What is left on the card the party is drawing on, or null if they are not using one. A postpaid card may be negative."}},"required":["roomNumber","guestCount","openedAt","sessionState","lines","fnbTotal"]},"SpaPackageIncludedItemDto":{"type":"object","properties":{"variantId":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Fresh orange juice"},"quantity":{"type":"number","example":1}},"required":["variantId","name","quantity"]},"SpaPackageEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Thai massage 90 min"},"description":{"type":"string","nullable":true,"example":null},"durationMinutes":{"type":"number","example":90},"price":{"type":"string","example":"45000.0000"},"isActive":{"type":"boolean","example":true},"variantId":{"type":"string","example":"uuid","description":"The variant the package bills against; its lines on a bill carry this id."},"items":{"type":"array","items":{"$ref":"#/components/schemas/SpaPackageIncludedItemDto"}},"createdAt":{"format":"date-time","type":"string","example":"2026-10-03T10:00:00.000Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-03T10:00:00.000Z"}},"required":["id","tenantId","name","durationMinutes","price","isActive","variantId","items","createdAt","updatedAt"]},"SpaPackageItemDto":{"type":"object","properties":{"variantId":{"type":"string","format":"uuid","example":"uuid","description":"A menu item variant, e.g. fresh juice."},"quantity":{"type":"number","minimum":1,"example":1,"default":1}},"required":["variantId"]},"CreateSpaPackageDto":{"type":"object","properties":{"name":{"type":"string","maxLength":100,"example":"Thai massage 90 min"},"description":{"type":"string","maxLength":500,"example":"Full body, with hot compress."},"durationMinutes":{"type":"number","minimum":1,"example":90,"description":"How long the treatment takes."},"price":{"type":"number","minimum":0,"example":45000,"description":"What the guest pays for the package."},"isActive":{"type":"boolean","example":true,"default":true},"items":{"maxItems":20,"description":"Menu items included in the price (\"+ juice\"). They go on the bill at 0 and to the kitchen. Makes it a room + menu package.","type":"array","items":{"$ref":"#/components/schemas/SpaPackageItemDto"}}},"required":["name","durationMinutes","price"]},"UpdateSpaPackageDto":{"type":"object","properties":{"name":{"type":"string","maxLength":100,"example":"Thai massage 90 min"},"description":{"type":"string","nullable":true,"maxLength":500,"example":"Full body, with hot compress."},"durationMinutes":{"type":"number","minimum":1,"example":90},"price":{"type":"number","minimum":0,"example":45000},"isActive":{"type":"boolean","example":true},"items":{"maxItems":20,"description":"Replaces the included items. Send [] to remove them all.","type":"array","items":{"$ref":"#/components/schemas/SpaPackageItemDto"}}}},"SpaRoomEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"locationId":{"type":"string","example":"uuid","description":"The spa outlet."},"roomNumber":{"type":"string","example":"S1"},"name":{"type":"object","example":"Lotus Room","nullable":true},"capacity":{"type":"number","example":1,"description":"How many guests the room takes."},"rateVariantId":{"type":"object","example":null,"nullable":true,"description":"Legacy: the variant whose price is one session of room time. Null for a room that is only a place, where the guest buys service packages."},"minimumMinutes":{"type":"number","example":60,"description":"Shortest treatment that can be charged."},"incrementMinutes":{"type":"number","example":60,"description":"One treatment. Time beyond the minimum sells in these blocks."},"graceMinutes":{"type":"number","example":15,"description":"Minutes past a block that are forgiven. Generous by default: a therapist finishing is not a guest overstaying."},"roundingMode":{"type":"string","enum":["UP","NEAREST","DOWN"],"example":"DOWN","description":"DOWN by default, unlike a KTV room. A treatment that runs over is still one treatment; rounding up would quietly double the bill."},"status":{"type":"string","enum":["AVAILABLE","OCCUPIED","CLEANING","OUT_OF_SERVICE"],"example":"AVAILABLE"},"deletedAt":{"type":"object","example":null,"nullable":true},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:07.586Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:07.586Z"}},"required":["id","tenantId","locationId","roomNumber","capacity","minimumMinutes","incrementMinutes","graceMinutes","roundingMode","status","createdAt","updatedAt"]},"CreateSpaRoomDto":{"type":"object","properties":{"locationId":{"type":"string","format":"uuid","example":"uuid","description":"The spa outlet."},"roomNumber":{"type":"string","maxLength":50,"example":"S1"},"name":{"type":"string","maxLength":100,"example":"Lotus Room"},"capacity":{"type":"number","minimum":1,"example":1,"description":"Guests the room takes."},"rateVariantId":{"type":"string","format":"uuid","example":"uuid","description":"Legacy: the variant whose price is one session of room time. Leave out - a SPA room is only a place, and guests buy service packages."},"sessionPrice":{"type":"number","minimum":0,"example":30000,"description":"Legacy: a price per session of room time. Leave out for a room where guests buy service packages (POST /v1/spa-packages)."},"minimumMinutes":{"type":"number","minimum":1,"example":60,"description":"Shortest chargeable treatment."},"incrementMinutes":{"type":"number","minimum":1,"example":60,"description":"One treatment. Usually the same as the minimum."},"graceMinutes":{"type":"number","minimum":0,"example":15,"description":"Minutes past a block that are forgiven."},"roundingMode":{"type":"string","enum":["UP","NEAREST","DOWN"],"example":"DOWN","description":"Leave as DOWN unless you mean to meter. A treatment that runs over is still one treatment; UP would charge for two."},"status":{"type":"string","enum":["AVAILABLE","OCCUPIED","CLEANING","OUT_OF_SERVICE"]}},"required":["locationId","roomNumber"]},"SpaBoardTherapistDto":{"type":"object","properties":{"userId":{"type":"string","example":"uuid"},"role":{"type":"string","nullable":true,"example":"LEAD","description":"Null when the room does not distinguish lead from assistant."}},"required":["userId"]},"SpaBoardSessionDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"openedAt":{"format":"date-time","type":"string","example":"2026-09-12T14:05:00.000Z"},"guestCount":{"type":"number","example":1},"sessionState":{"type":"string","enum":["OPEN","PAUSED","PAYMENT_PENDING","CLOSED"],"example":"OPEN"},"guestWalletId":{"type":"string","nullable":true,"example":"uuid","description":"The card the guest tapped when the treatment began. A till checks later taps against it."},"salesOrderId":{"type":"string","nullable":true,"example":"uuid","description":"The bill this session is building. Add items with POST /v1/sales-orders/{salesOrderId}/lines and pay with /v1/sales-orders/{salesOrderId}/settle."},"plannedMinutes":{"type":"number","nullable":true,"example":60,"description":"How long the treatment was booked for, in minutes."},"endsAt":{"format":"date-time","type":"string","nullable":true,"example":"2026-09-12T15:05:00.000Z","description":"When the booked time runs out, or null if none was given. Paused minutes push it back, so a treatment stopped for ten minutes gets them back."},"therapists":{"type":"array","items":{"$ref":"#/components/schemas/SpaBoardTherapistDto"}}},"required":["id","openedAt","guestCount","sessionState","therapists"]},"SpaRoomBoardDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"locationId":{"type":"string","example":"uuid","description":"The spa outlet."},"roomNumber":{"type":"string","example":"S1"},"name":{"type":"object","example":"Lotus Room","nullable":true},"capacity":{"type":"number","example":1,"description":"How many guests the room takes."},"rateVariantId":{"type":"object","example":null,"nullable":true,"description":"Legacy: the variant whose price is one session of room time. Null for a room that is only a place, where the guest buys service packages."},"minimumMinutes":{"type":"number","example":60,"description":"Shortest treatment that can be charged."},"incrementMinutes":{"type":"number","example":60,"description":"One treatment. Time beyond the minimum sells in these blocks."},"graceMinutes":{"type":"number","example":15,"description":"Minutes past a block that are forgiven. Generous by default: a therapist finishing is not a guest overstaying."},"roundingMode":{"type":"string","enum":["UP","NEAREST","DOWN"],"example":"DOWN","description":"DOWN by default, unlike a KTV room. A treatment that runs over is still one treatment; rounding up would quietly double the bill."},"status":{"type":"string","enum":["AVAILABLE","OCCUPIED","CLEANING","OUT_OF_SERVICE"],"example":"AVAILABLE"},"deletedAt":{"type":"object","example":null,"nullable":true},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:07.586Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:07.586Z"},"sessions":{"description":"Empty for a room that is free or being turned over. At most one entry in practice: a room holds one live treatment at a time.","type":"array","items":{"$ref":"#/components/schemas/SpaBoardSessionDto"}},"sessionPrice":{"type":"string","nullable":true,"example":null,"description":"Legacy price of one session of room time; null for a room priced by packages."},"rateProductId":{"type":"string","nullable":true,"example":null,"description":"Legacy: the product the room bills time against, so a menu can leave it out."}},"required":["id","tenantId","locationId","roomNumber","capacity","minimumMinutes","incrementMinutes","graceMinutes","roundingMode","status","createdAt","updatedAt","sessions"]},"UpdateSpaRoomDto":{"type":"object","properties":{"roomNumber":{"type":"string","maxLength":50,"example":"S1"},"name":{"type":"string","maxLength":100,"example":"Lotus Room"},"capacity":{"type":"number","minimum":1,"example":2},"rateVariantId":{"type":"string","format":"uuid","example":"uuid"},"sessionPrice":{"type":"number","minimum":0,"example":30000,"description":"Legacy: a price per session of room time. Leave out for a room where guests buy service packages (POST /v1/spa-packages)."},"minimumMinutes":{"type":"number","minimum":1,"example":60},"incrementMinutes":{"type":"number","minimum":1,"example":60},"graceMinutes":{"type":"number","minimum":0,"example":15},"roundingMode":{"type":"string","enum":["UP","NEAREST","DOWN"]},"status":{"type":"string","enum":["AVAILABLE","OCCUPIED","CLEANING","OUT_OF_SERVICE"]}}},"SpaSessionEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"roomId":{"type":"string","example":"uuid"},"guestCount":{"type":"number","example":1},"guestWalletId":{"type":"object","example":"uuid","nullable":true,"description":"The card the guest tapped when the treatment began, if any."},"openedAt":{"format":"date-time","type":"string","example":"2026-09-22T14:00:00.000Z"},"closedAt":{"type":"object","example":null,"nullable":true},"pausedMinutes":{"type":"number","example":0,"description":"Minutes the clock was stopped, deducted from the bill."},"pausedAt":{"type":"object","example":null,"nullable":true},"plannedMinutes":{"type":"object","example":60,"nullable":true,"description":"How long the treatment was booked for. Informational: the bill is still worked out from the clock, so this drives a countdown and nothing else."},"salesOrderId":{"type":"object","example":"uuid","nullable":true},"sessionState":{"type":"string","enum":["OPEN","PAUSED","PAYMENT_PENDING","CLOSED"],"example":"OPEN"},"posRegisterId":{"type":"object","example":"uuid","nullable":true},"openedByPosSessionId":{"type":"object","example":"uuid","nullable":true},"minimumMinutesSnapshot":{"type":"number","example":60},"incrementMinutesSnapshot":{"type":"number","example":60},"graceMinutesSnapshot":{"type":"number","example":15},"roundingModeSnapshot":{"type":"string","enum":["UP","NEAREST","DOWN"],"example":"DOWN"},"paymentTiming":{"type":"string","enum":["PAY_WHEN_ORDERING","PAY_AT_END"],"nullable":true,"description":"How this was paid, from Venue setup when it started: PAY_WHEN_ORDERING (each order by card) or PAY_AT_END (one bill, paid after close). Null on older sessions."},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:07.586Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:07.586Z"}},"required":["id","tenantId","roomId","guestCount","openedAt","pausedMinutes","sessionState","minimumMinutesSnapshot","incrementMinutesSnapshot","graceMinutesSnapshot","roundingModeSnapshot","createdAt","updatedAt"]},"TherapistAssignmentDto":{"type":"object","properties":{"userId":{"type":"string","format":"uuid","example":"uuid","description":"A staff user."},"role":{"type":"string","maxLength":50,"example":"lead","description":"Free text - \"lead\", \"assistant\". Left open until a property asks for something the spa actually distinguishes."}},"required":["userId"]},"SpaCardChargeDto":{"type":"object","properties":{"guestCardId":{"type":"string","format":"uuid","example":"uuid","description":"The card that was tapped. Left out to pay by cash or another way the venue takes, when rooms are not member card only."},"paymentMethodId":{"type":"string","format":"uuid","example":"uuid","description":"The guest-card payment method, or cash and the like."},"posSessionId":{"type":"string","format":"uuid","example":"uuid","description":"The till shift taking it."},"idempotencyKey":{"type":"string","maxLength":100,"example":"spa-charge-7c1…","description":"One per tap, so a retry after a lost response charges once."}},"required":["paymentMethodId"]},"SpaPackageOrderDto":{"type":"object","properties":{"packageId":{"type":"string","format":"uuid","example":"uuid"},"quantity":{"type":"number","minimum":1,"example":1,"default":1}},"required":["packageId"]},"SpaChargeItemDto":{"type":"object","properties":{"variantId":{"type":"string","format":"uuid","example":"uuid"},"quantity":{"type":"number","minimum":1,"example":2}},"required":["variantId","quantity"]},"OpenSpaSessionDto":{"type":"object","properties":{"roomId":{"type":"string","format":"uuid","example":"uuid"},"guestWalletId":{"type":"string","format":"uuid","example":"uuid","description":"The wallet behind the card the guest tapped. Recorded so a till can check later taps against it; paying is still a separate step at settle."},"guestCount":{"type":"number","minimum":1,"example":1},"plannedMinutes":{"type":"number","minimum":1,"example":60,"description":"How long the treatment is booked for. Drives the countdown only - the bill is still worked out from the clock."},"therapists":{"maxItems":10,"description":"Who is giving the treatment. Several is normal - four hands means two. Nothing stops a therapist appearing on more than one treatment at a time; that is a rota rule, not one this enforces.","type":"array","items":{"$ref":"#/components/schemas/TherapistAssignmentDto"}},"posRegisterId":{"type":"string","format":"uuid","example":"uuid"},"openedByPosSessionId":{"type":"string","format":"uuid","example":"uuid"},"salesChannel":{"type":"string","example":"POS"},"prepay":{"description":"Pay for what is booked now, from the tapped card. The treatment is then paid as it goes: extensions and add-ons are charged when ordered, and ending it charges nothing more. Needs `packages` (or, for a legacy priced room, `sessions`). Required when the venue takes payment when ordering; refused when it takes payment at the end (then `packages` and `items` go on the bill).","allOf":[{"$ref":"#/components/schemas/SpaCardChargeDto"}]},"roomCharges":{"maxItems":20,"description":"Room charges the cashier ticked (e.g. a sauna by the hour). Charges set to add automatically (e.g. a VIP room fee) are added without being sent.","type":"array","items":{"$ref":"#/components/schemas/PickedRoomChargeDto"}},"packages":{"maxItems":10,"description":"The service packages booked: paid with `prepay`, or put on the bill when the venue takes payment at the end. Their durations add up to the treatment's planned time; included menu items go to the kitchen.","type":"array","items":{"$ref":"#/components/schemas/SpaPackageOrderDto"}},"sessions":{"type":"number","minimum":1,"example":3,"description":"Legacy: sessions of room time, for a room that still has a price per session."},"items":{"maxItems":50,"description":"Food, drinks or add-ons ordered with the treatment: paid by the same tap, or put on the bill when the venue takes payment at the end.","type":"array","items":{"$ref":"#/components/schemas/SpaChargeItemDto"}}},"required":["roomId"]},"QuotedSpaSegmentDto":{"type":"object","properties":{"label":{"type":"string","example":"Standard"},"from":{"format":"date-time","type":"string","example":"2026-10-23T14:44:07.606Z"},"to":{"format":"date-time","type":"string","example":"2026-10-23T14:44:07.606Z"},"minutes":{"type":"number","example":62},"billableMinutes":{"type":"number","example":60},"hours":{"type":"string","example":"1.5000","description":"Billable time in hours, for display. Not what is charged."},"treatments":{"type":"string","example":"1.0000","description":"Billable time in treatments of the room's length - the line quantity. The rate buys one treatment, so a 90-minute room billed 90 minutes is 1."},"rate":{"type":"string","example":"45000.0000","description":"Price of one treatment in this rate window."},"amount":{"type":"string","example":"30000.0000"}},"required":["label","from","to","minutes","billableMinutes","hours","treatments","rate","amount"]},"SpaSessionQuoteDto":{"type":"object","properties":{"sessionId":{"type":"string","example":"uuid"},"roomId":{"type":"string","example":"uuid"},"roomNumber":{"type":"string","example":"S1"},"state":{"type":"string","enum":["OPEN","PAUSED","PAYMENT_PENDING","CLOSED"]},"openedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:07.607Z"},"asOf":{"format":"date-time","type":"string","example":"2026-10-23T14:44:07.607Z"},"elapsedMinutes":{"type":"number","example":62},"pausedMinutes":{"type":"number","example":0},"segments":{"type":"array","items":{"$ref":"#/components/schemas/QuotedSpaSegmentDto"}},"treatmentCharge":{"type":"string","example":"30000.0000","description":"The treatment itself."},"servicesCharge":{"type":"string","example":"8000.0000","description":"Add-on services already on the bill."},"runningTotal":{"type":"string","example":"38000.0000"},"prepaid":{"type":"boolean","example":false,"description":"True once the treatment is paid as it goes: its charges are then the paid lines, not the clock."},"paidTotal":{"type":"string","example":"38000.0000","description":"Taken from the card so far, net of refunds."},"paymentTiming":{"type":"string","nullable":true,"enum":["PAY_WHEN_ORDERING","PAY_AT_END"]},"salesOrderId":{"type":"string","nullable":true,"example":"uuid"},"amountDue":{"type":"string","example":"38000.0000","description":"Still to pay. With PAY_AT_END, settle it after close with POST /v1/sales-orders/{salesOrderId}/settle; a member card paying gets its tier discount off this. Zero once paid."},"cashier":{"nullable":true,"description":"Who took the latest payment on the bill, to print as the cashier.","allOf":[{"$ref":"#/components/schemas/CashierDto"}]},"orderNumber":{"type":"string","nullable":true,"example":"SO-R01-20261008-0012","description":"The bill’s order number, printed as the receipt number."}},"required":["sessionId","roomId","roomNumber","state","openedAt","asOf","elapsedMinutes","pausedMinutes","segments","treatmentCharge","servicesCharge","runningTotal","prepaid","paidTotal","paymentTiming","salesOrderId","amountDue"]},"SetTherapistsDto":{"type":"object","properties":{"therapists":{"maxItems":10,"description":"Replaces whoever was on the treatment. An empty list clears it.","type":"array","items":{"$ref":"#/components/schemas/TherapistAssignmentDto"}}},"required":["therapists"]},"SetSpaPlannedMinutesDto":{"type":"object","properties":{"plannedMinutes":{"type":"number","nullable":true,"minimum":1,"example":90,"description":"The new booked length in minutes, measured from when the treatment began - not an amount to add. Null clears the countdown."}},"required":["plannedMinutes"]},"SpaChargeResultDto":{"type":"object","properties":{"charged":{"type":"string","example":"12350.0000","description":"Taken from the card now. Zero when the venue takes payment at the end."},"addedToBill":{"type":"string","example":"12350.0000","description":"Put on the bill to pay at the end (PAY_AT_END)."},"balanceAfter":{"type":"string","example":"87650.0000","description":"The card balance after this charge or refund."},"quote":{"$ref":"#/components/schemas/SpaSessionQuoteDto"}},"required":["charged","balanceAfter","quote"]},"ExtendSpaSessionDto":{"type":"object","properties":{"guestCardId":{"type":"string","format":"uuid","example":"uuid","description":"The card that was tapped. Required when the venue takes payment when ordering."},"paymentMethodId":{"type":"string","format":"uuid","example":"uuid","description":"The guest-card payment method, or cash and the like with no card. Required when the venue takes payment when ordering."},"posSessionId":{"type":"string","format":"uuid","example":"uuid","description":"The till shift taking it."},"idempotencyKey":{"type":"string","maxLength":100,"example":"room-order-7c1…","description":"One per order sent, so a retry after a lost response charges or adds it once."},"packages":{"maxItems":10,"description":"More packages: paid now, or put on the bill when the venue takes payment at the end. Their durations extend the treatment.","type":"array","items":{"$ref":"#/components/schemas/SpaPackageOrderDto"}},"sessions":{"type":"number","minimum":1,"example":1,"description":"Legacy: sessions of room time, for a room with a price per session."}}},"ChargeSpaItemsDto":{"type":"object","properties":{"guestCardId":{"type":"string","format":"uuid","example":"uuid","description":"The card that was tapped. Required when the venue takes payment when ordering."},"paymentMethodId":{"type":"string","format":"uuid","example":"uuid","description":"The guest-card payment method, or cash and the like with no card. Required when the venue takes payment when ordering."},"posSessionId":{"type":"string","format":"uuid","example":"uuid","description":"The till shift taking it."},"idempotencyKey":{"type":"string","maxLength":100,"example":"room-order-7c1…","description":"One per order sent, so a retry after a lost response charges or adds it once."},"items":{"minItems":1,"maxItems":50,"description":"Priced on the server, from the catalogue; the till sends no prices.","type":"array","items":{"$ref":"#/components/schemas/SpaChargeItemDto"}}},"required":["items"]},"GiveFreeItemsDto":{"type":"object","properties":{"items":{"minItems":1,"maxItems":50,"description":"What the house gives. Nothing is charged to any card.","type":"array","items":{"$ref":"#/components/schemas/SpaChargeItemDto"}},"compReasonId":{"type":"string","format":"uuid","example":"uuid","description":"Why it is free: a saved discount reason. Give this or reason."},"reason":{"type":"string","maxLength":100,"example":"Birthday","description":"Why it is free, as typed. Matched to a discount reason of the same name, or saved as a new one so reports can group by it."}},"required":["items"]},"RefundSpaLineDto":{"type":"object","properties":{"reason":{"type":"string","maxLength":200,"example":"Wrong item tapped"}}},"CloseSpaSessionDto":{"type":"object","properties":{"closedAt":{"type":"string","example":"2026-09-22T15:05:00.000Z","description":"Defaults to now. Cannot be before the treatment began."},"tip":{"description":"A tip, when the room was paid as it went: charged now and added to the bill. A bill paid at the end takes its tip when it is settled.","allOf":[{"$ref":"#/components/schemas/RoomTipDto"}]}}},"TabletGuestDto":{"type":"object","properties":{"displayName":{"type":"string","example":"Daw Hla H."},"tier":{"type":"string","example":"Black"},"discountPercent":{"type":"number","example":15},"isPostpaid":{"type":"boolean","example":true},"balance":{"type":"string","example":"-96500.0000"}},"required":["displayName","tier","discountPercent","isPostpaid","balance"]},"TabletOrderItemDto":{"type":"object","properties":{"name":{"type":"string","example":"Ginger tea"},"quantity":{"type":"number","example":2},"refunded":{"type":"boolean","example":false}},"required":["name","quantity","refunded"]},"TabletVisitOrderDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"orderNumber":{"type":"number","example":3},"kind":{"type":"string","example":"ITEMS","enum":["ITEMS","SESSIONS"]},"source":{"type":"string","example":"TABLET","enum":["TABLET","STAFF"]},"amount":{"type":"string","example":"12150.0000"},"placedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:07.648Z"},"status":{"type":"string","example":"PREPARING","enum":["RECEIVED","PREPARING","READY","SERVED","REFUNDED"]},"items":{"type":"array","items":{"$ref":"#/components/schemas/TabletOrderItemDto"}}},"required":["id","orderNumber","kind","source","amount","placedAt","status","items"]},"TabletVisitRoomDto":{"type":"object","properties":{"kind":{"type":"string","example":"SPA","enum":["SPA","KTV"]},"sessionId":{"type":"string","example":"uuid"},"roomId":{"type":"string","example":"uuid"},"roomNumber":{"type":"string","example":"S2"},"roomName":{"type":"string","nullable":true,"example":"Orchid Room"},"sessionState":{"type":"string","example":"OPEN"},"openedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:07.649Z"},"plannedMinutes":{"type":"number","nullable":true,"example":120},"sessionMinutes":{"type":"number","example":60,"description":"Length of one session; 60 for a KTV room, sold by the hour."},"sessionPrice":{"type":"string","nullable":true,"example":"45000.0000","description":"List price of one more session, before the tier discount."},"endsAt":{"format":"date-time","type":"string","nullable":true,"example":"2026-10-23T14:44:07.649Z"},"prepaid":{"type":"boolean","example":true,"description":"Paid as it goes; only these rooms take orders from the tablet."},"spent":{"type":"string","example":"91350.0000"},"orders":{"type":"array","items":{"$ref":"#/components/schemas/TabletVisitOrderDto"}}},"required":["kind","sessionId","roomId","roomNumber","sessionState","openedAt","sessionMinutes","prepaid","spent","orders"]},"TabletVisitDto":{"type":"object","properties":{"guest":{"$ref":"#/components/schemas/TabletGuestDto"},"rooms":{"type":"array","items":{"$ref":"#/components/schemas/TabletVisitRoomDto"}}},"required":["guest","rooms"]},"TabletCardDto":{"type":"object","properties":{"cardUid":{"type":"string","maxLength":64,"example":"04C9D1E7","description":"The UID the tablet read from the card. Sent in the body, never the URL, so it stays out of access logs."}},"required":["cardUid"]},"TabletHistoryEntryDto":{"type":"object","properties":{"type":{"type":"string","example":"SPEND"},"amount":{"type":"string","example":"-12150.0000"},"balanceAfter":{"type":"string","example":"87850.0000"},"note":{"type":"string","nullable":true,"example":"Room S2: order"},"at":{"format":"date-time","type":"string","example":"2026-10-23T14:44:07.650Z"}},"required":["type","amount","balanceAfter","at"]},"TabletMenuItemDto":{"type":"object","properties":{"variantId":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Ginger tea"},"price":{"type":"string","example":"3500.0000"},"imageUrl":{"type":"string","nullable":true},"isAvailable":{"type":"boolean","example":true,"description":"False = sold out for now. Show it muted; ordering it is refused."}},"required":["variantId","name","price","isAvailable"]},"TabletMenuCategoryDto":{"type":"object","properties":{"categoryId":{"type":"string","example":"uuid"},"name":{"type":"string","example":"Soft Drinks"},"items":{"type":"array","items":{"$ref":"#/components/schemas/TabletMenuItemDto"}}},"required":["categoryId","name","items"]},"TabletMenuDto":{"type":"object","properties":{"categories":{"type":"array","items":{"$ref":"#/components/schemas/TabletMenuCategoryDto"}}},"required":["categories"]},"TabletOrderResultDto":{"type":"object","properties":{"charged":{"type":"string","example":"12150.0000"},"balanceAfter":{"type":"string","example":"87850.0000"},"orderNumber":{"type":"number","nullable":true,"example":4}},"required":["charged","balanceAfter"]},"TabletOrderDto":{"type":"object","properties":{"cardUid":{"type":"string","maxLength":64,"example":"04C9D1E7","description":"The UID the tablet read from the card. Sent in the body, never the URL, so it stays out of access logs."},"sessionId":{"type":"string","format":"uuid","example":"uuid","description":"The treatment ordering for."},"items":{"minItems":1,"maxItems":50,"type":"array","items":{"$ref":"#/components/schemas/SpaChargeItemDto"}},"idempotencyKey":{"type":"string","maxLength":100,"example":"tablet-7c1…","description":"One per tap."},"deviceName":{"type":"string","maxLength":100,"example":"Spa lounge tablet 1"}},"required":["cardUid","sessionId","items","idempotencyKey"]},"TabletExtendDto":{"type":"object","properties":{"cardUid":{"type":"string","maxLength":64,"example":"04C9D1E7","description":"The UID the tablet read from the card. Sent in the body, never the URL, so it stays out of access logs."},"sessionId":{"type":"string","format":"uuid","example":"uuid"},"sessions":{"type":"number","minimum":1,"example":1,"description":"Sessions for a spa room; hours for a KTV room."},"idempotencyKey":{"type":"string","maxLength":100,"example":"tablet-7c1…"},"deviceName":{"type":"string","maxLength":100,"example":"Spa lounge tablet 1"}},"required":["cardUid","sessionId","sessions","idempotencyKey"]},"TabletRoomDto":{"type":"object","properties":{"kind":{"type":"string","example":"SPA","enum":["SPA","KTV"]},"roomId":{"type":"string","example":"uuid"},"roomNumber":{"type":"string","example":"S2"},"name":{"type":"string","nullable":true,"example":"Orchid Room"},"treatment":{"type":"string","nullable":true,"example":"Aroma Massage 60 min"},"sessionMinutes":{"type":"number","example":60},"sessionPrice":{"type":"string","nullable":true,"example":"30000.0000"},"status":{"type":"string","example":"AVAILABLE","enum":["AVAILABLE","IN_USE","OCCUPIED","CLEANING","OUT_OF_SERVICE"]},"available":{"type":"boolean","example":true},"endsAt":{"format":"date-time","type":"string","nullable":true,"example":"2026-10-23T14:44:07.655Z"}},"required":["kind","roomId","roomNumber","sessionMinutes","status","available"]},"TabletStartResultDto":{"type":"object","properties":{"sessionId":{"type":"string","example":"uuid"},"charged":{"type":"string","example":"76500.0000"},"balanceAfter":{"type":"string","example":"23500.0000"}},"required":["sessionId","charged","balanceAfter"]},"TabletStartDto":{"type":"object","properties":{"cardUid":{"type":"string","maxLength":64,"example":"04C9D1E7","description":"The UID the tablet read from the card. Sent in the body, never the URL, so it stays out of access logs."},"roomId":{"type":"string","format":"uuid","example":"uuid","description":"The room this tablet belongs to."},"sessions":{"type":"number","minimum":1,"example":2,"description":"Sessions for a spa room; hours for a KTV room."},"guestCount":{"type":"number","minimum":1,"example":1},"items":{"maxItems":50,"type":"array","items":{"$ref":"#/components/schemas/SpaChargeItemDto"}},"idempotencyKey":{"type":"string","maxLength":100,"example":"tablet-7c1…"},"deviceName":{"type":"string","maxLength":100,"example":"S2 tablet"}},"required":["cardUid","roomId","sessions","idempotencyKey"]},"RoomOrderItemDto":{"type":"object","properties":{"name":{"type":"string","example":"Ginger tea"},"quantity":{"type":"number","example":2},"status":{"type":"string","example":"FIRED"}},"required":["name","quantity","status"]},"RoomOrderViewDto":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"orderNumber":{"type":"number","example":3},"source":{"type":"string","example":"TABLET","enum":["TABLET","STAFF"]},"kind":{"type":"string","example":"ITEMS","enum":["ITEMS","SESSIONS"]},"roomNumber":{"type":"string","example":"S2"},"roomName":{"type":"string","nullable":true,"example":"Orchid Room"},"roomKind":{"type":"string","example":"SPA","enum":["SPA","KTV"]},"spaSessionId":{"type":"string","nullable":true,"example":"uuid"},"ktvSessionId":{"type":"string","nullable":true,"example":null},"amount":{"type":"string","example":"12150.0000"},"deviceName":{"type":"string","nullable":true,"example":"Spa lounge tablet 1"},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:07.625Z"},"acknowledgedAt":{"format":"date-time","type":"string","nullable":true},"deliveredAt":{"format":"date-time","type":"string","nullable":true},"printClaimedAt":{"format":"date-time","type":"string","nullable":true},"items":{"type":"array","items":{"$ref":"#/components/schemas/RoomOrderItemDto"}}},"required":["id","orderNumber","source","kind","roomNumber","roomKind","amount","createdAt","items"]},"RoomOrderPrintClaimDto":{"type":"object","properties":{"claimed":{"type":"boolean","example":true,"description":"True for the one terminal that should print this ticket."},"order":{"$ref":"#/components/schemas/RoomOrderViewDto"}},"required":["claimed","order"]},"PrintHeaderSettingsDto":{"type":"object","properties":{"logo":{"type":"boolean","example":true},"outletName":{"type":"boolean","example":true},"address":{"type":"boolean","example":true},"contact":{"type":"boolean","example":true,"description":"Phone number."},"email":{"type":"boolean","example":true,"description":"Email address."}}},"PrintItemSettingsDto":{"type":"object","properties":{"bilingual":{"type":"boolean","example":false,"description":"Print the second-language name under the first."},"fontSize":{"type":"string","enum":["SMALL","MIDDLE","LARGE"],"example":"MIDDLE"},"qtyFirst":{"type":"boolean","example":true,"description":"\"x2 Fried Rice\" rather than \"Fried Rice x2\"."},"categorySubtotal":{"type":"boolean","example":false},"hidePriceOnOrderBill":{"type":"boolean","example":false,"description":"Leave prices off the ORDER_RECEIPT copy."},"itemTextScale":{"type":"string","enum":["1H1W","1H2W","2H1W","2H2W"],"example":"1H1W","description":"Item line magnification, height x width."},"otherTextScale":{"type":"string","enum":["1H1W","1H2W","2H1W","2H2W"],"example":"1H1W","description":"Magnification for modifiers, remarks and sub-items."},"productRemarks":{"type":"boolean","example":true},"modifiers":{"type":"boolean","example":true},"price":{"type":"boolean","example":true}}},"PrintBillSettingsDto":{"type":"object","properties":{"amountAfterDiscount":{"type":"boolean","example":true},"totalPayment":{"type":"boolean","example":true},"payTime":{"type":"boolean","example":false},"rounding":{"type":"boolean","example":false}}},"PrintOtherSettingsDto":{"type":"object","properties":{"orderNumber":{"type":"boolean","example":true},"cashier":{"type":"boolean","example":true},"serviceType":{"type":"boolean","example":true,"description":"Dine in, takeaway..."},"tableOrRoom":{"type":"boolean","example":true,"description":"The table, KTV room or spa room the order belongs to."},"pickupCode":{"type":"boolean","example":false},"footerText":{"type":"string","nullable":true,"maxLength":500,"example":"Thank you!","description":"Printed at the bottom. Null prints nothing."}}},"PrintTemplateSettingsDto":{"type":"object","properties":{"language":{"type":"string","enum":["FOLLOW_POS","EN","MY"],"example":"FOLLOW_POS"},"copies":{"type":"array","enum":["ORDER_RECEIPT","CUSTOMER","FINANCE"],"minItems":1,"example":["CUSTOMER"],"description":"Which copies print at checkout, each titled with its own name. ORDER_RECEIPT goes to the floor, CUSTOMER to the guest, FINANCE to the office.","items":{"type":"string","enum":["ORDER_RECEIPT","CUSTOMER","FINANCE"]}},"header":{"$ref":"#/components/schemas/PrintHeaderSettingsDto"},"item":{"$ref":"#/components/schemas/PrintItemSettingsDto"},"bill":{"description":"Ignored on KITCHEN templates, which print no money.","allOf":[{"$ref":"#/components/schemas/PrintBillSettingsDto"}]},"other":{"$ref":"#/components/schemas/PrintOtherSettingsDto"}}},"TemplateFieldDto":{"type":"object","properties":{"path":{"type":"string","example":"item.price","description":"Where the switch sits in settings, dot-separated."},"kind":{"type":"string","enum":["boolean","enum","enum[]","text"],"example":"boolean","description":"boolean: on/off. enum: one of options. enum[]: any of options. text: free text or null."},"options":{"example":["SMALL","MIDDLE","LARGE"],"type":"array","items":{"type":"string"}},"default":{"type":"object","example":true,"description":"The type's built-in value for this switch."},"description":{"type":"string","example":"Prices on item lines."}},"required":["path","kind","default","description"]},"PrintTemplateEntity":{"type":"object","properties":{"id":{"type":"string","example":"uuid"},"tenantId":{"type":"string","example":"uuid"},"locationId":{"type":"string","nullable":true,"example":"uuid","description":"Null for a template that covers every outlet."},"type":{"type":"string","enum":["RECEIPT","KITCHEN","FINANCE","SHIFT"],"example":"RECEIPT","description":"RECEIPT: the guest bill at checkout. KITCHEN: a KDS station ticket. FINANCE: the office copy of a bill. SHIFT: the end-of-shift report."},"name":{"type":"string","example":"Default receipt"},"paperWidth":{"type":"string","enum":["MM58","MM80"],"example":"MM80"},"isDefault":{"type":"boolean","example":true},"settings":{"description":"Always complete - every switch is present.","allOf":[{"$ref":"#/components/schemas/PrintTemplateSettingsDto"}]},"fields":{"description":"The switches that apply to this type, in display order. settings still carries every switch; the ones not listed here hold the type's default and cannot be changed.","type":"array","items":{"$ref":"#/components/schemas/TemplateFieldDto"}},"deletedAt":{"format":"date-time","type":"string","nullable":true,"example":null},"createdAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:07.687Z"},"updatedAt":{"format":"date-time","type":"string","example":"2026-10-23T14:44:07.687Z"}},"required":["id","tenantId","type","name","paperWidth","isDefault","settings","fields","createdAt","updatedAt"]},"CreatePrintTemplateDto":{"type":"object","properties":{"type":{"type":"string","enum":["RECEIPT","KITCHEN","FINANCE","SHIFT"],"example":"RECEIPT","description":"RECEIPT: the guest bill at checkout. KITCHEN: a KDS station ticket. FINANCE: the office copy of a bill. SHIFT: the end-of-shift report."},"name":{"type":"string","maxLength":100,"example":"Default receipt"},"locationId":{"type":"string","format":"uuid","example":"uuid","description":"The outlet this is for. Leave out for every outlet."},"paperWidth":{"type":"string","enum":["MM58","MM80"],"example":"MM80"},"isDefault":{"type":"boolean","example":true,"description":"Make this the one that prints. Replaces the current default for the same outlet and type."},"settings":{"description":"Anything left out takes the built-in default for the type.","allOf":[{"$ref":"#/components/schemas/PrintTemplateSettingsDto"}]}},"required":["type","name"]},"ResolvedPrintTemplateDto":{"type":"object","properties":{"id":{"type":"string","nullable":true,"example":"uuid","description":"Null when nothing is set up and the built-in layout applies."},"source":{"type":"string","enum":["LOCATION","TENANT","BUILT_IN"],"example":"LOCATION","description":"LOCATION: the outlet's own default. TENANT: the default for every outlet. BUILT_IN: nothing is set up; these are the factory settings."},"type":{"type":"string","enum":["RECEIPT","KITCHEN","FINANCE","SHIFT"],"example":"RECEIPT","description":"RECEIPT: the guest bill at checkout. KITCHEN: a KDS station ticket. FINANCE: the office copy of a bill. SHIFT: the end-of-shift report."},"name":{"type":"string","example":"Default receipt"},"paperWidth":{"type":"string","enum":["MM58","MM80"],"example":"MM80"},"settings":{"$ref":"#/components/schemas/PrintTemplateSettingsDto"},"fields":{"description":"The switches that apply to this type, in display order. settings still carries every switch; the ones not listed here hold the type's default and cannot be changed.","type":"array","items":{"$ref":"#/components/schemas/TemplateFieldDto"}}},"required":["source","type","name","paperWidth","settings","fields"]},"UpdatePrintTemplateDto":{"type":"object","properties":{"name":{"type":"string","maxLength":100,"example":"Default receipt"},"paperWidth":{"type":"string","enum":["MM58","MM80"],"example":"MM80"},"isDefault":{"type":"boolean","example":true,"description":"Make this the one that prints. Replaces the current default for the same outlet and type."},"settings":{"description":"Anything left out takes the built-in default for the type.","allOf":[{"$ref":"#/components/schemas/PrintTemplateSettingsDto"}]}}}}}}