Compare commits
96 Commits
ee0eb2820e
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2a45b43f50 | ||
|
|
9f61c7dee2 | ||
|
|
980578e1e4 | ||
|
|
ce4dc15aac | ||
|
|
da785da2dd | ||
|
|
24563964a6 | ||
|
|
44e91a6973 | ||
|
|
de2957acf1 | ||
|
|
17df88ced5 | ||
|
|
d3209d73c1 | ||
|
|
518106ede2 | ||
|
|
833cee5040 | ||
|
|
aeb79c1acb | ||
|
|
ff185a59dd | ||
|
|
689f12ba69 | ||
|
|
bf081f875d | ||
|
|
8f9c941699 | ||
|
|
e6c15dd053 | ||
|
|
8a5a307c50 | ||
|
|
43d7049a7b | ||
|
|
c60b899c4d | ||
|
|
e8a5322775 | ||
|
|
cb30352b57 | ||
|
|
5d6b31de15 | ||
|
|
8827d6fc14 | ||
|
|
16f70603bc | ||
|
|
ce7f5aad2a | ||
|
|
26adfc5aa9 | ||
|
|
0480a5dcbe | ||
|
|
dd5c9646b3 | ||
|
|
5a0b603306 | ||
|
|
72d05a34d0 | ||
|
|
8fece9d916 | ||
|
|
5fac537268 | ||
|
|
61529023b0 | ||
|
|
2df7c59feb | ||
|
|
02301ff172 | ||
|
|
ab6fcc107f | ||
|
|
bc1340419c | ||
|
|
fbe3105dc9 | ||
|
|
e82ea15d02 | ||
|
|
527e55fec2 | ||
|
|
e1d27b44a7 | ||
|
|
a7258abf35 | ||
|
|
1b432cb6c6 | ||
|
|
0303f8121c | ||
|
|
d151bb5fe3 | ||
|
|
676a40d4fe | ||
|
|
005b48ff66 | ||
|
|
72e6e79d20 | ||
|
|
6a80473594 | ||
|
|
bcdfba1742 | ||
|
|
907ee998c0 | ||
|
|
158748c5e6 | ||
|
|
dc9fcdad96 | ||
|
|
116b51f0a9 | ||
|
|
c937bad151 | ||
|
|
1881830b0a | ||
|
|
01d6aa0e3f | ||
|
|
ff73750092 | ||
|
|
e7884c03ef | ||
|
|
1c5385061c | ||
|
|
1ac6435c3f | ||
|
|
80ecad6ddd | ||
|
|
97cae698db | ||
|
|
88ed2be452 | ||
|
|
b3368a53f8 | ||
|
|
e490ad78b5 | ||
|
|
41c532e2ca | ||
|
|
b6f68f04a4 | ||
|
|
2cc166bbec | ||
|
|
2dea4e86f1 | ||
|
|
74d3ba5aeb | ||
|
|
69388c789f | ||
|
|
a5a9e51898 | ||
|
|
5d6d07e8bf | ||
|
|
fb2dafd920 | ||
|
|
c07e4dc083 | ||
|
|
369fbb2a70 | ||
|
|
464021318a | ||
|
|
9929e322a3 | ||
|
|
ebbeb6437a | ||
|
|
3f2bdce5ad | ||
|
|
1a5e3f23e2 | ||
|
|
e83116c83d | ||
|
|
7fcaca318a | ||
|
|
76235b0e1f | ||
|
|
a6cb52e415 | ||
|
|
36a135011f | ||
|
|
a27f507138 | ||
|
|
e83be2ca21 | ||
|
|
1a0023b775 | ||
|
|
1aa1582682 | ||
|
|
be834412e7 | ||
|
|
5be5644329 | ||
|
|
ada4d93f65 |
17
.dockerignore
Normal file
17
.dockerignore
Normal file
@@ -0,0 +1,17 @@
|
||||
node_modules/*
|
||||
!node_modules/better-sqlite3
|
||||
!node_modules/canvas
|
||||
!node_modules/@img
|
||||
!node_modules/sharp
|
||||
dist/*
|
||||
!dist/dashback
|
||||
data
|
||||
certs
|
||||
.git
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
*.log
|
||||
docs/api
|
||||
scratch
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
# Server
|
||||
# Host interface to listen on (defaults to 127.0.0.1 for local only, use 0.0.0.0 for all network interfaces)
|
||||
HOST=127.0.0.1
|
||||
PORT=4208
|
||||
# HTTPS server port (defaults to 8443, set to 0 or false to disable)
|
||||
HTTPS_PORT=8443
|
||||
@@ -15,6 +17,7 @@ CORS_ORIGINS=http://localhost:5173
|
||||
# Auth — Google OAuth client ID and JWT signing secret
|
||||
GOOGLE_CLIENT_ID=
|
||||
JWT_SECRET=fallback_secret_please_change_in_production
|
||||
# Auto-create user on first login (when false, only allowlisted or invited emails can sign in / create an account)
|
||||
IMPLICIT_CREATE=false
|
||||
|
||||
# Database Provider — 'sqlite' or 'mssql' (defaults to 'mssql', or 'sqlite' if SQLITE_PATH is set)
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,3 +5,4 @@ logs/
|
||||
print_spool/
|
||||
certs/
|
||||
output/
|
||||
dist/
|
||||
|
||||
25
Dockerfile
Normal file
25
Dockerfile
Normal file
@@ -0,0 +1,25 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
FROM debian:12-slim AS syslibs
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
libatomic1 libuuid1 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
FROM gcr.io/distroless/cc-debian12
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Shared dynamic libraries needed by Node.js SEA and native addons (better-sqlite3)
|
||||
COPY --from=syslibs /usr/lib/x86_64-linux-gnu/libatomic.so* /usr/lib/x86_64-linux-gnu/
|
||||
COPY --from=syslibs /usr/lib/x86_64-linux-gnu/libuuid.so* /usr/lib/x86_64-linux-gnu/
|
||||
|
||||
# Set production defaults: port 4208
|
||||
ENV RUNNING_IN_DOCKER=true \
|
||||
NODE_ENV=production \
|
||||
HOST=0.0.0.0 \
|
||||
PORT=4208 \
|
||||
HTTPS_PORT=0 \
|
||||
SQLITE_PATH=/app/data/dash.db \
|
||||
STORAGE_DIR=/app/data/storage \
|
||||
BACKUP_DIR=/app/data/backups
|
||||
|
||||
CMD ["./dist/dashback"]
|
||||
@@ -37,6 +37,15 @@ Generated from `@openapi` annotations in [`src/api/routes/`](../../src/api/route
|
||||
| [`routes/account.get.md`](routes/account.get.md) | `GET /account` |
|
||||
| [`routes/account.post.md`](routes/account.post.md) | `POST /account` |
|
||||
| [`routes/account/_id.md`](routes/account/_id.md) | `DELETE /account/{id}` |
|
||||
| [`routes/agent/events.md`](routes/agent/events.md) | `GET /agent/events` |
|
||||
| [`routes/agent/pair.get.md`](routes/agent/pair.get.md) | `GET /agent/pair` |
|
||||
| [`routes/agent/pair.post.md`](routes/agent/pair.post.md) | `POST /agent/pair` |
|
||||
| [`routes/agent/state.md`](routes/agent/state.md) | `POST /agent/state` |
|
||||
| [`routes/agentprinter.md`](routes/agentprinter.md) | `GET /agentprinter` |
|
||||
| [`routes/agentprinter/order.md`](routes/agentprinter/order.md) | `PUT /agentprinter/order` |
|
||||
| [`routes/agentprinter/_id.delete.md`](routes/agentprinter/_id.delete.md) | `DELETE /agentprinter/{id}` |
|
||||
| [`routes/agentprinter/_id.get.md`](routes/agentprinter/_id.get.md) | `GET /agentprinter/{id}` |
|
||||
| [`routes/agentprinter/_id.patch.md`](routes/agentprinter/_id.patch.md) | `PATCH /agentprinter/{id}` |
|
||||
| [`routes/article/create.md`](routes/article/create.md) | `POST /article` |
|
||||
| [`routes/article/export.zip.md`](routes/article/export.zip.md) | `GET /article/export.zip` |
|
||||
| [`routes/article/history-list.md`](routes/article/history-list.md) | `GET /article/history` |
|
||||
@@ -89,6 +98,9 @@ Generated from `@openapi` annotations in [`src/api/routes/`](../../src/api/route
|
||||
| [`routes/auth/logout.md`](routes/auth/logout.md) | `POST /auth/logout` |
|
||||
| [`routes/auth/me.md`](routes/auth/me.md) | `GET /auth/me` |
|
||||
| [`routes/auth/selected-company.md`](routes/auth/selected-company.md) | `PUT /auth/selected-company` |
|
||||
| [`routes/autoinvite/list.md`](routes/autoinvite/list.md) | `GET /autoinvite` |
|
||||
| [`routes/autoinvite/create.md`](routes/autoinvite/create.md) | `POST /autoinvite` |
|
||||
| [`routes/autoinvite/delete.md`](routes/autoinvite/delete.md) | `DELETE /autoinvite/{id}` |
|
||||
| [`routes/backup.md`](routes/backup.md) | `GET /backup` |
|
||||
| [`routes/backup/_id/vfs.md`](routes/backup/_id/vfs.md) | `GET /backup/{id}/vfs` |
|
||||
| [`routes/backup/_id/vfs/recover.md`](routes/backup/_id/vfs/recover.md) | `POST /backup/{id}/vfs/recover` |
|
||||
@@ -115,6 +127,7 @@ Generated from `@openapi` annotations in [`src/api/routes/`](../../src/api/route
|
||||
| [`routes/category/_id/attributevalue.put.md`](routes/category/_id/attributevalue.put.md) | `PUT /category/{id}/attributevalue` |
|
||||
| [`routes/category/delete-image.md`](routes/category/delete-image.md) | `DELETE /category/{id}/image` |
|
||||
| [`routes/category/add-image.md`](routes/category/add-image.md) | `POST /category/{id}/image` |
|
||||
| [`routes/category/_id/image/generate.md`](routes/category/_id/image/generate.md) | `POST /category/{id}/image/generate` |
|
||||
| [`routes/category/_id/property.get.md`](routes/category/_id/property.get.md) | `GET /category/{id}/property` |
|
||||
| [`routes/category/_id/property.put.md`](routes/category/_id/property.put.md) | `PUT /category/{id}/property` |
|
||||
| [`routes/category/_id/property/_propertyId.md`](routes/category/_id/property/_propertyId.md) | `DELETE /category/{id}/property/{propertyId}` |
|
||||
@@ -130,6 +143,10 @@ Generated from `@openapi` annotations in [`src/api/routes/`](../../src/api/route
|
||||
| [`routes/companysetting/set.md`](routes/companysetting/set.md) | `PUT /company/setting/{key}` |
|
||||
| [`routes/company/delete.md`](routes/company/delete.md) | `DELETE /company/{id}` |
|
||||
| [`routes/company/update.md`](routes/company/update.md) | `PUT /company/{id}` |
|
||||
| [`routes/companyuser/list.md`](routes/companyuser/list.md) | `GET /companyuser` |
|
||||
| [`routes/companyuser/create.md`](routes/companyuser/create.md) | `POST /companyuser` |
|
||||
| [`routes/companyuser/delete.md`](routes/companyuser/delete.md) | `DELETE /companyuser/{id}` |
|
||||
| [`routes/companyuser/update.md`](routes/companyuser/update.md) | `PATCH /companyuser/{id}` |
|
||||
| [`routes/customergroup/list.md`](routes/customergroup/list.md) | `GET /customergroup` |
|
||||
| [`routes/customergroup/create.md`](routes/customergroup/create.md) | `POST /customergroup` |
|
||||
| [`routes/customergroup/order.md`](routes/customergroup/order.md) | `PUT /customergroup/order` |
|
||||
@@ -163,6 +180,7 @@ Generated from `@openapi` annotations in [`src/api/routes/`](../../src/api/route
|
||||
| [`routes/image/get.md`](routes/image/get.md) | `GET /image/{fullHash}` |
|
||||
| [`routes/labeltemplate/list.md`](routes/labeltemplate/list.md) | `GET /labeltemplate` |
|
||||
| [`routes/labeltemplate/create.md`](routes/labeltemplate/create.md) | `POST /labeltemplate` |
|
||||
| [`routes/labeltemplate/testprint.md`](routes/labeltemplate/testprint.md) | `POST /labeltemplate/testprint` |
|
||||
| [`routes/labeltemplate/delete.md`](routes/labeltemplate/delete.md) | `DELETE /labeltemplate/{id}` |
|
||||
| [`routes/labeltemplate/get.md`](routes/labeltemplate/get.md) | `GET /labeltemplate/{id}` |
|
||||
| [`routes/labeltemplate/update.md`](routes/labeltemplate/update.md) | `PATCH /labeltemplate/{id}` |
|
||||
@@ -218,10 +236,22 @@ Generated from `@openapi` annotations in [`src/api/routes/`](../../src/api/route
|
||||
| [`routes/printer/list.md`](routes/printer/list.md) | `GET /printer` |
|
||||
| [`routes/printer/create.md`](routes/printer/create.md) | `POST /printer` |
|
||||
| [`routes/printer/order.md`](routes/printer/order.md) | `PUT /printer/order` |
|
||||
| [`routes/printer/state.md`](routes/printer/state.md) | `GET /printer/state` |
|
||||
| [`routes/printer/delete.md`](routes/printer/delete.md) | `DELETE /printer/{id}` |
|
||||
| [`routes/printer/get.md`](routes/printer/get.md) | `GET /printer/{id}` |
|
||||
| [`routes/printer/update.md`](routes/printer/update.md) | `PATCH /printer/{id}` |
|
||||
| [`routes/printer/_id.put.md`](routes/printer/_id.put.md) | `PUT /printer/{id}` |
|
||||
| [`routes/printer/_id/state.md`](routes/printer/_id/state.md) | `GET /printer/{id}/state` |
|
||||
| [`routes/printeragent.get.md`](routes/printeragent.get.md) | `GET /printeragent` |
|
||||
| [`routes/printeragent.put.md`](routes/printeragent.put.md) | `PUT /printeragent` |
|
||||
| [`routes/printeragent/_id.delete.md`](routes/printeragent/_id.delete.md) | `DELETE /printeragent/{id}` |
|
||||
| [`routes/printeragent/_id.patch.md`](routes/printeragent/_id.patch.md) | `PATCH /printeragent/{id}` |
|
||||
| [`routes/printerjob.get.md`](routes/printerjob.get.md) | `GET /printerjob` |
|
||||
| [`routes/printerjob.post.md`](routes/printerjob.post.md) | `POST /printerjob` |
|
||||
| [`routes/printerjob/cancel-all.md`](routes/printerjob/cancel-all.md) | `POST /printerjob/cancel-all` |
|
||||
| [`routes/printerjob/_id.delete.md`](routes/printerjob/_id.delete.md) | `DELETE /printerjob/{id}` |
|
||||
| [`routes/printerjob/_id.get.md`](routes/printerjob/_id.get.md) | `GET /printerjob/{id}` |
|
||||
| [`routes/printerjob/_id/cancel.md`](routes/printerjob/_id/cancel.md) | `POST /printerjob/{id}/cancel` |
|
||||
| [`routes/propertyname.get.md`](routes/propertyname.get.md) | `GET /propertyname` |
|
||||
| [`routes/propertyname.post.md`](routes/propertyname.post.md) | `POST /propertyname` |
|
||||
| [`routes/propertyname/order.md`](routes/propertyname/order.md) | `PUT /propertyname/order` |
|
||||
@@ -240,6 +270,20 @@ Generated from `@openapi` annotations in [`src/api/routes/`](../../src/api/route
|
||||
| [`routes/quote/_id/file/_fileId.get.md`](routes/quote/_id/file/_fileId.get.md) | `GET /quote/{id}/file/{fileId}` |
|
||||
| [`routes/quote/order.md`](routes/quote/order.md) | `POST /quote/{id}/order` |
|
||||
| [`routes/quote/_id/pdf.md`](routes/quote/_id/pdf.md) | `POST /quote/{id}/pdf` |
|
||||
| [`routes/retoure.get.md`](routes/retoure.get.md) | `GET /retoure` |
|
||||
| [`routes/retoure.post.md`](routes/retoure.post.md) | `POST /retoure` |
|
||||
| [`routes/retoure/rebuild-summaries.md`](routes/retoure/rebuild-summaries.md) | `POST /retoure/rebuild-summaries` |
|
||||
| [`routes/retoure/_id.delete.md`](routes/retoure/_id.delete.md) | `DELETE /retoure/{id}` |
|
||||
| [`routes/retoure/_id.get.md`](routes/retoure/_id.get.md) | `GET /retoure/{id}` |
|
||||
| [`routes/retoure/_id.put.md`](routes/retoure/_id.put.md) | `PUT /retoure/{id}` |
|
||||
| [`routes/retoure/_id/shipment.md`](routes/retoure/_id/shipment.md) | `POST /retoure/{id}/shipment` |
|
||||
| [`routes/return.get.md`](routes/return.get.md) | `GET /return` |
|
||||
| [`routes/return.post.md`](routes/return.post.md) | `POST /return` |
|
||||
| [`routes/return/rebuild-summaries.md`](routes/return/rebuild-summaries.md) | `POST /return/rebuild-summaries` |
|
||||
| [`routes/return/_id.delete.md`](routes/return/_id.delete.md) | `DELETE /return/{id}` |
|
||||
| [`routes/return/_id.get.md`](routes/return/_id.get.md) | `GET /return/{id}` |
|
||||
| [`routes/return/_id.put.md`](routes/return/_id.put.md) | `PUT /return/{id}` |
|
||||
| [`routes/return/_id/book.md`](routes/return/_id/book.md) | `POST /return/{id}/book` |
|
||||
| [`routes/serper/image.md`](routes/serper/image.md) | `POST /serper/image` |
|
||||
| [`routes/serper/images.md`](routes/serper/images.md) | `POST /serper/images` |
|
||||
| [`routes/shipment.md`](routes/shipment.md) | `GET /shipment` |
|
||||
@@ -275,8 +319,13 @@ Generated from `@openapi` annotations in [`src/api/routes/`](../../src/api/route
|
||||
| [`routes/unit/list.md`](routes/unit/list.md) | `GET /unit` |
|
||||
| [`routes/unit/upsert.md`](routes/unit/upsert.md) | `PUT /unit` |
|
||||
| [`routes/v1/category.md`](routes/v1/category.md) | `GET /v1/category` |
|
||||
| [`routes/pos/cimage.md`](routes/pos/cimage.md) | `GET /v1/cimage` |
|
||||
| [`routes/pos/client.md`](routes/pos/client.md) | `GET /v1/client` |
|
||||
| [`routes/v1/customer.md`](routes/v1/customer.md) | `GET /v1/customer` |
|
||||
| [`routes/v1/customergroup.md`](routes/v1/customergroup.md) | `GET /v1/customergroup` |
|
||||
| [`routes/v1/deletedentity.md`](routes/v1/deletedentity.md) | `GET /v1/deletedentity` |
|
||||
| [`routes/pos/init.md`](routes/pos/init.md) | `GET /v1/init` |
|
||||
| [`routes/v1/order.md`](routes/v1/order.md) | `POST /v1/order` |
|
||||
| [`routes/pos/pimage.md`](routes/pos/pimage.md) | `GET /v1/pimage` |
|
||||
| [`routes/v1/product.md`](routes/v1/product.md) | `GET /v1/product` |
|
||||
| [`routes/vfs/list.md`](routes/vfs/list.md) | `GET /vfs` |
|
||||
@@ -296,6 +345,7 @@ Generated from `@openapi` annotations in [`src/api/routes/`](../../src/api/route
|
||||
| [`routes/warehouse/get.md`](routes/warehouse/get.md) | `GET /warehouse/{id}` |
|
||||
| [`routes/warehouse/update.md`](routes/warehouse/update.md) | `PATCH /warehouse/{id}` |
|
||||
| [`routes/warehouse/_id.put.md`](routes/warehouse/_id.put.md) | `PUT /warehouse/{id}` |
|
||||
| [`routes/zpljob.md`](routes/zpljob.md) | `POST /zpljob` |
|
||||
|
||||
Route overview: [`routes.md`](routes.md) | All routes: [`routes-all.md`](routes-all.md).
|
||||
|
||||
@@ -305,12 +355,16 @@ Clients subscribe via [`GET /events`](routes/events.md) (`text/event-stream`). A
|
||||
|
||||
| Signal | Emitted by |
|
||||
|--------|------------|
|
||||
| `agentprinter` | `PUT /agentprinter/order`, `DELETE /agentprinter/{id}`, `PATCH /agentprinter/{id}` |
|
||||
| `article-<sku>` | `PUT /article/{sku}/brand`, `PUT /article/{sku}/categories`, `PUT /article/{sku}/eans`, `POST /article/{sku}/image`, `DELETE /article/{sku}/image/{fullHash}`, `PUT /article/{sku}/images/order`, `PUT /article/{sku}/prices`, `POST /article/{sku}/supplier`, `PUT /article/{sku}/supplier/order`, `DELETE /article/{sku}/supplier/{id}`, `PATCH /article/{sku}/supplier/{id}`, `PUT /article/{sku}/track_stock`, `PUT /article/{sku}/weight`, `POST /stock/adjust` |
|
||||
| `articles` | `POST /article`, `DELETE /article/{sku}`, `PATCH /article/{sku}`, `DELETE /category/{id}`, `DELETE /shipment/{id}`, `POST /stock/accept`, `POST /stock/adjust`, `POST /stock/ship` |
|
||||
| `attributename` | `POST /attributename`, `PUT /attributename/order`, `DELETE /attributename/{id}`, `PATCH /attributename/{id}`, `DELETE /attributevalue/{id}/image`, `POST /attributevalue/{id}/image` |
|
||||
| `autoinvite` | `POST /autoinvite`, `DELETE /autoinvite/{id}` |
|
||||
| `brand` | `POST /brand`, `DELETE /brand/{id}`, `PATCH /brand/{id}`, `DELETE /brand/{id}/image`, `POST /brand/{id}/image` |
|
||||
| `carrier` | `POST /carrier`, `PUT /carrier/order`, `DELETE /carrier/{id}`, `PATCH /carrier/{id}` |
|
||||
| `category` | `POST /category`, `PUT /category/order`, `DELETE /category/{id}`, `PATCH /category/{id}`, `DELETE /category/{id}/image`, `POST /category/{id}/image` |
|
||||
| `category` | `POST /category`, `PUT /category/order`, `DELETE /category/{id}`, `PATCH /category/{id}`, `DELETE /category/{id}/image`, `POST /category/{id}/image`, `POST /category/{id}/image/generate` |
|
||||
| `company` | `PUT /auth/selected-company`, `POST /company`, `DELETE /company/{id}`, `PUT /company/{id}` |
|
||||
| `companyuser` | `POST /companyuser`, `DELETE /companyuser/{id}`, `PATCH /companyuser/{id}` |
|
||||
| `delivery` | `DELETE /delivery/{id}/file/{fileId}`, `POST /delivery/{id}/pdf`, `POST /stock/accept` |
|
||||
| `labeltemplate` | `POST /labeltemplate`, `DELETE /labeltemplate/{id}`, `PATCH /labeltemplate/{id}`, `PUT /labeltemplate/{id}` |
|
||||
| `ledger` | `DELETE /shipment/{id}`, `POST /stock/accept`, `POST /stock/adjust`, `POST /stock/ship` |
|
||||
@@ -324,6 +378,8 @@ Clients subscribe via [`GET /events`](routes/events.md) (`text/event-stream`). A
|
||||
| `shipping` | `POST /stock/ship` |
|
||||
| `stock` | `DELETE /shipment/{id}`, `POST /stock/accept`, `POST /stock/adjust`, `POST /stock/ship` |
|
||||
| `subagentschedule` | `POST /subagentschedule`, `DELETE /subagentschedule/{id}`, `PUT /subagentschedule/{id}` |
|
||||
| `supplier` | `POST /supplier`, `DELETE /supplier/{id}`, `PATCH /supplier/{id}` |
|
||||
| `user` | `PUT /auth/selected-company`, `POST /company`, `DELETE /company/{id}` |
|
||||
| `vfs` | `POST /vfs/applets/restore`, `POST /vfs/mkdir`, `POST /vfs/rename`, `POST /vfs/skills/restore`, `POST /vfs/upload`, `DELETE /vfs/{*path}`, `POST /vfs/{*path}`, `PUT /vfs/{*path}` |
|
||||
| `warehouse` | `POST /warehouse`, `PUT /warehouse/order`, `DELETE /warehouse/{id}`, `PUT /warehouse/{id}` |
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Dash API Routes Overview (All)
|
||||
|
||||
Overview of all 264 API endpoints across all modules.
|
||||
Overview of all 314 API endpoints across all modules.
|
||||
|
||||
### Notation
|
||||
|
||||
@@ -9,44 +9,48 @@ Params: path values first, then `query:` and `body:` (`body?` = optional body).
|
||||
|
||||
### Reusable types
|
||||
|
||||
- `T1` = `{ id: int, number: str, type: str, entityId: int, date: str, lines: T18[], externalNumber?: str|null, createdAt?: str, shipping?: T20|null, shippings?: T20[], payment?: T29|null, payments?: T29[], paid?: bool, shipped?: bool, delivered?: bool, orderTotal?: num, paidTotal?: num, orderedQuantity?: num, shippedQuantity?: num, shipments?: T2[], files?: T9[] }`
|
||||
- `T2` = `{ id: int, number: str, type: str, date: str, lines: T18[], shippings: T20[], entityId?: int|null, externalNumber?: str|null, createdAt?: str|null, lineCount?: int, packageCount?: int, files?: T9[], state?: str }`
|
||||
- `T3` = `{ id: int, number: str, type: str, date: str, lines: T18[], entityId?: int|null, externalNumber?: str|null, createdAt?: str, positions?: int, grossTotal?: num, totalQuantity?: num, customerName?: str|null, files?: T9[] }`
|
||||
- `T4` = `{ id: int, number: str, type: str, supplierId: int, date: str, lines: T21[], files: T9[], externalNumber?: str|null, createdAt?: str, ledger?: T36 }`
|
||||
- `T1` = `{ id: int, number: str, type: str, entityId: int, date: str, lines: T20[], externalNumber?: str|null, createdAt?: str, shipping?: T23|null, shippings?: T23[], payment?: T33|null, payments?: T33[], paid?: bool, shipped?: bool, delivered?: bool, orderTotal?: num, paidTotal?: num, orderedQuantity?: num, shippedQuantity?: num, shipments?: T2[], files?: T10[] }`
|
||||
- `T2` = `{ id: int, number: str, type: str, date: str, lines: T20[], shippings: T23[], entityId?: int|null, externalNumber?: str|null, createdAt?: str|null, lineCount?: int, packageCount?: int, files?: T10[], state?: str }`
|
||||
- `T3` = `{ id: int, number: str, type: str, date: str, lines: T20[], entityId?: int|null, externalNumber?: str|null, createdAt?: str, positions?: int, grossTotal?: num, totalQuantity?: num, customerName?: str|null, files?: T10[] }`
|
||||
- `T4` = `{ id: int, number: str, type: str, supplierId: int, date: str, lines: T24[], files: T10[], externalNumber?: str|null, createdAt?: str, ledger?: T40 }`
|
||||
- `T5` = `{ name: str, path: str, totalSizeBytes: int, timestamp: str|null, manifest?: T6|null }`
|
||||
- `T6` = `{ id: str, timestamp: str, dateKey: str, monthKey: str, dbProvider: str, files: T11, totalSizeBytes: int, durationMs: int }`
|
||||
- `T7` = `{ id: int, articleId: int, entityId: int, pu: num, sort: int, supplierName?: str|null, sku?: str|null, stock?: num|null, priceId?: int|null, price?: T38|null, incoming?: { date: str, amount: num }[] }`
|
||||
- `T8` = `{ id: int, name: str, width: num, height: num, dpi: int, type: str, content: { objects: T22[] }, thumb?: str|null }`
|
||||
- `T9` = `{ id: int, manifestId: int, fileId: int, sort: int, hash: str, mimetype: str, name: str, size: int, created?: str, modified?: str, skeledash?: str|null, thumbx?: int|null, thumby?: int|null, meta?: { [k]: str }|null }`
|
||||
- `T10` = `{ id: int, name: str, pairingpin?: str|null, token?: str|null, pairedAt?: str|null, clientserial?: str|null, rootCategoryId?: int|null, syncRootArticles?: bool, lastseenAt?: str|null, updatedAt?: str|null, categoryIds?: int[] }`
|
||||
- `T11` = `{ vfs: T37, storage: T37, database: T31 }`
|
||||
- `T12` = `{ id: int, entityId: int, addressType: str, firstName?: str|null, name?: str|null, street?: str|null, streetNumber?: str|null, zip?: str|null, city?: str|null, county?: str|null }`
|
||||
- `T13` = `{ id: int, company_id: int, prompt: str, max_itr: int, cron: str, created_at: str, desc?: str|null, skills?: str|null, lastagentnote?: str|null, lastrun_at?: str|null }`
|
||||
- `T14` = `{ id: int, manifestarticle_id: int, transaction_type: str, amount: num, transaction_text: str, hash_version: int, prev_hash?: str, sku?: str|null, created_at?: str }`
|
||||
- `T15` = `{ id: int, name: str, sort: int, exclusive: bool, values: T27[], articleCount?: int }`
|
||||
- `T16` = `{ id: int, companyuser_id: int, provider: str, model: str, created_at: str, updated_at: str, state: str, started_by?: int|null, first_message?: str|null }`
|
||||
- `T17` = `{ id: int, name: str, rootCategoryId: int|null, languageId: int|null, iso639: str|null, taxrate: num, reducedtaxrate: num, taxfreerate: num }`
|
||||
- `T18` = `{ id: int, sku: str|null, name: str|null, pu: num, amount: num, net: num, rebate: num, taxrate: num, comment: str|null, shippable: bool }`
|
||||
- `T19` = `{ amount: num, net: num, taxrate: num, sku?: str|null, name?: str|null, pu?: num, rebate?: num, comment?: str|null, shippable?: bool }`
|
||||
- `T20` = `{ id: int, manifestId: int, number: str, carrierId: int, type: str, state: str, trackingCode?: str|null, carrier?: str|null }`
|
||||
- `T21` = `{ id: int, sku: str|null, name: str|null, pu: num, amount: num, net: num, rebate: num, taxrate: num, comment: str|null }`
|
||||
- `T22` = `{ id: str, type: str, x: num, y: num, w?: num, h?: num, text?: str, font?: str, fontSize?: num, barcodeFormat?: str }`
|
||||
- `T23` = `{ id: int, company_id: int, address: str, type: str, sort: int, model?: str|null, serial?: str|null, desc?: str|null }`
|
||||
- `T24` = `{ id: int, customergroupId: int, firstName: str|null, name: str, number: str|null, createdAt: str, updatedAt: str }`
|
||||
- `T25` = `{ name: str, id?: int|null, fullHash?: str|null, thumbW?: int|null, thumbH?: int|null, thumbHash?: str|null }`
|
||||
- `T26` = `{ si: str, basesi: str, basesifactor: num, symbol?: str|null, name?: str|null }`
|
||||
- `T27` = `{ id: int, attributeId: int, value: str, sort: int, articleCount?: int }`
|
||||
- `T28` = `{ id: int, name: str, sort: int, exclusive: bool, articleCount?: int }`
|
||||
- `T29` = `{ id: int, accountId: int, manifestId: int, type: str, amount: num }`
|
||||
- `T30` = `{ id: int, name: str, sort: int, hasPackages: bool, isReverse: bool }`
|
||||
- `T31` = `{ name: str|null, sizeBytes: int, backedUp: bool, reason?: str|null }`
|
||||
- `T32` = `{ id: int, email: str, selectedCompanyId: int|null, picture?: str }`
|
||||
- `T33` = `{ fullHash: str, thumbW: int, thumbH: int, thumbHash: str }`
|
||||
- `T34` = `{ id: int, entityId: int, contactType: str, contact: str }`
|
||||
- `T35` = `{ id: int, name: str, createdAt: str, updatedAt: str }`
|
||||
- `T36` = `{ totalPositions: int, completelyOnLedgerPositions: int }`
|
||||
- `T37` = `{ name: str, sizeBytes: int, sourceExists: bool }`
|
||||
- `T38` = `{ net: num, taxId: int, taxRate?: num|null }`
|
||||
- `T7` = `{ id: int, name: str, pairingpin?: str|null, token?: str|null, pairedAt?: str|null, clientserial?: str|null, rootCategoryId?: int|null, syncRootArticles?: bool, sort?: int, enabled?: bool, clientversion?: str|null, lastseenAt?: str|null, updatedAt?: str|null, categoryIds?: int[] }`
|
||||
- `T8` = `{ id: int, articleId: int, entityId: int, pu: num, sort: int, supplierName?: str|null, sku?: str|null, stock?: num|null, priceId?: int|null, price?: T42|null, incoming?: { date: str, amount: num }[] }`
|
||||
- `T9` = `{ id: int, name: str, width: num, height: num, dpi: int, type: str, content: { objects: T25[] }, thumb?: str|null }`
|
||||
- `T10` = `{ id: int, manifestId: int, fileId: int, sort: int, hash: str, mimetype: str, name: str, size: int, created?: str, modified?: str, skeledash?: str|null, thumbx?: int|null, thumby?: int|null, meta?: { [k]: str }|null }`
|
||||
- `T11` = `{ vfs: T41, storage: T41, database: T35 }`
|
||||
- `T12` = `{ id: int, name: str, companyId?: int, token?: str|null, pairingpin?: str|null, pairedAt?: str|null, agentversion?: str|null, lastseenAt?: str|null, updatedAt?: str, sort?: int, enabled?: bool }`
|
||||
- `T13` = `{ id: int, printeragentId: int, type: str, enabled: bool, sort: int, model?: str|null, serial?: str|null, open?: bool, pause?: bool, error?: bool, online?: bool, labelLength?: int|null }`
|
||||
- `T14` = `{ id: int, entityId: int, addressType: str, firstName?: str|null, name?: str|null, street?: str|null, streetNumber?: str|null, zip?: str|null, city?: str|null, county?: str|null }`
|
||||
- `T15` = `{ id: int, company_id: int, prompt: str, max_itr: int, cron: str, created_at: str, desc?: str|null, skills?: str|null, lastagentnote?: str|null, lastrun_at?: str|null }`
|
||||
- `T16` = `{ id: int, manifestarticle_id: int, transaction_type: str, amount: num, transaction_text: str, hash_version: int, prev_hash?: str, sku?: str|null, created_at?: str }`
|
||||
- `T17` = `{ id: int, name: str, sort: int, exclusive: bool, values: T30[], articleCount?: int }`
|
||||
- `T18` = `{ id: int, companyuser_id: int, provider: str, model: str, created_at: str, updated_at: str, state: str, started_by?: int|null, first_message?: str|null }`
|
||||
- `T19` = `{ id: int, name: str, rootCategoryId: int|null, languageId: int|null, iso639: str|null, taxrate: num, reducedtaxrate: num, taxfreerate: num, role: str }`
|
||||
- `T20` = `{ id: int, sku: str|null, name: str|null, pu: num, amount: num, net: num, rebate: num, taxrate: num, comment: str|null, shippable: bool }`
|
||||
- `T21` = `{ amount: num, net: num, taxrate: num, sku?: str|null, name?: str|null, pu?: num, rebate?: num, comment?: str|null, shippable?: bool }`
|
||||
- `T22` = `{ id: int, agentprinterId: int, type: str, state: str, data: str, createdAt: str, printeragentId?: int|null, completedAt?: str|null }`
|
||||
- `T23` = `{ id: int, manifestId: int, number: str, carrierId: int, type: str, state: str, trackingCode?: str|null, carrier?: str|null }`
|
||||
- `T24` = `{ id: int, sku: str|null, name: str|null, pu: num, amount: num, net: num, rebate: num, taxrate: num, comment: str|null }`
|
||||
- `T25` = `{ id: str, type: str, x: num, y: num, w?: num, h?: num, text?: str, font?: str, fontSize?: num, barcodeFormat?: str }`
|
||||
- `T26` = `{ id: int, company_id: int, address: str, type: str, sort: int, model?: str|null, serial?: str|null, desc?: str|null }`
|
||||
- `T27` = `{ id: int, customergroupId: int, firstName: str|null, name: str, number: str|null, createdAt: str, updatedAt: str }`
|
||||
- `T28` = `{ name: str, id?: int|null, fullHash?: str|null, thumbW?: int|null, thumbH?: int|null, thumbHash?: str|null }`
|
||||
- `T29` = `{ si: str, basesi: str, basesifactor: num, symbol?: str|null, name?: str|null }`
|
||||
- `T30` = `{ id: int, attributeId: int, value: str, sort: int, articleCount?: int }`
|
||||
- `T31` = `{ id: int, googleAuthId: int, email: str, role: str, picture?: str|null }`
|
||||
- `T32` = `{ id: int, name: str, sort: int, exclusive: bool, articleCount?: int }`
|
||||
- `T33` = `{ id: int, accountId: int, manifestId: int, type: str, amount: num }`
|
||||
- `T34` = `{ id: int, name: str, sort: int, hasPackages: bool, isReverse: bool }`
|
||||
- `T35` = `{ name: str|null, sizeBytes: int, backedUp: bool, reason?: str|null }`
|
||||
- `T36` = `{ id: int, email: str, selectedCompanyId: int|null, picture?: str }`
|
||||
- `T37` = `{ fullHash: str, thumbW: int, thumbH: int, thumbHash: str }`
|
||||
- `T38` = `{ id: int, entityId: int, contactType: str, contact: str }`
|
||||
- `T39` = `{ id: int, name: str, createdAt: str, updatedAt: str }`
|
||||
- `T40` = `{ totalPositions: int, completelyOnLedgerPositions: int }`
|
||||
- `T41` = `{ name: str, sizeBytes: int, sourceExists: bool }`
|
||||
- `T42` = `{ net: num, taxId: int, taxRate?: num|null }`
|
||||
|
||||
### Routes
|
||||
|
||||
@@ -72,6 +76,39 @@ _none_
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
|
||||
### Section: /agent
|
||||
|
||||
#### Printer agent SSE stream — `GET /agent/events`
|
||||
- Params: `query: token?: str, agentversion?: str`
|
||||
- Returns: `200 SSE`
|
||||
#### Pair printer agent via query parameters — `GET /agent/pair`
|
||||
- Params: `query: authCode?: str, pairingpin?: str, serial?: str, model?: str, version?: str`
|
||||
- Returns: `200`
|
||||
#### Pair printer agent — `POST /agent/pair`
|
||||
- Params: `body: { pairingpin: str, clientserial?: str, clientmodel?: str, agentversion?: str }`
|
||||
- Returns: `200 { id: int, name: str, companyId: int, token: str, pairedAt: str, clientserial: str|null, clientmodel: str|null, agentversion: str|null, sort: int }`
|
||||
#### Post agent state — `POST /agent/state`
|
||||
- Params: `body: { state?: any }`
|
||||
- Returns: `200 { success: bool, agent: T12 }`
|
||||
|
||||
### Section: /agentprinter
|
||||
|
||||
#### List agent printers — `GET /agentprinter`
|
||||
- Params: `query: printeragentId?: int`
|
||||
- Returns: `200 { agentprinters: T13[] }`
|
||||
#### Reorder agent printers — `PUT /agentprinter/order`
|
||||
- Params: `body: { agentprinterIds: int[], printeragentId?: int }`
|
||||
- Returns: `200 { agentprinterIds: int[] }`
|
||||
#### Delete agent printer — `DELETE /agentprinter/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
#### Get agent printer — `GET /agentprinter/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { agentprinter: T13 }`
|
||||
#### Update agent printer — `PATCH /agentprinter/{id}`
|
||||
- Params: `id: int, body: { enabled?: bool, sort?: int }`
|
||||
- Returns: `200 { agentprinter: T13 }`
|
||||
|
||||
### Section: /article
|
||||
|
||||
#### Create article in category — `POST /article`
|
||||
@@ -88,7 +125,7 @@ _none_
|
||||
- Returns: `204 void`
|
||||
#### Get article by SKU — `GET /article/{sku}`
|
||||
- Params: `sku: str`
|
||||
- Returns: `200 { article: { id: int, sku: str, name: str, slug: str, desc: str|null, seo: str|null, track_stock: bool, unitamount: num|null, weight: num|null, unit: T26, brand: T25|null, categoryIds: int[], photos: { sort: int, fullHash: str, fullW: int, fullH: int, fullSize: int, thumbW: int, thumbH: int, thumbHash: str }[], eans: str[], prices: { minmultiplier: num, net: num, taxRate: num, customergroupId: int }[], suppliers: T7[], undeliveredOrders: { orderId: int, orderNumber: str, date: str, amount: num, customerName?: str|null }[] } }`
|
||||
- Returns: `200 { article: { id: int, sku: str, name: str, slug: str, desc: str|null, seo: str|null, track_stock: bool, unitamount: num|null, weight: num|null, unit: T29, brand: T28|null, categoryIds: int[], photos: { sort: int, fullHash: str, fullW: int, fullH: int, fullSize: int, thumbW: int, thumbH: int, thumbHash: str }[], eans: str[], prices: { minmultiplier: num, net: num, taxRate: num, customergroupId: int }[], suppliers: T8[], undeliveredOrders: { orderId: int, orderNumber: str, date: str, amount: num, customerName?: str|null }[] } }`
|
||||
#### Update article by SKU — `PATCH /article/{sku}`
|
||||
- Params: `sku: str, body: { name?: str, desc?: str, seo?: str, unitamount?: num, unitSi?: str, track_stock?: bool }`
|
||||
- Returns: `204 void`
|
||||
@@ -126,8 +163,8 @@ _none_
|
||||
- Params: `sku: str, body: { eans: str[] }`
|
||||
- Returns: `204 void`
|
||||
#### Get article history by SKU — `GET /article/{sku}/history`
|
||||
- Params: `sku: str, query: limit?: int`
|
||||
- Returns: `200 { history: { id: int, date: str, text: str }[], truncated: bool }`
|
||||
- Params: `sku: str, query: offset?: int, limit?: int, search?: str, seekMonths?: int`
|
||||
- Returns: `200 { history: { id: int, date: str, text: str }[], total: int, unfilteredTotal: int, offset: int, limit: int }`
|
||||
#### Add article image — `POST /article/{sku}/image`
|
||||
- Params: `sku: str, image/avif`
|
||||
- Returns: `201 { image: { picId: int, sort: int, full: { w: int, h: int, size: int }, thumb: { w: int, h: int }, hash: str, thumbHash: str } }`
|
||||
@@ -146,11 +183,11 @@ _none_
|
||||
#### Toggle parent mode for an article — `POST /article/{sku}/parent`
|
||||
- Params: `sku: str, body: { isParent: bool, attributeNameId?: int }`
|
||||
- Returns: `204 void`
|
||||
#### Replace POS prices by SKU (net > gross; price=net, tax=taxRate %) — `PUT /article/{sku}/prices`
|
||||
- Params: `sku: str, body: { prices: { net?: num, gross?: num, price?: num, taxRate?: num, tax?: num, minmultiplier?: num }[] }`
|
||||
#### Replace POS prices by SKU (net > gross) — `PUT /article/{sku}/prices`
|
||||
- Params: `sku: str, body: { prices: { net?: num, gross?: num, taxRate?: num, minmultiplier?: num }[] }`
|
||||
- Returns: `204 void`
|
||||
#### Print article label — `POST /article/{sku}/print`
|
||||
- Params: `sku: str, body: { templateId: int, printerId: int, quantity: int }`
|
||||
- Params: `sku: str, body: { templateId: int, agentprinterId: int, quantity: int }`
|
||||
- Returns: `200 { success: bool }`
|
||||
#### List article properties — `GET /article/{sku}/property`
|
||||
- Params: `sku: str`
|
||||
@@ -163,10 +200,10 @@ _none_
|
||||
- Returns: `200 { ok: bool }`
|
||||
#### List article suppliers — `GET /article/{sku}/supplier`
|
||||
- Params: `sku: str`
|
||||
- Returns: `200 { suppliers: T7[] }`
|
||||
- Returns: `200 { suppliers: T8[] }`
|
||||
#### Assign supplier to article — `POST /article/{sku}/supplier`
|
||||
- Params: `sku: str, body: { entityId: int, sku?: str|null, pu?: num, stock?: num|null, sort?: int|null, netPrice?: num|null, taxId?: int|null, taxRate?: num|null }`
|
||||
- Returns: `201 { supplier: T7 }`
|
||||
- Returns: `201 { supplier: T8 }`
|
||||
#### Reorder article suppliers — `PUT /article/{sku}/supplier/order`
|
||||
- Params: `sku: str, body: { ids: int[] }`
|
||||
- Returns: `200 { ids: int[] }`
|
||||
@@ -175,7 +212,7 @@ _none_
|
||||
- Returns: `204 void`
|
||||
#### Update article supplier assignment — `PATCH /article/{sku}/supplier/{id}`
|
||||
- Params: `sku: str, id: int, body: { sku?: str|null, pu?: num, stock?: num|null, sort?: int, netPrice?: num|null, taxId?: int|null, taxRate?: num|null }`
|
||||
- Returns: `200 { supplier: T7 }`
|
||||
- Returns: `200 { supplier: T8 }`
|
||||
#### Set article track_stock flag by SKU — `PUT /article/{sku}/track_stock`
|
||||
- Params: `sku: str, body: { track_stock: bool }`
|
||||
- Returns: `204 void`
|
||||
@@ -187,19 +224,19 @@ _none_
|
||||
|
||||
#### List attribute names — `GET /attributename`
|
||||
_none_
|
||||
- Returns: `200 { attributenames: T15[] }`
|
||||
- Returns: `200 { attributenames: T17[] }`
|
||||
#### Create attribute name — `POST /attributename`
|
||||
- Params: `body: { name: str, sort?: int, exclusive?: bool }`
|
||||
- Returns: `201 { attributename: T15 }`
|
||||
- Returns: `201 { attributename: T17 }`
|
||||
#### Reorder attribute names — `PUT /attributename/order`
|
||||
- Params: `body: { attributenameIds: int[] }`
|
||||
- Returns: `200 { ok: bool }`
|
||||
#### List values for an attribute — `GET /attributename/{attributeId}/value`
|
||||
- Params: `attributeId: int`
|
||||
- Returns: `200 { values: T27[] }`
|
||||
- Returns: `200 { values: T30[] }`
|
||||
#### Create value for an attribute — `POST /attributename/{attributeId}/value`
|
||||
- Params: `attributeId: int, body: { value: str, sort?: int }`
|
||||
- Returns: `201 { attributevalue: T27 }`
|
||||
- Returns: `201 { attributevalue: T30 }`
|
||||
#### Reorder values of an attribute — `PUT /attributename/{attributeId}/value/order`
|
||||
- Params: `attributeId: int, body: { attributevalueIds: int[] }`
|
||||
- Returns: `200 { ok: bool }`
|
||||
@@ -208,7 +245,7 @@ _none_
|
||||
- Returns: `200 { ok: bool }`
|
||||
#### Update attribute name — `PATCH /attributename/{id}`
|
||||
- Params: `id: int, body: { name?: str, sort?: int, exclusive?: bool }`
|
||||
- Returns: `200 { attributename: T15 }`
|
||||
- Returns: `200 { attributename: T17 }`
|
||||
|
||||
### Section: /attributevalue
|
||||
|
||||
@@ -217,28 +254,40 @@ _none_
|
||||
- Returns: `200 { ok: bool }`
|
||||
#### Update attribute value — `PATCH /attributevalue/{id}`
|
||||
- Params: `id: int, body: { value?: str, sort?: int }`
|
||||
- Returns: `200 { attributevalue: T27 }`
|
||||
- Returns: `200 { attributevalue: T30 }`
|
||||
#### Delete attribute value image — `DELETE /attributevalue/{id}/image`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { attributevalue: { id: int, thumbW: int|null, thumbH: int|null, thumbHash: str|null, pics: T33[] } }`
|
||||
- Returns: `200 { attributevalue: { id: int, thumbW: int|null, thumbH: int|null, thumbHash: str|null, pics: T37[] } }`
|
||||
#### Add or replace attribute value image — `POST /attributevalue/{id}/image`
|
||||
- Params: `id: int, image/avif`
|
||||
- Returns: `201 { attributevalue: { id: int, fullHash: str, thumbW: int, thumbH: int, thumbHash: str, pics: T33[] } }`
|
||||
- Returns: `201 { attributevalue: { id: int, fullHash: str, thumbW: int, thumbH: int, thumbHash: str, pics: T37[] } }`
|
||||
|
||||
### Section: /auth
|
||||
|
||||
#### Login with Google ID token — `POST /auth/login`
|
||||
- Params: `body: { idToken: str }`
|
||||
- Returns: `200 { message: str, user: T32 }`
|
||||
- Returns: `200 { message: str, user: T36 }`
|
||||
#### Logout — `POST /auth/logout`
|
||||
_none_
|
||||
- Returns: `200 { message: str }`
|
||||
#### Current user — `GET /auth/me`
|
||||
_none_
|
||||
- Returns: `200 { user: T32, googleClientId: str }`
|
||||
- Returns: `200 { user: T36, googleClientId: str, schemaVersion: int, vhost: bool, vhostSettings: str }`
|
||||
#### Set selected company — `PUT /auth/selected-company`
|
||||
- Params: `body: { companyId: int }`
|
||||
- Returns: `200 { user: T32 }`
|
||||
- Returns: `200 { user: T36 }`
|
||||
|
||||
### Section: /autoinvite
|
||||
|
||||
#### List auto-invitations — `GET /autoinvite`
|
||||
_none_
|
||||
- Returns: `200 { autoinvites: { id: int, email: str, role: str, createdAt: str }[] }`
|
||||
#### Create auto-invitation — `POST /autoinvite`
|
||||
- Params: `body: { email: str, role?: str }`
|
||||
- Returns: `201 { autoinvite: { id: int, email: str, role: str } }`
|
||||
#### Delete auto-invitation — `DELETE /autoinvite/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
|
||||
### Section: /backup
|
||||
|
||||
@@ -259,7 +308,7 @@ _none_
|
||||
- Returns: `200 { brands: { id: int, name: str, articleCount: int, pics: { fullHash: str, thumbW: int, thumbH: int, thumbHash: str, smallThumbW?: int|null, smallThumbH?: int|null, smallThumbBinary?: str|null }[], gsprpinfo?: str|null }[], total: int, offset: int, limit: int }`
|
||||
#### Create brand — `POST /brand`
|
||||
- Params: `body: { name: str, gsprpinfo?: str }`
|
||||
- Returns: `201 { brand: { id: int, name: str, pics: T33[], gsprpinfo?: str|null } }`
|
||||
- Returns: `201 { brand: { id: int, name: str, pics: T37[], gsprpinfo?: str|null } }`
|
||||
#### Delete brand — `DELETE /brand/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
@@ -268,19 +317,19 @@ _none_
|
||||
- Returns: `200 { brand: { id: int, name: str, touchedArticleCount: int, gsprpinfo?: str|null } }`
|
||||
#### Delete brand image — `DELETE /brand/{id}/image`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { brand: { id: int, thumbW: int|null, thumbH: int|null, thumbHash: str|null, pics: T33[] } }`
|
||||
- Returns: `200 { brand: { id: int, thumbW: int|null, thumbH: int|null, thumbHash: str|null, pics: T37[] } }`
|
||||
#### Add or replace brand image — `POST /brand/{id}/image`
|
||||
- Params: `id: int, image/avif`
|
||||
- Returns: `201 { brand: { id: int, fullHash: str, thumbW: int, thumbH: int, thumbHash: str, pics: T33[] } }`
|
||||
- Returns: `201 { brand: { id: int, fullHash: str, thumbW: int, thumbH: int, thumbHash: str, pics: T37[] } }`
|
||||
|
||||
### Section: /carrier
|
||||
|
||||
#### List carriers — `GET /carrier`
|
||||
_none_
|
||||
- Returns: `200 { carriers: T30[] }`
|
||||
- Returns: `200 { carriers: T34[] }`
|
||||
#### Create carrier — `POST /carrier`
|
||||
- Params: `body: { name: str, sort?: int, hasPackages?: bool, isReverse?: bool }`
|
||||
- Returns: `201 { carrier: T30 }`
|
||||
- Returns: `201 { carrier: T34 }`
|
||||
#### Reorder carriers — `PUT /carrier/order`
|
||||
- Params: `body: { carrierIds: int[] }`
|
||||
- Returns: `200 { carrierIds: int[] }`
|
||||
@@ -289,10 +338,10 @@ _none_
|
||||
- Returns: `204 void`
|
||||
#### Get carrier by ID — `GET /carrier/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { carrier: T30 }`
|
||||
- Returns: `200 { carrier: T34 }`
|
||||
#### Update carrier — `PATCH /carrier/{id}`
|
||||
- Params: `id: int, body: { name?: str, sort?: int, hasPackages?: bool, isReverse?: bool }`
|
||||
- Returns: `200 { carrier: T30 }`
|
||||
- Returns: `200 { carrier: T34 }`
|
||||
|
||||
### Section: /category
|
||||
|
||||
@@ -315,8 +364,8 @@ _none_
|
||||
- Params: `id: int, body: { name?: str, parentId?: int }`
|
||||
- Returns: `200 { category: { id: int, name: str, slug: str, parentId: int, sort: int } }`
|
||||
#### Articles in category — `GET /category/{id}/articles`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { articles: { id: int, sku: str, name: str, slug: str, track_stock: bool, optionsCount: int, articleListCount: int, childCount: int, net?: num|null, taxRate?: num|null, parentArticleId?: int|null, parentSku?: str|null, fullHash?: str|null, thumbW?: int|null, thumbH?: int|null, thumbHash?: str|null, smallThumbW?: int|null, smallThumbH?: int|null, smallThumbBinary?: str|null, brand?: T25|null, articlewarehousesummary?: { id: int, articleId: int, warehouseId: int, stock: num, article_id?: int, warehouse_id?: int, warehouseName?: str|null }[], warehouses?: { id: int, name: str, stock: num }[] }[] }`
|
||||
- Params: `id: int, query: includeChildren?: bool`
|
||||
- Returns: `200 { articles: { id: int, sku: str, name: str, slug: str, track_stock: bool, optionsCount: int, articleListCount: int, childCount: int, net?: num|null, taxRate?: num|null, parentArticleId?: int|null, parentSku?: str|null, fullHash?: str|null, thumbW?: int|null, thumbH?: int|null, thumbHash?: str|null, smallThumbW?: int|null, smallThumbH?: int|null, smallThumbBinary?: str|null, brand?: T28|null, articlewarehousesummary?: { id: int, articleId: int, warehouseId: int, stock: num, article_id?: int, warehouse_id?: int, warehouseName?: str|null }[], warehouses?: { id: int, name: str, stock: num }[] }[] }`
|
||||
#### List category attribute values — `GET /category/{id}/attributevalue`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { attributevalues: { id: int, attributeId: int, attributeName: str, attributeValueId: int, value: str, sort: int, categoryId?: int, exclusive?: bool }[] }`
|
||||
@@ -329,6 +378,9 @@ _none_
|
||||
#### Add category image — `POST /category/{id}/image`
|
||||
- Params: `id: int, image/avif`
|
||||
- Returns: `201 { category: { id: int, thumbW: int, thumbH: int, thumbHash: str } }`
|
||||
#### Generate category mosaic image from contents — `POST /category/{id}/image/generate`
|
||||
- Params: `id: int, body?: { size?: int }`
|
||||
- Returns: `200 { category: { id: int, fullHash: str, thumbW: int, thumbH: int, thumbHash: str, size: int, grid: str, articleCount: int } }`
|
||||
#### List category properties — `GET /category/{id}/property`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { properties: { id: int, propertyId: int, name: str, exclusive: bool, value: str, sort: int, categoryId?: int }[] }`
|
||||
@@ -343,10 +395,10 @@ _none_
|
||||
|
||||
#### List companies — `GET /company`
|
||||
_none_
|
||||
- Returns: `200 { companies: T17[] }`
|
||||
- Returns: `200 { companies: T19[] }`
|
||||
#### Create company — `POST /company`
|
||||
- Params: `body: { iso639: str, name: str, taxrate: num, reducedtaxrate: num }`
|
||||
- Returns: `201 { company: T17, user: T32 }`
|
||||
- Returns: `201 { company: T19, user: T36 }`
|
||||
#### Export company catalog as zip archive (SSE) — `GET /company/export`
|
||||
- Params: `query: stream?: str`
|
||||
- Returns: `200 SSE`
|
||||
@@ -376,7 +428,22 @@ _none_
|
||||
- Returns: `204 void`
|
||||
#### Update company — `PUT /company/{id}`
|
||||
- Params: `id: int, body: { iso639: str, name: str, taxrate: num, reducedtaxrate: num }`
|
||||
- Returns: `200 { company: T17 }`
|
||||
- Returns: `200 { company: T19 }`
|
||||
|
||||
### Section: /companyuser
|
||||
|
||||
#### List company users — `GET /companyuser`
|
||||
_none_
|
||||
- Returns: `200 { companyusers: T31[] }`
|
||||
#### Add an existing user to the company — `POST /companyuser`
|
||||
- Params: `body: { email: str, role?: str }`
|
||||
- Returns: `201 { companyuser: T31 }`
|
||||
#### Remove a user from the company — `DELETE /companyuser/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
#### Change a company user's role — `PATCH /companyuser/{id}`
|
||||
- Params: `id: int, body: { role: str }`
|
||||
- Returns: `200 { companyuser: T31 }`
|
||||
|
||||
### Section: /customergroup
|
||||
|
||||
@@ -400,7 +467,7 @@ _none_
|
||||
|
||||
#### List deliveries — `GET /delivery`
|
||||
- Params: `query: offset?: int, limit?: int, search?: str, onlyUnbooked?: bool, supplierId?: int, seekMonths?: int`
|
||||
- Returns: `200 { deliveries: { id: int, number: str, type: str, supplierId: int, date: str, externalNumber?: str|null, createdAt?: str, ledger?: T36 }[], total: int, unfilteredTotal: int, offset: int, limit: int }`
|
||||
- Returns: `200 { deliveries: { id: int, number: str, type: str, supplierId: int, date: str, externalNumber?: str|null, createdAt?: str, ledger?: T40 }[], total: int, unfilteredTotal: int, offset: int, limit: int }`
|
||||
#### Create delivery — `POST /delivery`
|
||||
- Params: `body: { externalNumber: str, date: str, supplierId: int, lines: { amount: num, net: num, taxrate: num, sku?: str|null, name?: str|null, pu?: num, rebate?: num, comment?: str|null }[], files?: { mimetype: str, name: str, content: str, sort?: int, size?: int, hash?: str, created?: str, modified?: str, meta?: { [k]: str } }[] }`
|
||||
- Returns: `201 { delivery: T4 }`
|
||||
@@ -421,52 +488,52 @@ _none_
|
||||
- Returns: `200 str`
|
||||
#### Generate and attach delivery note PDF (goods receipt) — `POST /delivery/{id}/pdf`
|
||||
- Params: `id: int`
|
||||
- Returns: `201 { attachment: T9, fileUrl: str }`
|
||||
- Returns: `201 { attachment: T10, fileUrl: str }`
|
||||
|
||||
### Section: /entity
|
||||
|
||||
#### List entities — `GET /entity`
|
||||
- Params: `query: customergroupId?: int, role?: str`
|
||||
- Returns: `200 { entities: T24[] }`
|
||||
- Returns: `200 { entities: T27[] }`
|
||||
#### Create entity — `POST /entity`
|
||||
- Params: `body: { customergroupId: int, name: str, firstName?: str|null, number?: str }`
|
||||
- Returns: `201 { entity: T24 }`
|
||||
- Returns: `201 { entity: T27 }`
|
||||
#### Peek next customer number — `GET /entity/next-number`
|
||||
_none_
|
||||
- Returns: `200 { number: str }`
|
||||
#### List entity addresses — `GET /entity/{entityId}/address`
|
||||
- Params: `entityId: int`
|
||||
- Returns: `200 { addresses: T12[] }`
|
||||
- Returns: `200 { addresses: T14[] }`
|
||||
#### Create entity address — `POST /entity/{entityId}/address`
|
||||
- Params: `entityId: int, body: { addressType: str, firstName?: str|null, name?: str|null, street?: str|null, streetNumber?: str|null, zip?: str|null, city?: str|null, county?: str|null }`
|
||||
- Returns: `201 { address: T12 }`
|
||||
- Returns: `201 { address: T14 }`
|
||||
#### Delete entity address — `DELETE /entity/{entityId}/address/{id}`
|
||||
- Params: `entityId: int, id: int`
|
||||
- Returns: `204 void`
|
||||
#### Update entity address — `PATCH /entity/{entityId}/address/{id}`
|
||||
- Params: `entityId: int, id: int, body: { addressType?: str, firstName?: str|null, name?: str|null, street?: str|null, streetNumber?: str|null, zip?: str|null, city?: str|null, county?: str|null }`
|
||||
- Returns: `200 { address: T12 }`
|
||||
- Returns: `200 { address: T14 }`
|
||||
#### List entity contacts — `GET /entity/{entityId}/contact`
|
||||
- Params: `entityId: int`
|
||||
- Returns: `200 { contacts: T34[] }`
|
||||
- Returns: `200 { contacts: T38[] }`
|
||||
#### Create entity contact — `POST /entity/{entityId}/contact`
|
||||
- Params: `entityId: int, body: { contactType: str, contact: str }`
|
||||
- Returns: `201 { contact: T34 }`
|
||||
- Returns: `201 { contact: T38 }`
|
||||
#### Delete entity contact — `DELETE /entity/{entityId}/contact/{id}`
|
||||
- Params: `entityId: int, id: int`
|
||||
- Returns: `204 void`
|
||||
#### Update entity contact — `PATCH /entity/{entityId}/contact/{id}`
|
||||
- Params: `entityId: int, id: int, body: { contactType?: str, contact?: str }`
|
||||
- Returns: `200 { contact: T34 }`
|
||||
- Returns: `200 { contact: T38 }`
|
||||
#### Delete entity — `DELETE /entity/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
#### Get entity — `GET /entity/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { entity: T24 }`
|
||||
- Returns: `200 { entity: T27 }`
|
||||
#### Update entity — `PATCH /entity/{id}`
|
||||
- Params: `id: int, body: { name?: str, firstName?: str|null, number?: str|null }`
|
||||
- Returns: `200 { entity: T24 }`
|
||||
- Returns: `200 { entity: T27 }`
|
||||
|
||||
### Section: /events
|
||||
|
||||
@@ -475,6 +542,8 @@ _none_
|
||||
- Returns: `200 SSE`
|
||||
|
||||
- Events:
|
||||
- `user`: `{ selectedCompanyId }`
|
||||
- `company`: `{ companyId }`
|
||||
- `category`: `{}`
|
||||
- `articles`: `{}`
|
||||
- `article-<sku>`: `{}`
|
||||
@@ -482,9 +551,15 @@ _none_
|
||||
- `ledger`: `{}`
|
||||
- `attributename`: `{}`
|
||||
- `propertyname`: `{}`
|
||||
- `companyuser`: `{}`
|
||||
- `autoinvite`: `{}`
|
||||
- `labeltemplate`: `{}`
|
||||
- `printer`: `{}`
|
||||
- `printeragent`: `{}`
|
||||
- `agentprinter`: `{ printers } or {}`
|
||||
- `printerjob`: `{ job } or { jobId, state }`
|
||||
- `warehouse`: `{}`
|
||||
- `supplier`: `{}`
|
||||
- `vfs`: `{}`
|
||||
- `modelconversation`: `{}`
|
||||
- `modelconversation-<id>`: `{}`
|
||||
@@ -511,35 +586,38 @@ _none_
|
||||
_none_
|
||||
- Returns: `200 { labeltemplates: { id: int, name: str, width: num, height: num, dpi: int, type: str, thumb?: str|null }[] }`
|
||||
#### Create label template — `POST /labeltemplate`
|
||||
- Params: `body: { name: str, width: num, height: num, dpi: int, type: str, content: { objects: T22[] } }`
|
||||
- Returns: `201 { labeltemplate: T8 }`
|
||||
- Params: `body: { name: str, width: num, height: num, dpi: int, type: str, content: { objects: T25[] } }`
|
||||
- Returns: `201 { labeltemplate: T9 }`
|
||||
#### Test print label template — `POST /labeltemplate/testprint`
|
||||
- Params: `body: { agentprinterId: int, templateId?: int, objects?: any[], width?: int, height?: int, dpi?: int, sku?: str, quantity?: int }`
|
||||
- Returns: `200 { success: bool }`
|
||||
#### Delete label template — `DELETE /labeltemplate/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
#### Get label template by ID — `GET /labeltemplate/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { labeltemplate: T8 }`
|
||||
- Returns: `200 { labeltemplate: T9 }`
|
||||
#### Update label template (partial) — `PATCH /labeltemplate/{id}`
|
||||
- Params: `id: int, body: { name?: str, width?: num, height?: num, dpi?: int, type?: str, content?: { objects: T22[] } }`
|
||||
- Returns: `200 { labeltemplate: T8 }`
|
||||
- Params: `id: int, body: { name?: str, width?: num, height?: num, dpi?: int, type?: str, content?: { objects: T25[] } }`
|
||||
- Returns: `200 { labeltemplate: T9 }`
|
||||
#### Update label template — `PUT /labeltemplate/{id}`
|
||||
- Params: `id: int, body: { name?: str, width?: num, height?: num, dpi?: int, type?: str, content?: { objects: T22[] } }`
|
||||
- Returns: `200 { labeltemplate: T8 }`
|
||||
- Params: `id: int, body: { name?: str, width?: num, height?: num, dpi?: int, type?: str, content?: { objects: T25[] } }`
|
||||
- Returns: `200 { labeltemplate: T9 }`
|
||||
|
||||
### Section: /ledger
|
||||
|
||||
#### Query ledger by manifest article ID or SKU — `GET /ledger`
|
||||
- Params: `query: manifestarticle_id?: int, sku?: str, transaction_type?: str`
|
||||
- Returns: `200 { ledger: T14[] }`
|
||||
- Returns: `200 { ledger: T16[] }`
|
||||
#### Query company-wide ledger history — `GET /ledger/history`
|
||||
- Params: `query: offset?: int, limit?: int, search?: str, seekMonths?: int`
|
||||
- Returns: `200 { ledger: { id: int, date: str, transaction_type: str, transaction_text: str, sku?: str|null, name?: str|null, amount?: num }[], total: int, unfilteredTotal: int, offset: int, limit: int }`
|
||||
#### Query ledger by manifest article ID — `GET /ledger/manifestarticle/{manifestarticleId}`
|
||||
- Params: `manifestarticleId: int, query: transaction_type?: str`
|
||||
- Returns: `200 { ledger: T14[] }`
|
||||
- Returns: `200 { ledger: T16[] }`
|
||||
#### Query ledger by article SKU — `GET /ledger/sku/{sku}`
|
||||
- Params: `sku: str, query: transaction_type?: str`
|
||||
- Returns: `200 { ledger: T14[] }`
|
||||
- Returns: `200 { ledger: T16[] }`
|
||||
|
||||
### Section: /mcp
|
||||
|
||||
@@ -569,16 +647,16 @@ _none_
|
||||
|
||||
#### List conversations — `GET /modelconversation`
|
||||
_none_
|
||||
- Returns: `200 { conversations: T16[] }`
|
||||
- Returns: `200 { conversations: T18[] }`
|
||||
#### Create conversation — `POST /modelconversation`
|
||||
- Params: `body: { provider: str, model: str }`
|
||||
- Returns: `201 { conversation: T16 }`
|
||||
- Returns: `201 { conversation: T18 }`
|
||||
#### Delete conversation — `DELETE /modelconversation/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
#### Get conversation — `GET /modelconversation/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { conversation: T16 }`
|
||||
- Returns: `200 { conversation: T18 }`
|
||||
#### List conversation messages — `GET /modelconversation/{id}/message`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { messages: { id: int, conversation_id: int, created_at: str, role: str, message: str }[] }`
|
||||
@@ -619,7 +697,7 @@ _none_
|
||||
- Params: `query: offset?: int, limit?: int, search?: str, onlyUnpaid?: bool, onlyUndelivered?: bool, seekMonths?: int`
|
||||
- Returns: `200 { orders: T1[], total: int, unfilteredTotal: int, offset: int, limit: int }`
|
||||
#### Create order — `POST /order`
|
||||
- Params: `body: { number: str, date: str, entityId: int, lines: T19[], externalNumber?: str|null }`
|
||||
- Params: `body: { number: str, date: str, entityId: int, lines: T21[], externalNumber?: str|null }`
|
||||
- Returns: `201 { order: T1 }`
|
||||
#### Delete order — `DELETE /order/{id}`
|
||||
- Params: `id: int`
|
||||
@@ -628,7 +706,7 @@ _none_
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { order: T1 }`
|
||||
#### Update order — `PATCH /order/{id}`
|
||||
- Params: `id: int, body: { number?: str, date?: str, entityId?: int|null, externalNumber?: str|null, lines?: T19[] }`
|
||||
- Params: `id: int, body: { number?: str, date?: str, entityId?: int|null, externalNumber?: str|null, lines?: T21[] }`
|
||||
- Returns: `200 { order: T1 }`
|
||||
#### Delete order file attachment — `DELETE /order/{id}/file/{fileId}`
|
||||
- Params: `id: int, fileId: int`
|
||||
@@ -638,13 +716,13 @@ _none_
|
||||
- Returns: `200 str`
|
||||
#### List payments of an order — `GET /order/{id}/payment`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { payments: T29[] }`
|
||||
- Returns: `200 { payments: T33[] }`
|
||||
#### Add payment to an order — `POST /order/{id}/payment`
|
||||
- Params: `id: int, body: { accountId: int, type: str, amount: num }`
|
||||
- Returns: `201 { payment: T29 }`
|
||||
- Returns: `201 { payment: T33 }`
|
||||
#### Generate and attach order PDF — `POST /order/{id}/pdf`
|
||||
- Params: `id: int`
|
||||
- Returns: `201 { attachment: T9, fileUrl: str }`
|
||||
- Returns: `201 { attachment: T10, fileUrl: str }`
|
||||
#### List shipments of an order — `GET /order/{id}/shipment`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { shipments: T2[] }`
|
||||
@@ -653,10 +731,10 @@ _none_
|
||||
- Returns: `201 { shipment: T2 }`
|
||||
#### List shippings of an order — `GET /order/{id}/shipping`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { shippings: T20[] }`
|
||||
- Returns: `200 { shippings: T23[] }`
|
||||
#### Create shipping for an order — `POST /order/{id}/shipping`
|
||||
- Params: `id: int, body: { carrierId: int, type: str, state: str, trackingCode?: str, warehouseId?: int }`
|
||||
- Returns: `201 { shipping: T20 }`
|
||||
- Returns: `201 { shipping: T23 }`
|
||||
|
||||
### Section: /package
|
||||
|
||||
@@ -674,26 +752,26 @@ _none_
|
||||
|
||||
#### List POS terminals — `GET /posterminal`
|
||||
_none_
|
||||
- Returns: `200 { posterminals: T10[] }`
|
||||
- Returns: `200 { posterminals: T7[] }`
|
||||
#### Create POS terminal — `PUT /posterminal`
|
||||
- Params: `body: { name: str, rootCategoryId?: int|null, syncRootArticles?: bool }`
|
||||
- Returns: `200 { posterminal: T10 }`
|
||||
- Params: `body: { name: str, rootCategoryId?: int|null, syncRootArticles?: bool, sort?: int, enabled?: bool }`
|
||||
- Returns: `200 { posterminal: T7 }`
|
||||
#### Delete POS terminal — `DELETE /posterminal/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
#### Update POS terminal — `PATCH /posterminal/{id}`
|
||||
- Params: `id: int, body: { name?: str, rootCategoryId?: int|null, syncRootArticles?: bool, pairingpin?: str|null }`
|
||||
- Returns: `200 { posterminal: T10 }`
|
||||
- Params: `id: int, body: { name?: str, rootCategoryId?: int|null, syncRootArticles?: bool, sort?: int, enabled?: bool, pairingpin?: str|null }`
|
||||
- Returns: `200 { posterminal: T7 }`
|
||||
#### Disable all categories on terminal — `DELETE /posterminal/{id}/all`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { id: int, categoryIds: int[] }`
|
||||
#### Enable all categories on terminal — `PUT /posterminal/{id}/all`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { id: int, categoryIds: int[] }`
|
||||
#### Disable category on terminal — `DELETE /posterminal/{id}/category/{categoryId}`
|
||||
#### Disable category and subcategories on terminal — `DELETE /posterminal/{id}/category/{categoryId}`
|
||||
- Params: `id: int, categoryId: int`
|
||||
- Returns: `200 { id: int, categoryIds: int[] }`
|
||||
#### Enable category on terminal — `PUT /posterminal/{id}/category/{categoryId}`
|
||||
#### Enable category and subcategories on terminal — `PUT /posterminal/{id}/category/{categoryId}`
|
||||
- Params: `id: int, categoryId: int`
|
||||
- Returns: `200 { id: int, categoryIds: int[] }`
|
||||
|
||||
@@ -701,34 +779,76 @@ _none_
|
||||
|
||||
#### List printers — `GET /printer`
|
||||
_none_
|
||||
- Returns: `200 { printers: T23[] }`
|
||||
- Returns: `200 { printers: T26[] }`
|
||||
#### Create printer — `POST /printer`
|
||||
- Params: `body: { address: str, type: str, model?: str|null, serial?: str|null, sort?: int, desc?: str|null }`
|
||||
- Returns: `201 { printer: T23 }`
|
||||
- Returns: `201 { printer: T26 }`
|
||||
#### Reorder printers — `PUT /printer/order`
|
||||
- Params: `body: { printerIds: int[] }`
|
||||
- Returns: `200 { printerIds: int[] }`
|
||||
#### Get live printer states — `GET /printer/state`
|
||||
- Params: `query: serial?: str, agentId?: int`
|
||||
- Returns: `200 { printers: {}[] }`
|
||||
#### Delete printer — `DELETE /printer/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
#### Get printer by ID — `GET /printer/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { printer: T23 }`
|
||||
- Returns: `200 { printer: T26 }`
|
||||
#### Update printer (partial) — `PATCH /printer/{id}`
|
||||
- Params: `id: int, body: { address?: str, type?: str, model?: str|null, serial?: str|null, sort?: int, desc?: str|null }`
|
||||
- Returns: `200 { printer: T23 }`
|
||||
- Returns: `200 { printer: T26 }`
|
||||
#### Update printer — `PUT /printer/{id}`
|
||||
- Params: `id: int, body: { address?: str, type?: str, model?: str|null, serial?: str|null, sort?: int, desc?: str|null }`
|
||||
- Returns: `200 { printer: T23 }`
|
||||
- Returns: `200 { printer: T26 }`
|
||||
#### Get live state for a printer — `GET /printer/{id}/state`
|
||||
- Params: `id: str`
|
||||
- Returns: `200 { printer: {} }`
|
||||
|
||||
### Section: /printeragent
|
||||
|
||||
#### List printer agents — `GET /printeragent`
|
||||
_none_
|
||||
- Returns: `200 { printeragents: T12[] }`
|
||||
#### Create printer agent — `PUT /printeragent`
|
||||
- Params: `body: { name: str, sort?: int, enabled?: bool }`
|
||||
- Returns: `200 { printeragent: T12 }`
|
||||
#### Delete printer agent — `DELETE /printeragent/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
#### Update printer agent — `PATCH /printeragent/{id}`
|
||||
- Params: `id: int, body: { name?: str, sort?: int, enabled?: bool }`
|
||||
- Returns: `200 { printeragent: T12 }`
|
||||
|
||||
### Section: /printerjob
|
||||
|
||||
#### List printer jobs — `GET /printerjob`
|
||||
- Params: `query: agentprinterId?: int, state?: str`
|
||||
- Returns: `200 { printerjobs: T22[] }`
|
||||
#### Create print job — `POST /printerjob`
|
||||
- Params: `body: { agentprinterId: int, data: str, type?: str }`
|
||||
- Returns: `201 { printerjob: T22 }`
|
||||
#### Cancel all pending and processing printer jobs — `POST /printerjob/cancel-all`
|
||||
- Params: `body?: { agentprinterId?: int }`
|
||||
- Returns: `200 { success: bool, cancelledCount: int, jobs: T22[] }`
|
||||
#### Cancel and delete printer job — `DELETE /printerjob/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { success: bool, deletedJob: T22 }`
|
||||
#### Get printer job — `GET /printerjob/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { printerjob: T22 }`
|
||||
#### Cancel printer job — `POST /printerjob/{id}/cancel`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { success: bool, printerjob: T22 }`
|
||||
|
||||
### Section: /propertyname
|
||||
|
||||
#### List property names — `GET /propertyname`
|
||||
_none_
|
||||
- Returns: `200 { propertynames: T28[] }`
|
||||
- Returns: `200 { propertynames: T32[] }`
|
||||
#### Create property name — `POST /propertyname`
|
||||
- Params: `body: { name: str, sort?: int, exclusive?: bool }`
|
||||
- Returns: `201 { propertyname: T28 }`
|
||||
- Returns: `201 { propertyname: T32 }`
|
||||
#### Reorder property names — `PUT /propertyname/order`
|
||||
- Params: `body: { propertynameIds: int[] }`
|
||||
- Returns: `200 { ok: bool }`
|
||||
@@ -737,7 +857,7 @@ _none_
|
||||
- Returns: `200 { ok: bool }`
|
||||
#### Update property name — `PATCH /propertyname/{id}`
|
||||
- Params: `id: int, body: { name?: str, sort?: int, exclusive?: bool }`
|
||||
- Returns: `200 { propertyname: T28 }`
|
||||
- Returns: `200 { propertyname: T32 }`
|
||||
|
||||
### Section: /public
|
||||
|
||||
@@ -749,7 +869,7 @@ _none_
|
||||
- Returns: `200 { articles: { id: int, sku: str, name: str, slug: str, net: num|null, taxRate: num|null, gross: num|null, trackStock: bool, brand: { id: int|null, name: str }, fullHash: str|null, thumbW: int|null, thumbH: int|null, thumbHash: str|null }[] }`
|
||||
#### Get public article detail — `GET /public/{companyId}/articles/{sku}`
|
||||
- Params: `companyId: int, sku: str`
|
||||
- Returns: `200 { article: { id: int, sku: str, name: str, slug: str, description: str, unitamount: num|null, weight: num|null, trackStock: bool, unit: T26|null, brand: T25|null, price: { minmultiplier: num, net: num|null, taxRate: num|null, gross: num|null }, prices: { minmultiplier: num, net: num|null, taxRate: num|null, gross: num|null }[], categories: { id: int, name: str, slug: str }[], photos: { sort: int, fullHash: str, fullW: int, fullH: int, fullSize: int, thumbW: int, thumbH: int, thumbHash: str }[], eans: str[], isParent: bool, parentSku: str|null, variants: { id: int, sku: str, sort: int, name: str, slug: str, attributeValueId: int|null, attributeValue: str|null, unitamount: num|null, weight: num|null, trackStock: bool }[] } }`
|
||||
- Returns: `200 { article: { id: int, sku: str, name: str, slug: str, description: str, unitamount: num|null, weight: num|null, trackStock: bool, unit: T29|null, brand: T28|null, price: { minmultiplier: num, net: num|null, taxRate: num|null, gross: num|null }, prices: { minmultiplier: num, net: num|null, taxRate: num|null, gross: num|null }[], categories: { id: int, name: str, slug: str }[], photos: { sort: int, fullHash: str, fullW: int, fullH: int, fullSize: int, thumbW: int, thumbH: int, thumbHash: str }[], eans: str[], isParent: bool, parentSku: str|null, variants: { id: int, sku: str, sort: int, name: str, slug: str, attributeValueId: int|null, attributeValue: str|null, unitamount: num|null, weight: num|null, trackStock: bool }[] } }`
|
||||
#### List public categories — `GET /public/{companyId}/categories`
|
||||
- Params: `companyId: int`
|
||||
- Returns: `200 { categories: { id: int, parentId: int|null, sort: int, name: str, slug: str, fullHash: str|null, thumbW: int|null, thumbH: int|null, thumbHash: str|null }[] }`
|
||||
@@ -760,7 +880,7 @@ _none_
|
||||
- Params: `query: offset?: int, limit?: int, search?: str, seekMonths?: int`
|
||||
- Returns: `200 { quotes: T3[], total: int, unfilteredTotal: int, offset: int, limit: int }`
|
||||
#### Create quote — `POST /quote`
|
||||
- Params: `body: { number: str, date: str, lines: T19[], entityId?: int|null, externalNumber?: str|null }`
|
||||
- Params: `body: { number: str, date: str, lines: T21[], entityId?: int|null, externalNumber?: str|null }`
|
||||
- Returns: `201 { quote: T3 }`
|
||||
#### Delete quote — `DELETE /quote/{id}`
|
||||
- Params: `id: int`
|
||||
@@ -769,7 +889,7 @@ _none_
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { quote: T3 }`
|
||||
#### Update quote — `PATCH /quote/{id}`
|
||||
- Params: `id: int, body: { number?: str, date?: str, entityId?: int|null, externalNumber?: str|null, lines?: T19[] }`
|
||||
- Params: `id: int, body: { number?: str, date?: str, entityId?: int|null, externalNumber?: str|null, lines?: T21[] }`
|
||||
- Returns: `200 { quote: T3 }`
|
||||
#### Delete quote file attachment — `DELETE /quote/{id}/file/{fileId}`
|
||||
- Params: `id: int, fileId: int`
|
||||
@@ -778,11 +898,59 @@ _none_
|
||||
- Params: `id: int, fileId: int, query: download?: bool`
|
||||
- Returns: `200 str`
|
||||
#### Create order from quote — `POST /quote/{id}/order`
|
||||
- Params: `id: int, body?: { number?: str, date?: str, createdAt?: str, entityId?: int|null, externalNumber?: str|null, lines?: T19[] }`
|
||||
- Params: `id: int, body?: { number?: str, date?: str, createdAt?: str, entityId?: int|null, externalNumber?: str|null, lines?: T21[] }`
|
||||
- Returns: `201 { order: T1 }`
|
||||
#### Generate and attach quote PDF — `POST /quote/{id}/pdf`
|
||||
- Params: `id: int`
|
||||
- Returns: `201 { attachment: T9, fileUrl: str }`
|
||||
- Returns: `201 { attachment: T10, fileUrl: str }`
|
||||
|
||||
### Section: /retoure
|
||||
|
||||
#### List retoures — `GET /retoure`
|
||||
- Params: `query: offset?: int, limit?: int, search?: str, onlyUnpaid?: bool, onlyUndelivered?: bool, entityId?: int, seekMonths?: int`
|
||||
- Returns: `200`
|
||||
#### Create retoure — `POST /retoure`
|
||||
- Params: `body: { date: str, number?: str, entityId?: int, externalNumber?: str, lines?: any[] }`
|
||||
- Returns: `201`
|
||||
#### Rebuild retoure summaries — `POST /retoure/rebuild-summaries`
|
||||
_none_
|
||||
- Returns: `200`
|
||||
#### Delete retoure — `DELETE /retoure/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
#### Get retoure by ID — `GET /retoure/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `200`
|
||||
#### Update retoure — `PUT /retoure/{id}`
|
||||
- Params: `id: int, body: {}`
|
||||
- Returns: `200`
|
||||
#### Create shipment for retoure — `POST /retoure/{id}/shipment`
|
||||
- Params: `id: int`
|
||||
- Returns: `201`
|
||||
|
||||
### Section: /return
|
||||
|
||||
#### List returns — `GET /return`
|
||||
- Params: `query: offset?: int, limit?: int, search?: str, onlyUnbooked?: bool, supplierId?: int`
|
||||
- Returns: `200`
|
||||
#### Create return — `POST /return`
|
||||
- Params: `body: {}`
|
||||
- Returns: `201`
|
||||
#### Rebuild return summaries — `POST /return/rebuild-summaries`
|
||||
_none_
|
||||
- Returns: `200`
|
||||
#### Delete return — `DELETE /return/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
#### Get return by ID — `GET /return/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `200`
|
||||
#### Update return — `PUT /return/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `200`
|
||||
#### Book return to ledger — `POST /return/{id}/book`
|
||||
- Params: `id: int`
|
||||
- Returns: `200`
|
||||
|
||||
### Section: /serper
|
||||
|
||||
@@ -821,13 +989,13 @@ _none_
|
||||
- Returns: `200 str`
|
||||
#### Generate and attach shipment PDF (delivery note) — `POST /shipment/{id}/pdf`
|
||||
- Params: `id: int`
|
||||
- Returns: `201 { attachment: T9, fileUrl: str }`
|
||||
- Returns: `201 { attachment: T10, fileUrl: str }`
|
||||
#### List packages of a shipment — `GET /shipment/{id}/shipping`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { shippings: T20[] }`
|
||||
- Returns: `200 { shippings: T23[] }`
|
||||
#### Create package for a shipment — `POST /shipment/{id}/shipping`
|
||||
- Params: `id: int, body: { carrierId: int, type: str, state: str, trackingCode?: str, warehouseId?: int }`
|
||||
- Returns: `201 { shipping: T20 }`
|
||||
- Returns: `201 { shipping: T23 }`
|
||||
|
||||
### Section: /shipping
|
||||
|
||||
@@ -836,7 +1004,7 @@ _none_
|
||||
- Returns: `204 void`
|
||||
#### Update shipping — `PATCH /shipping/{id}`
|
||||
- Params: `id: int, body: { type?: str, state?: str, trackingCode?: str, carrierId?: int, warehouseId?: int }`
|
||||
- Returns: `200 { shipping: T20 }`
|
||||
- Returns: `200 { shipping: T23 }`
|
||||
#### List packages of a shipping — `GET /shipping/{id}/package`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { packages: { id: int, shippingId: int, entityaddressId: int, number: str, type: str, state: str, details?: str|null }[] }`
|
||||
@@ -857,7 +1025,7 @@ _none_
|
||||
- Returns: `200`
|
||||
#### Adjust stock manually — `POST /stock/adjust`
|
||||
- Params: `body: { sku?: str, warehouseId?: int, amount?: num, text?: str|null, lines?: { sku: str, amount: num, warehouseId?: int, text?: str }[] }`
|
||||
- Returns: `201 { manifest: { id: int, number: str, type: str, date: str, createdAt: str }, lines: { manifestarticle_id: int, sku: str, name: str, warehouse_id: int, amount: num, text: str }[], ledger: T14[] }`
|
||||
- Returns: `201 { manifest: { id: int, number: str, type: str, date: str, createdAt: str }, lines: { manifestarticle_id: int, sku: str, name: str, warehouse_id: int, amount: num, text: str }[], ledger: T16[] }`
|
||||
#### Ship shipment manifest item(s) — `POST /stock/ship`
|
||||
- Params: `body: { manifestarticleId?: int, warehouseId?: int, items?: { manifestarticleId: int, warehouseId?: int }[] }`
|
||||
- Returns: `200`
|
||||
@@ -866,40 +1034,40 @@ _none_
|
||||
|
||||
#### List subagent schedules — `GET /subagentschedule`
|
||||
_none_
|
||||
- Returns: `200 { schedules: T13[] }`
|
||||
- Returns: `200 { schedules: T15[] }`
|
||||
#### Create subagent schedule — `POST /subagentschedule`
|
||||
- Params: `body: { prompt: str, cron: str, desc?: str|null, skills?: str|null, lastagentnote?: str|null, max_itr?: int }`
|
||||
- Returns: `201 { schedule: T13 }`
|
||||
- Returns: `201 { schedule: T15 }`
|
||||
#### Delete subagent schedule — `DELETE /subagentschedule/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
#### Get subagent schedule by ID — `GET /subagentschedule/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { schedule: T13 }`
|
||||
- Returns: `200 { schedule: T15 }`
|
||||
#### Update subagent schedule — `PUT /subagentschedule/{id}`
|
||||
- Params: `id: int, body: { prompt?: str, cron?: str, desc?: str|null, skills?: str|null, lastagentnote?: str|null, max_itr?: int, lastrun_at?: str|null }`
|
||||
- Returns: `200 { schedule: T13 }`
|
||||
- Returns: `200 { schedule: T15 }`
|
||||
|
||||
### Section: /supplier
|
||||
|
||||
#### List suppliers — `GET /supplier`
|
||||
_none_
|
||||
- Returns: `200 { suppliers: T35[] }`
|
||||
- Returns: `200 { suppliers: T39[] }`
|
||||
#### Create supplier — `POST /supplier`
|
||||
- Params: `body: { name: str }`
|
||||
- Returns: `201 { supplier: T35 }`
|
||||
- Returns: `201 { supplier: T39 }`
|
||||
#### Delete supplier — `DELETE /supplier/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
#### Update supplier — `PATCH /supplier/{id}`
|
||||
- Params: `id: int, body: { name: str }`
|
||||
- Returns: `200 { supplier: T35 }`
|
||||
- Returns: `200 { supplier: T39 }`
|
||||
#### List supplier articles by SKUs — `GET /supplier/{id}/articles`
|
||||
- Params: `id: int, query: skus?: str`
|
||||
- Returns: `200 { articles: { id: int, articleId: int, entityId: int, pu: num, sort: int, article: { id: int, sku: str, name?: str|null, slug?: str|null, photos?: { sort: int, fullHash: str, thumbW: int, thumbH: int, thumbHash: str }[], eans?: str[] }, supplierName?: str|null, sku?: str|null, stock?: num|null, priceId?: int|null, price?: T38|null, incoming?: { date: str, amount: num }[] }[] }`
|
||||
- Returns: `200 { articles: { id: int, articleId: int, entityId: int, pu: num, sort: int, article: { id: int, sku: str, name?: str|null, slug?: str|null, photos?: { sort: int, fullHash: str, thumbW: int, thumbH: int, thumbHash: str }[], eans?: str[] }, supplierName?: str|null, sku?: str|null, stock?: num|null, priceId?: int|null, price?: T42|null, incoming?: { date: str, amount: num }[] }[] }`
|
||||
#### Query supplier articles by SKUs (bulk) — `POST /supplier/{id}/articles`
|
||||
- Params: `id: int, body?: { skus?: str[] }`
|
||||
- Returns: `200 { articles: { id: int, articleId: int, entityId: int, pu: num, sort: int, article: { id: int, sku: str, name?: str|null, slug?: str|null, photos?: { sort: int, fullHash: str, thumbW: int, thumbH: int, thumbHash: str }[], eans?: str[] }, supplierName?: str|null, sku?: str|null, stock?: num|null, priceId?: int|null, price?: T38|null, incoming?: { date: str, amount: num }[] }[] }`
|
||||
- Returns: `200 { articles: { id: int, articleId: int, entityId: int, pu: num, sort: int, article: { id: int, sku: str, name?: str|null, slug?: str|null, photos?: { sort: int, fullHash: str, thumbW: int, thumbH: int, thumbHash: str }[], eans?: str[] }, supplierName?: str|null, sku?: str|null, stock?: num|null, priceId?: int|null, price?: T42|null, incoming?: { date: str, amount: num }[] }[] }`
|
||||
|
||||
### Section: /thumb
|
||||
|
||||
@@ -914,24 +1082,39 @@ _none_
|
||||
- Returns: `204 void`
|
||||
#### List units — `GET /unit`
|
||||
_none_
|
||||
- Returns: `200 { units: T26[] }`
|
||||
- Returns: `200 { units: T29[] }`
|
||||
#### Upsert unit — `PUT /unit`
|
||||
- Params: `body: { si: str, basesi: str, basesifactor: num, symbol: str, name: str }`
|
||||
- Returns: `200 { unit: T26 }`
|
||||
- Returns: `200 { unit: T29 }`
|
||||
|
||||
### Section: /v1
|
||||
|
||||
#### JTL-POS category synchronization — `GET /v1/category`
|
||||
- Params: `query: lastChangedCategory?: str, limit?: int`
|
||||
- Returns: `200 {}[]`
|
||||
#### POS category image delivery — `GET /v1/cimage`
|
||||
- Params: `query: path: str, size?: int, w?: int, h?: int, format?: str`
|
||||
- Returns: `200 jpeg`
|
||||
#### POS discovery and pairing — `GET /v1/client`
|
||||
- Params: `query: authCode: str, name?: str`
|
||||
- Params: `query: authCode: str, name?: str, clientversion?: str`
|
||||
- Returns: `200 { authCode: str|null, authToken: str|null, certificateFingerprint: str, certificateSerialNumber: str, mandantId: str, mandantName: str|null, mandantDatabase: str|null, serverFingerprint: str|null, name: str|null, serverTimestamp: str }`
|
||||
#### JTL-POS customer catalog synchronization — `GET /v1/customer`
|
||||
- Params: `query: lastChangedCustomer?: str, limit?: int`
|
||||
- Returns: `200 { id: str, customerNumber: str, firstname: str, lastname: str, title: str, company: str, address: str, addressSupplement: str, city: str, postalCode: str, state: str, country: str, phone: str, email: str, customerGroupId: str, salutation: str, birthday: str, discount: str, taxIdNumber: str, lastChanged: str, debtorNumber: str }[]`
|
||||
#### JTL-POS customer group synchronization — `GET /v1/customergroup`
|
||||
- Params: `query: lastChangedCustomerGroup?: str, limit?: int`
|
||||
- Returns: `200 { customerGroupId: str, name: str, standard: str, discountPercent: str, lastChanged: str }[]`
|
||||
#### JTL-POS deleted entity synchronization — `GET /v1/deletedentity`
|
||||
- Params: `query: lastChangedDeletedEntity?: str, limit?: int`
|
||||
- Returns: `200 { entityId: str, entityType: int, lastChanged: int }[]`
|
||||
#### POS sync initialization counts — `GET /v1/init`
|
||||
- Params: `query: lastChangedProduct?: int, lastChangedCategory?: int, lastChangedCustomer?: int, lastChangedCustomerGroup?: int, lastChangedCompositeProduct?: int, lastChangedDeletedEntity?: int`
|
||||
- Returns: `200 { version: str, product_count: str, category_count: str, customer_count: str, customerGroup_count: str, compositeProduct_count: str, configurationGroup_count: str, configurationItem_count: str, deletedEntity_count: str, max_orderId_count: str }`
|
||||
#### JTL-POS order upload — `POST /v1/order`
|
||||
- Params: `query: mandantId?: str, body: { orders?: {}[] }`
|
||||
- Returns: `200 { status: str, externalOrderId: str, message: str }[]`
|
||||
#### POS product image delivery — `GET /v1/pimage`
|
||||
- Params: `query: path: str, w?: int, h?: int, format?: str`
|
||||
- Params: `query: path: str, size?: int, w?: int, h?: int, format?: str`
|
||||
- Returns: `200 jpeg`
|
||||
#### JTL-POS product catalog synchronization — `GET /v1/product`
|
||||
- Params: `query: lastChangedProduct?: str, limit?: int`
|
||||
@@ -993,3 +1176,9 @@ _none_
|
||||
#### Update warehouse — `PUT /warehouse/{id}`
|
||||
- Params: `id: int, body: { name?: str, sort?: int }`
|
||||
- Returns: `200 { warehouse: { id: int, name: str, sort: int } }`
|
||||
|
||||
### Section: /zpljob
|
||||
|
||||
#### Create ZPL print job — `POST /zpljob`
|
||||
- Params: `body: { agentprinterId: int, data: str, copiescount?: int }`
|
||||
- Returns: `201 { printerjob: T22 }`
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Dash API Routes Overview
|
||||
|
||||
Overview of all 187 API endpoints across all modules.
|
||||
Overview of all 196 API endpoints across all modules.
|
||||
|
||||
### Notation
|
||||
|
||||
@@ -9,34 +9,33 @@ Params: path values first, then `query:` and `body:` (`body?` = optional body).
|
||||
|
||||
### Reusable types
|
||||
|
||||
- `T1` = `{ id: int, number: str, type: str, entityId: int, date: str, lines: T12[], externalNumber?: str|null, createdAt?: str, shipping?: T14|null, shippings?: T14[], payment?: T22|null, payments?: T22[], paid?: bool, shipped?: bool, delivered?: bool, orderTotal?: num, paidTotal?: num, orderedQuantity?: num, shippedQuantity?: num, shipments?: T2[], files?: T7[] }`
|
||||
- `T2` = `{ id: int, number: str, type: str, date: str, lines: T12[], shippings: T14[], entityId?: int|null, externalNumber?: str|null, createdAt?: str|null, lineCount?: int, packageCount?: int, files?: T7[], state?: str }`
|
||||
- `T3` = `{ id: int, number: str, type: str, date: str, lines: T12[], entityId?: int|null, externalNumber?: str|null, createdAt?: str, positions?: int, grossTotal?: num, totalQuantity?: num, customerName?: str|null, files?: T7[] }`
|
||||
- `T4` = `{ id: int, number: str, type: str, supplierId: int, date: str, lines: T15[], files: T7[], externalNumber?: str|null, createdAt?: str, ledger?: T27 }`
|
||||
- `T5` = `{ id: int, articleId: int, entityId: int, pu: num, sort: int, supplierName?: str|null, sku?: str|null, stock?: num|null, priceId?: int|null, price?: T28|null, incoming?: { date: str, amount: num }[] }`
|
||||
- `T6` = `{ id: int, name: str, width: num, height: num, dpi: int, type: str, content: { objects: T16[] }, thumb?: str|null }`
|
||||
- `T1` = `{ id: int, number: str, type: str, entityId: int, date: str, lines: T11[], externalNumber?: str|null, createdAt?: str, shipping?: T13|null, shippings?: T13[], payment?: T21|null, payments?: T21[], paid?: bool, shipped?: bool, delivered?: bool, orderTotal?: num, paidTotal?: num, orderedQuantity?: num, shippedQuantity?: num, shipments?: T2[], files?: T7[] }`
|
||||
- `T2` = `{ id: int, number: str, type: str, date: str, lines: T11[], shippings: T13[], entityId?: int|null, externalNumber?: str|null, createdAt?: str|null, lineCount?: int, packageCount?: int, files?: T7[], state?: str }`
|
||||
- `T3` = `{ id: int, number: str, type: str, date: str, lines: T11[], entityId?: int|null, externalNumber?: str|null, createdAt?: str, positions?: int, grossTotal?: num, totalQuantity?: num, customerName?: str|null, files?: T7[] }`
|
||||
- `T4` = `{ id: int, number: str, type: str, supplierId: int, date: str, lines: T14[], files: T7[], externalNumber?: str|null, createdAt?: str, ledger?: T26 }`
|
||||
- `T5` = `{ id: int, articleId: int, entityId: int, pu: num, sort: int, supplierName?: str|null, sku?: str|null, stock?: num|null, priceId?: int|null, price?: T27|null, incoming?: { date: str, amount: num }[] }`
|
||||
- `T6` = `{ id: int, name: str, width: num, height: num, dpi: int, type: str, content: { objects: T15[] }, thumb?: str|null }`
|
||||
- `T7` = `{ id: int, manifestId: int, fileId: int, sort: int, hash: str, mimetype: str, name: str, size: int, created?: str, modified?: str, skeledash?: str|null, thumbx?: int|null, thumby?: int|null, meta?: { [k]: str }|null }`
|
||||
- `T8` = `{ id: int, entityId: int, addressType: str, firstName?: str|null, name?: str|null, street?: str|null, streetNumber?: str|null, zip?: str|null, city?: str|null, county?: str|null }`
|
||||
- `T9` = `{ id: int, company_id: int, prompt: str, max_itr: int, cron: str, created_at: str, desc?: str|null, skills?: str|null, lastagentnote?: str|null, lastrun_at?: str|null }`
|
||||
- `T10` = `{ id: int, manifestarticle_id: int, transaction_type: str, amount: num, transaction_text: str, hash_version: int, prev_hash?: str, sku?: str|null, created_at?: str }`
|
||||
- `T11` = `{ id: int, name: str, sort: int, exclusive: bool, values: T20[], articleCount?: int }`
|
||||
- `T12` = `{ id: int, sku: str|null, name: str|null, pu: num, amount: num, net: num, rebate: num, taxrate: num, comment: str|null, shippable: bool }`
|
||||
- `T13` = `{ amount: num, net: num, taxrate: num, sku?: str|null, name?: str|null, pu?: num, rebate?: num, comment?: str|null, shippable?: bool }`
|
||||
- `T14` = `{ id: int, manifestId: int, number: str, carrierId: int, type: str, state: str, trackingCode?: str|null, carrier?: str|null }`
|
||||
- `T15` = `{ id: int, sku: str|null, name: str|null, pu: num, amount: num, net: num, rebate: num, taxrate: num, comment: str|null }`
|
||||
- `T16` = `{ id: str, type: str, x: num, y: num, w?: num, h?: num, text?: str, font?: str, fontSize?: num, barcodeFormat?: str }`
|
||||
- `T17` = `{ id: int, company_id: int, address: str, type: str, sort: int, model?: str|null, serial?: str|null, desc?: str|null }`
|
||||
- `T18` = `{ id: int, customergroupId: int, firstName: str|null, name: str, number: str|null, createdAt: str, updatedAt: str }`
|
||||
- `T19` = `{ si: str, basesi: str, basesifactor: num, symbol?: str|null, name?: str|null }`
|
||||
- `T20` = `{ id: int, attributeId: int, value: str, sort: int, articleCount?: int }`
|
||||
- `T21` = `{ id: int, name: str, sort: int, exclusive: bool, articleCount?: int }`
|
||||
- `T22` = `{ id: int, accountId: int, manifestId: int, type: str, amount: num }`
|
||||
- `T23` = `{ id: int, name: str, sort: int, hasPackages: bool, isReverse: bool }`
|
||||
- `T24` = `{ fullHash: str, thumbW: int, thumbH: int, thumbHash: str }`
|
||||
- `T25` = `{ id: int, entityId: int, contactType: str, contact: str }`
|
||||
- `T26` = `{ id: int, name: str, createdAt: str, updatedAt: str }`
|
||||
- `T27` = `{ totalPositions: int, completelyOnLedgerPositions: int }`
|
||||
- `T28` = `{ net: num, taxId: int, taxRate?: num|null }`
|
||||
- `T9` = `{ id: int, manifestarticle_id: int, transaction_type: str, amount: num, transaction_text: str, hash_version: int, prev_hash?: str, sku?: str|null, created_at?: str }`
|
||||
- `T10` = `{ id: int, name: str, sort: int, exclusive: bool, values: T18[], articleCount?: int }`
|
||||
- `T11` = `{ id: int, sku: str|null, name: str|null, pu: num, amount: num, net: num, rebate: num, taxrate: num, comment: str|null, shippable: bool }`
|
||||
- `T12` = `{ amount: num, net: num, taxrate: num, sku?: str|null, name?: str|null, pu?: num, rebate?: num, comment?: str|null, shippable?: bool }`
|
||||
- `T13` = `{ id: int, manifestId: int, number: str, carrierId: int, type: str, state: str, trackingCode?: str|null, carrier?: str|null }`
|
||||
- `T14` = `{ id: int, sku: str|null, name: str|null, pu: num, amount: num, net: num, rebate: num, taxrate: num, comment: str|null }`
|
||||
- `T15` = `{ id: str, type: str, x: num, y: num, w?: num, h?: num, text?: str, font?: str, fontSize?: num, barcodeFormat?: str }`
|
||||
- `T16` = `{ id: int, customergroupId: int, firstName: str|null, name: str, number: str|null, createdAt: str, updatedAt: str }`
|
||||
- `T17` = `{ si: str, basesi: str, basesifactor: num, symbol?: str|null, name?: str|null }`
|
||||
- `T18` = `{ id: int, attributeId: int, value: str, sort: int, articleCount?: int }`
|
||||
- `T19` = `{ id: int, googleAuthId: int, email: str, role: str, picture?: str|null }`
|
||||
- `T20` = `{ id: int, name: str, sort: int, exclusive: bool, articleCount?: int }`
|
||||
- `T21` = `{ id: int, accountId: int, manifestId: int, type: str, amount: num }`
|
||||
- `T22` = `{ id: int, name: str, sort: int, hasPackages: bool, isReverse: bool }`
|
||||
- `T23` = `{ fullHash: str, thumbW: int, thumbH: int, thumbHash: str }`
|
||||
- `T24` = `{ id: int, entityId: int, contactType: str, contact: str }`
|
||||
- `T25` = `{ id: int, name: str, createdAt: str, updatedAt: str }`
|
||||
- `T26` = `{ totalPositions: int, completelyOnLedgerPositions: int }`
|
||||
- `T27` = `{ net: num, taxId: int, taxRate?: num|null }`
|
||||
|
||||
### Routes
|
||||
|
||||
@@ -54,7 +53,7 @@ Params: path values first, then `query:` and `body:` (`body?` = optional body).
|
||||
- Returns: `204 void`
|
||||
#### Get article by SKU — `GET /article/{sku}`
|
||||
- Params: `sku: str`
|
||||
- Returns: `200 { article: { id: int, sku: str, name: str, slug: str, desc: str|null, seo: str|null, track_stock: bool, unitamount: num|null, weight: num|null, unit: T19, brand: { name: str, id?: int|null, fullHash?: str|null, thumbW?: int|null, thumbH?: int|null, thumbHash?: str|null }, categoryIds: int[], photos: { sort: int, fullHash: str, fullW: int, fullH: int, fullSize: int, thumbW: int, thumbH: int, thumbHash: str }[], eans: str[], prices: { minmultiplier: num, net: num, taxRate: num, customergroupId: int }[], suppliers: T5[], undeliveredOrders: { orderId: int, orderNumber: str, date: str, amount: num, customerName?: str|null }[] } }`
|
||||
- Returns: `200 { article: { id: int, sku: str, name: str, slug: str, desc: str|null, seo: str|null, track_stock: bool, unitamount: num|null, weight: num|null, unit: T17, brand: { name: str, id?: int|null, fullHash?: str|null, thumbW?: int|null, thumbH?: int|null, thumbHash?: str|null }, categoryIds: int[], photos: { sort: int, fullHash: str, fullW: int, fullH: int, fullSize: int, thumbW: int, thumbH: int, thumbHash: str }[], eans: str[], prices: { minmultiplier: num, net: num, taxRate: num, customergroupId: int }[], suppliers: T5[], undeliveredOrders: { orderId: int, orderNumber: str, date: str, amount: num, customerName?: str|null }[] } }`
|
||||
#### Update article by SKU — `PATCH /article/{sku}`
|
||||
- Params: `sku: str, body: { name?: str, desc?: str, seo?: str, unitamount?: num, unitSi?: str, track_stock?: bool }`
|
||||
- Returns: `204 void`
|
||||
@@ -92,8 +91,8 @@ Params: path values first, then `query:` and `body:` (`body?` = optional body).
|
||||
- Params: `sku: str, body: { eans: str[] }`
|
||||
- Returns: `204 void`
|
||||
#### Get article history by SKU — `GET /article/{sku}/history`
|
||||
- Params: `sku: str, query: limit?: int`
|
||||
- Returns: `200 { history: { id: int, date: str, text: str }[], truncated: bool }`
|
||||
- Params: `sku: str, query: offset?: int, limit?: int, search?: str, seekMonths?: int`
|
||||
- Returns: `200 { history: { id: int, date: str, text: str }[], total: int, unfilteredTotal: int, offset: int, limit: int }`
|
||||
#### Delete article image — `DELETE /article/{sku}/image/{fullHash}`
|
||||
- Params: `sku: str, fullHash: str`
|
||||
- Returns: `204 void`
|
||||
@@ -109,11 +108,11 @@ Params: path values first, then `query:` and `body:` (`body?` = optional body).
|
||||
#### Toggle parent mode for an article — `POST /article/{sku}/parent`
|
||||
- Params: `sku: str, body: { isParent: bool, attributeNameId?: int }`
|
||||
- Returns: `204 void`
|
||||
#### Replace POS prices by SKU (net > gross; price=net, tax=taxRate %) — `PUT /article/{sku}/prices`
|
||||
- Params: `sku: str, body: { prices: { net?: num, gross?: num, price?: num, taxRate?: num, tax?: num, minmultiplier?: num }[] }`
|
||||
#### Replace POS prices by SKU (net > gross) — `PUT /article/{sku}/prices`
|
||||
- Params: `sku: str, body: { prices: { net?: num, gross?: num, taxRate?: num, minmultiplier?: num }[] }`
|
||||
- Returns: `204 void`
|
||||
#### Print article label — `POST /article/{sku}/print`
|
||||
- Params: `sku: str, body: { templateId: int, printerId: int, quantity: int }`
|
||||
- Params: `sku: str, body: { templateId: int, agentprinterId: int, quantity: int }`
|
||||
- Returns: `200 { success: bool }`
|
||||
#### List article properties — `GET /article/{sku}/property`
|
||||
- Params: `sku: str`
|
||||
@@ -150,19 +149,19 @@ Params: path values first, then `query:` and `body:` (`body?` = optional body).
|
||||
|
||||
#### List attribute names — `GET /attributename`
|
||||
_none_
|
||||
- Returns: `200 { attributenames: T11[] }`
|
||||
- Returns: `200 { attributenames: T10[] }`
|
||||
#### Create attribute name — `POST /attributename`
|
||||
- Params: `body: { name: str, sort?: int, exclusive?: bool }`
|
||||
- Returns: `201 { attributename: T11 }`
|
||||
- Returns: `201 { attributename: T10 }`
|
||||
#### Reorder attribute names — `PUT /attributename/order`
|
||||
- Params: `body: { attributenameIds: int[] }`
|
||||
- Returns: `200 { ok: bool }`
|
||||
#### List values for an attribute — `GET /attributename/{attributeId}/value`
|
||||
- Params: `attributeId: int`
|
||||
- Returns: `200 { values: T20[] }`
|
||||
- Returns: `200 { values: T18[] }`
|
||||
#### Create value for an attribute — `POST /attributename/{attributeId}/value`
|
||||
- Params: `attributeId: int, body: { value: str, sort?: int }`
|
||||
- Returns: `201 { attributevalue: T20 }`
|
||||
- Returns: `201 { attributevalue: T18 }`
|
||||
#### Reorder values of an attribute — `PUT /attributename/{attributeId}/value/order`
|
||||
- Params: `attributeId: int, body: { attributevalueIds: int[] }`
|
||||
- Returns: `200 { ok: bool }`
|
||||
@@ -171,7 +170,7 @@ _none_
|
||||
- Returns: `200 { ok: bool }`
|
||||
#### Update attribute name — `PATCH /attributename/{id}`
|
||||
- Params: `id: int, body: { name?: str, sort?: int, exclusive?: bool }`
|
||||
- Returns: `200 { attributename: T11 }`
|
||||
- Returns: `200 { attributename: T10 }`
|
||||
|
||||
### Section: /attributevalue
|
||||
|
||||
@@ -180,10 +179,22 @@ _none_
|
||||
- Returns: `200 { ok: bool }`
|
||||
#### Update attribute value — `PATCH /attributevalue/{id}`
|
||||
- Params: `id: int, body: { value?: str, sort?: int }`
|
||||
- Returns: `200 { attributevalue: T20 }`
|
||||
- Returns: `200 { attributevalue: T18 }`
|
||||
#### Delete attribute value image — `DELETE /attributevalue/{id}/image`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { attributevalue: { id: int, thumbW: int|null, thumbH: int|null, thumbHash: str|null, pics: T24[] } }`
|
||||
- Returns: `200 { attributevalue: { id: int, thumbW: int|null, thumbH: int|null, thumbHash: str|null, pics: T23[] } }`
|
||||
|
||||
### Section: /autoinvite
|
||||
|
||||
#### List auto-invitations — `GET /autoinvite`
|
||||
_none_
|
||||
- Returns: `200 { autoinvites: { id: int, email: str, role: str, createdAt: str }[] }`
|
||||
#### Create auto-invitation — `POST /autoinvite`
|
||||
- Params: `body: { email: str, role?: str }`
|
||||
- Returns: `201 { autoinvite: { id: int, email: str, role: str } }`
|
||||
#### Delete auto-invitation — `DELETE /autoinvite/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
|
||||
### Section: /brand
|
||||
|
||||
@@ -192,7 +203,7 @@ _none_
|
||||
- Returns: `200 { brands: { id: int, name: str, articleCount: int, pics: { fullHash: str, thumbW: int, thumbH: int, thumbHash: str, smallThumbW?: int|null, smallThumbH?: int|null, smallThumbBinary?: str|null }[], gsprpinfo?: str|null }[], total: int, offset: int, limit: int }`
|
||||
#### Create brand — `POST /brand`
|
||||
- Params: `body: { name: str, gsprpinfo?: str }`
|
||||
- Returns: `201 { brand: { id: int, name: str, pics: T24[], gsprpinfo?: str|null } }`
|
||||
- Returns: `201 { brand: { id: int, name: str, pics: T23[], gsprpinfo?: str|null } }`
|
||||
#### Delete brand — `DELETE /brand/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
@@ -201,16 +212,16 @@ _none_
|
||||
- Returns: `200 { brand: { id: int, name: str, touchedArticleCount: int, gsprpinfo?: str|null } }`
|
||||
#### Delete brand image — `DELETE /brand/{id}/image`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { brand: { id: int, thumbW: int|null, thumbH: int|null, thumbHash: str|null, pics: T24[] } }`
|
||||
- Returns: `200 { brand: { id: int, thumbW: int|null, thumbH: int|null, thumbHash: str|null, pics: T23[] } }`
|
||||
|
||||
### Section: /carrier
|
||||
|
||||
#### List carriers — `GET /carrier`
|
||||
_none_
|
||||
- Returns: `200 { carriers: T23[] }`
|
||||
- Returns: `200 { carriers: T22[] }`
|
||||
#### Create carrier — `POST /carrier`
|
||||
- Params: `body: { name: str, sort?: int, hasPackages?: bool, isReverse?: bool }`
|
||||
- Returns: `201 { carrier: T23 }`
|
||||
- Returns: `201 { carrier: T22 }`
|
||||
#### Reorder carriers — `PUT /carrier/order`
|
||||
- Params: `body: { carrierIds: int[] }`
|
||||
- Returns: `200 { carrierIds: int[] }`
|
||||
@@ -219,10 +230,10 @@ _none_
|
||||
- Returns: `204 void`
|
||||
#### Get carrier by ID — `GET /carrier/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { carrier: T23 }`
|
||||
- Returns: `200 { carrier: T22 }`
|
||||
#### Update carrier — `PATCH /carrier/{id}`
|
||||
- Params: `id: int, body: { name?: str, sort?: int, hasPackages?: bool, isReverse?: bool }`
|
||||
- Returns: `200 { carrier: T23 }`
|
||||
- Returns: `200 { carrier: T22 }`
|
||||
|
||||
### Section: /category
|
||||
|
||||
@@ -242,7 +253,7 @@ _none_
|
||||
- Params: `id: int, body: { name?: str, parentId?: int }`
|
||||
- Returns: `200 { category: { id: int, name: str, slug: str, parentId: int, sort: int } }`
|
||||
#### Articles in category — `GET /category/{id}/articles`
|
||||
- Params: `id: int`
|
||||
- Params: `id: int, query: includeChildren?: bool`
|
||||
- Returns: `200 { articles: { id: int, sku: str, name: str, slug: str, track_stock: bool, optionsCount: int, articleListCount: int, childCount: int, net?: num|null, taxRate?: num|null, parentArticleId?: int|null, parentSku?: str|null, fullHash?: str|null, thumbW?: int|null, thumbH?: int|null, thumbHash?: str|null, smallThumbW?: int|null, smallThumbH?: int|null, smallThumbBinary?: str|null, brand?: { name: str, id?: int|null, fullHash?: str|null, thumbW?: int|null, thumbH?: int|null, thumbHash?: str|null }, articlewarehousesummary?: { id: int, articleId: int, warehouseId: int, stock: num, article_id?: int, warehouse_id?: int, warehouseName?: str|null }[], warehouses?: { id: int, name: str, stock: num }[] }[] }`
|
||||
#### List category attribute values — `GET /category/{id}/attributevalue`
|
||||
- Params: `id: int`
|
||||
@@ -253,6 +264,9 @@ _none_
|
||||
#### Delete category image — `DELETE /category/{id}/image`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { category: { id: int, thumbW: int|null, thumbH: int|null, thumbHash: str|null } }`
|
||||
#### Generate category mosaic image from contents — `POST /category/{id}/image/generate`
|
||||
- Params: `id: int, body?: { size?: int }`
|
||||
- Returns: `200 { category: { id: int, fullHash: str, thumbW: int, thumbH: int, thumbHash: str, size: int, grid: str, articleCount: int } }`
|
||||
#### List category properties — `GET /category/{id}/property`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { properties: { id: int, propertyId: int, name: str, exclusive: bool, value: str, sort: int, categoryId?: int }[] }`
|
||||
@@ -267,7 +281,7 @@ _none_
|
||||
|
||||
#### List companies — `GET /company`
|
||||
_none_
|
||||
- Returns: `200 { companies: { id: int, name: str, rootCategoryId: int|null, languageId: int|null, iso639: str|null, taxrate: num, reducedtaxrate: num, taxfreerate: num }[] }`
|
||||
- Returns: `200 { companies: { id: int, name: str, rootCategoryId: int|null, languageId: int|null, iso639: str|null, taxrate: num, reducedtaxrate: num, taxfreerate: num, role: str }[] }`
|
||||
#### Get company history — `GET /company/history`
|
||||
- Params: `query: limit?: int`
|
||||
- Returns: `200 { history: { id: int, date: str, text: str, companyuserId?: int|null }[], truncated: bool }`
|
||||
@@ -288,7 +302,22 @@ _none_
|
||||
- Returns: `200 { setting: { key: str, value: str|null } }`
|
||||
#### Update company — `PUT /company/{id}`
|
||||
- Params: `id: int, body: { iso639: str, name: str, taxrate: num, reducedtaxrate: num }`
|
||||
- Returns: `200 { company: { id: int, name: str, rootCategoryId: int|null, languageId: int|null, iso639: str|null, taxrate: num, reducedtaxrate: num, taxfreerate: num } }`
|
||||
- Returns: `200 { company: { id: int, name: str, rootCategoryId: int|null, languageId: int|null, iso639: str|null, taxrate: num, reducedtaxrate: num, taxfreerate: num, role: str } }`
|
||||
|
||||
### Section: /companyuser
|
||||
|
||||
#### List company users — `GET /companyuser`
|
||||
_none_
|
||||
- Returns: `200 { companyusers: T19[] }`
|
||||
#### Add an existing user to the company — `POST /companyuser`
|
||||
- Params: `body: { email: str, role?: str }`
|
||||
- Returns: `201 { companyuser: T19 }`
|
||||
#### Remove a user from the company — `DELETE /companyuser/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
#### Change a company user's role — `PATCH /companyuser/{id}`
|
||||
- Params: `id: int, body: { role: str }`
|
||||
- Returns: `200 { companyuser: T19 }`
|
||||
|
||||
### Section: /customergroup
|
||||
|
||||
@@ -312,7 +341,7 @@ _none_
|
||||
|
||||
#### List deliveries — `GET /delivery`
|
||||
- Params: `query: offset?: int, limit?: int, search?: str, onlyUnbooked?: bool, supplierId?: int, seekMonths?: int`
|
||||
- Returns: `200 { deliveries: { id: int, number: str, type: str, supplierId: int, date: str, externalNumber?: str|null, createdAt?: str, ledger?: T27 }[], total: int, unfilteredTotal: int, offset: int, limit: int }`
|
||||
- Returns: `200 { deliveries: { id: int, number: str, type: str, supplierId: int, date: str, externalNumber?: str|null, createdAt?: str, ledger?: T26 }[], total: int, unfilteredTotal: int, offset: int, limit: int }`
|
||||
#### Create delivery — `POST /delivery`
|
||||
- Params: `body: { externalNumber: str, date: str, supplierId: int, lines: { amount: num, net: num, taxrate: num, sku?: str|null, name?: str|null, pu?: num, rebate?: num, comment?: str|null }[], files?: { mimetype: str, name: str, content: str, sort?: int, size?: int, hash?: str, created?: str, modified?: str, meta?: { [k]: str } }[] }`
|
||||
- Returns: `201 { delivery: T4 }`
|
||||
@@ -336,10 +365,10 @@ _none_
|
||||
|
||||
#### List entities — `GET /entity`
|
||||
- Params: `query: customergroupId?: int, role?: str`
|
||||
- Returns: `200 { entities: T18[] }`
|
||||
- Returns: `200 { entities: T16[] }`
|
||||
#### Create entity — `POST /entity`
|
||||
- Params: `body: { customergroupId: int, name: str, firstName?: str|null, number?: str }`
|
||||
- Returns: `201 { entity: T18 }`
|
||||
- Returns: `201 { entity: T16 }`
|
||||
#### Peek next customer number — `GET /entity/next-number`
|
||||
_none_
|
||||
- Returns: `200 { number: str }`
|
||||
@@ -357,31 +386,25 @@ _none_
|
||||
- Returns: `200 { address: T8 }`
|
||||
#### List entity contacts — `GET /entity/{entityId}/contact`
|
||||
- Params: `entityId: int`
|
||||
- Returns: `200 { contacts: T25[] }`
|
||||
- Returns: `200 { contacts: T24[] }`
|
||||
#### Create entity contact — `POST /entity/{entityId}/contact`
|
||||
- Params: `entityId: int, body: { contactType: str, contact: str }`
|
||||
- Returns: `201 { contact: T25 }`
|
||||
- Returns: `201 { contact: T24 }`
|
||||
#### Delete entity contact — `DELETE /entity/{entityId}/contact/{id}`
|
||||
- Params: `entityId: int, id: int`
|
||||
- Returns: `204 void`
|
||||
#### Update entity contact — `PATCH /entity/{entityId}/contact/{id}`
|
||||
- Params: `entityId: int, id: int, body: { contactType?: str, contact?: str }`
|
||||
- Returns: `200 { contact: T25 }`
|
||||
- Returns: `200 { contact: T24 }`
|
||||
#### Delete entity — `DELETE /entity/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
#### Get entity — `GET /entity/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { entity: T18 }`
|
||||
- Returns: `200 { entity: T16 }`
|
||||
#### Update entity — `PATCH /entity/{id}`
|
||||
- Params: `id: int, body: { name?: str, firstName?: str|null, number?: str|null }`
|
||||
- Returns: `200 { entity: T18 }`
|
||||
|
||||
### Section: /health
|
||||
|
||||
#### Health latency history — `GET /health/latency`
|
||||
- Params: `query: range?: str`
|
||||
- Returns: `200 { raw: { timestamp: int, value: num }[], avg: { timestamp: int, value: num }[], max: { timestamp: int, value: num }[] }`
|
||||
- Returns: `200 { entity: T16 }`
|
||||
|
||||
### Section: /labeltemplate
|
||||
|
||||
@@ -389,8 +412,11 @@ _none_
|
||||
_none_
|
||||
- Returns: `200 { labeltemplates: { id: int, name: str, width: num, height: num, dpi: int, type: str, thumb?: str|null }[] }`
|
||||
#### Create label template — `POST /labeltemplate`
|
||||
- Params: `body: { name: str, width: num, height: num, dpi: int, type: str, content: { objects: T16[] } }`
|
||||
- Params: `body: { name: str, width: num, height: num, dpi: int, type: str, content: { objects: T15[] } }`
|
||||
- Returns: `201 { labeltemplate: T6 }`
|
||||
#### Test print label template — `POST /labeltemplate/testprint`
|
||||
- Params: `body: { agentprinterId: int, templateId?: int, objects?: any[], width?: int, height?: int, dpi?: int, sku?: str, quantity?: int }`
|
||||
- Returns: `200 { success: bool }`
|
||||
#### Delete label template — `DELETE /labeltemplate/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
@@ -398,26 +424,26 @@ _none_
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { labeltemplate: T6 }`
|
||||
#### Update label template (partial) — `PATCH /labeltemplate/{id}`
|
||||
- Params: `id: int, body: { name?: str, width?: num, height?: num, dpi?: int, type?: str, content?: { objects: T16[] } }`
|
||||
- Params: `id: int, body: { name?: str, width?: num, height?: num, dpi?: int, type?: str, content?: { objects: T15[] } }`
|
||||
- Returns: `200 { labeltemplate: T6 }`
|
||||
#### Update label template — `PUT /labeltemplate/{id}`
|
||||
- Params: `id: int, body: { name?: str, width?: num, height?: num, dpi?: int, type?: str, content?: { objects: T16[] } }`
|
||||
- Params: `id: int, body: { name?: str, width?: num, height?: num, dpi?: int, type?: str, content?: { objects: T15[] } }`
|
||||
- Returns: `200 { labeltemplate: T6 }`
|
||||
|
||||
### Section: /ledger
|
||||
|
||||
#### Query ledger by manifest article ID or SKU — `GET /ledger`
|
||||
- Params: `query: manifestarticle_id?: int, sku?: str, transaction_type?: str`
|
||||
- Returns: `200 { ledger: T10[] }`
|
||||
- Returns: `200 { ledger: T9[] }`
|
||||
#### Query company-wide ledger history — `GET /ledger/history`
|
||||
- Params: `query: offset?: int, limit?: int, search?: str, seekMonths?: int`
|
||||
- Returns: `200 { ledger: { id: int, date: str, transaction_type: str, transaction_text: str, sku?: str|null, name?: str|null, amount?: num }[], total: int, unfilteredTotal: int, offset: int, limit: int }`
|
||||
#### Query ledger by manifest article ID — `GET /ledger/manifestarticle/{manifestarticleId}`
|
||||
- Params: `manifestarticleId: int, query: transaction_type?: str`
|
||||
- Returns: `200 { ledger: T10[] }`
|
||||
- Returns: `200 { ledger: T9[] }`
|
||||
#### Query ledger by article SKU — `GET /ledger/sku/{sku}`
|
||||
- Params: `sku: str, query: transaction_type?: str`
|
||||
- Returns: `200 { ledger: T10[] }`
|
||||
- Returns: `200 { ledger: T9[] }`
|
||||
|
||||
### Section: /number
|
||||
|
||||
@@ -434,7 +460,7 @@ _none_
|
||||
- Params: `query: offset?: int, limit?: int, search?: str, onlyUnpaid?: bool, onlyUndelivered?: bool, seekMonths?: int`
|
||||
- Returns: `200 { orders: T1[], total: int, unfilteredTotal: int, offset: int, limit: int }`
|
||||
#### Create order — `POST /order`
|
||||
- Params: `body: { number: str, date: str, entityId: int, lines: T13[], externalNumber?: str|null }`
|
||||
- Params: `body: { number: str, date: str, entityId: int, lines: T12[], externalNumber?: str|null }`
|
||||
- Returns: `201 { order: T1 }`
|
||||
#### Delete order — `DELETE /order/{id}`
|
||||
- Params: `id: int`
|
||||
@@ -443,17 +469,17 @@ _none_
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { order: T1 }`
|
||||
#### Update order — `PATCH /order/{id}`
|
||||
- Params: `id: int, body: { number?: str, date?: str, entityId?: int|null, externalNumber?: str|null, lines?: T13[] }`
|
||||
- Params: `id: int, body: { number?: str, date?: str, entityId?: int|null, externalNumber?: str|null, lines?: T12[] }`
|
||||
- Returns: `200 { order: T1 }`
|
||||
#### Delete order file attachment — `DELETE /order/{id}/file/{fileId}`
|
||||
- Params: `id: int, fileId: int`
|
||||
- Returns: `204 void`
|
||||
#### List payments of an order — `GET /order/{id}/payment`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { payments: T22[] }`
|
||||
- Returns: `200 { payments: T21[] }`
|
||||
#### Add payment to an order — `POST /order/{id}/payment`
|
||||
- Params: `id: int, body: { accountId: int, type: str, amount: num }`
|
||||
- Returns: `201 { payment: T22 }`
|
||||
- Returns: `201 { payment: T21 }`
|
||||
#### Generate and attach order PDF — `POST /order/{id}/pdf`
|
||||
- Params: `id: int`
|
||||
- Returns: `201 { attachment: T7, fileUrl: str }`
|
||||
@@ -465,10 +491,10 @@ _none_
|
||||
- Returns: `201 { shipment: T2 }`
|
||||
#### List shippings of an order — `GET /order/{id}/shipping`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { shippings: T14[] }`
|
||||
- Returns: `200 { shippings: T13[] }`
|
||||
#### Create shipping for an order — `POST /order/{id}/shipping`
|
||||
- Params: `id: int, body: { carrierId: int, type: str, state: str, trackingCode?: str, warehouseId?: int }`
|
||||
- Returns: `201 { shipping: T14 }`
|
||||
- Returns: `201 { shipping: T13 }`
|
||||
|
||||
### Section: /package
|
||||
|
||||
@@ -482,38 +508,14 @@ _none_
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
|
||||
### Section: /printer
|
||||
|
||||
#### List printers — `GET /printer`
|
||||
_none_
|
||||
- Returns: `200 { printers: T17[] }`
|
||||
#### Create printer — `POST /printer`
|
||||
- Params: `body: { address: str, type: str, model?: str|null, serial?: str|null, sort?: int, desc?: str|null }`
|
||||
- Returns: `201 { printer: T17 }`
|
||||
#### Reorder printers — `PUT /printer/order`
|
||||
- Params: `body: { printerIds: int[] }`
|
||||
- Returns: `200 { printerIds: int[] }`
|
||||
#### Delete printer — `DELETE /printer/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
#### Get printer by ID — `GET /printer/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { printer: T17 }`
|
||||
#### Update printer (partial) — `PATCH /printer/{id}`
|
||||
- Params: `id: int, body: { address?: str, type?: str, model?: str|null, serial?: str|null, sort?: int, desc?: str|null }`
|
||||
- Returns: `200 { printer: T17 }`
|
||||
#### Update printer — `PUT /printer/{id}`
|
||||
- Params: `id: int, body: { address?: str, type?: str, model?: str|null, serial?: str|null, sort?: int, desc?: str|null }`
|
||||
- Returns: `200 { printer: T17 }`
|
||||
|
||||
### Section: /propertyname
|
||||
|
||||
#### List property names — `GET /propertyname`
|
||||
_none_
|
||||
- Returns: `200 { propertynames: T21[] }`
|
||||
- Returns: `200 { propertynames: T20[] }`
|
||||
#### Create property name — `POST /propertyname`
|
||||
- Params: `body: { name: str, sort?: int, exclusive?: bool }`
|
||||
- Returns: `201 { propertyname: T21 }`
|
||||
- Returns: `201 { propertyname: T20 }`
|
||||
#### Reorder property names — `PUT /propertyname/order`
|
||||
- Params: `body: { propertynameIds: int[] }`
|
||||
- Returns: `200 { ok: bool }`
|
||||
@@ -522,7 +524,7 @@ _none_
|
||||
- Returns: `200 { ok: bool }`
|
||||
#### Update property name — `PATCH /propertyname/{id}`
|
||||
- Params: `id: int, body: { name?: str, sort?: int, exclusive?: bool }`
|
||||
- Returns: `200 { propertyname: T21 }`
|
||||
- Returns: `200 { propertyname: T20 }`
|
||||
|
||||
### Section: /quote
|
||||
|
||||
@@ -530,7 +532,7 @@ _none_
|
||||
- Params: `query: offset?: int, limit?: int, search?: str, seekMonths?: int`
|
||||
- Returns: `200 { quotes: T3[], total: int, unfilteredTotal: int, offset: int, limit: int }`
|
||||
#### Create quote — `POST /quote`
|
||||
- Params: `body: { number: str, date: str, lines: T13[], entityId?: int|null, externalNumber?: str|null }`
|
||||
- Params: `body: { number: str, date: str, lines: T12[], entityId?: int|null, externalNumber?: str|null }`
|
||||
- Returns: `201 { quote: T3 }`
|
||||
#### Delete quote — `DELETE /quote/{id}`
|
||||
- Params: `id: int`
|
||||
@@ -539,18 +541,66 @@ _none_
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { quote: T3 }`
|
||||
#### Update quote — `PATCH /quote/{id}`
|
||||
- Params: `id: int, body: { number?: str, date?: str, entityId?: int|null, externalNumber?: str|null, lines?: T13[] }`
|
||||
- Params: `id: int, body: { number?: str, date?: str, entityId?: int|null, externalNumber?: str|null, lines?: T12[] }`
|
||||
- Returns: `200 { quote: T3 }`
|
||||
#### Delete quote file attachment — `DELETE /quote/{id}/file/{fileId}`
|
||||
- Params: `id: int, fileId: int`
|
||||
- Returns: `204 void`
|
||||
#### Create order from quote — `POST /quote/{id}/order`
|
||||
- Params: `id: int, body?: { number?: str, date?: str, createdAt?: str, entityId?: int|null, externalNumber?: str|null, lines?: T13[] }`
|
||||
- Params: `id: int, body?: { number?: str, date?: str, createdAt?: str, entityId?: int|null, externalNumber?: str|null, lines?: T12[] }`
|
||||
- Returns: `201 { order: T1 }`
|
||||
#### Generate and attach quote PDF — `POST /quote/{id}/pdf`
|
||||
- Params: `id: int`
|
||||
- Returns: `201 { attachment: T7, fileUrl: str }`
|
||||
|
||||
### Section: /retoure
|
||||
|
||||
#### List retoures — `GET /retoure`
|
||||
- Params: `query: offset?: int, limit?: int, search?: str, onlyUnpaid?: bool, onlyUndelivered?: bool, entityId?: int, seekMonths?: int`
|
||||
- Returns: `200`
|
||||
#### Create retoure — `POST /retoure`
|
||||
- Params: `body: { date: str, number?: str, entityId?: int, externalNumber?: str, lines?: any[] }`
|
||||
- Returns: `201`
|
||||
#### Rebuild retoure summaries — `POST /retoure/rebuild-summaries`
|
||||
_none_
|
||||
- Returns: `200`
|
||||
#### Delete retoure — `DELETE /retoure/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
#### Get retoure by ID — `GET /retoure/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `200`
|
||||
#### Update retoure — `PUT /retoure/{id}`
|
||||
- Params: `id: int, body: {}`
|
||||
- Returns: `200`
|
||||
#### Create shipment for retoure — `POST /retoure/{id}/shipment`
|
||||
- Params: `id: int`
|
||||
- Returns: `201`
|
||||
|
||||
### Section: /return
|
||||
|
||||
#### List returns — `GET /return`
|
||||
- Params: `query: offset?: int, limit?: int, search?: str, onlyUnbooked?: bool, supplierId?: int`
|
||||
- Returns: `200`
|
||||
#### Create return — `POST /return`
|
||||
- Params: `body: {}`
|
||||
- Returns: `201`
|
||||
#### Rebuild return summaries — `POST /return/rebuild-summaries`
|
||||
_none_
|
||||
- Returns: `200`
|
||||
#### Delete return — `DELETE /return/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
#### Get return by ID — `GET /return/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `200`
|
||||
#### Update return — `PUT /return/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `200`
|
||||
#### Book return to ledger — `POST /return/{id}/book`
|
||||
- Params: `id: int`
|
||||
- Returns: `200`
|
||||
|
||||
### Section: /shipment
|
||||
|
||||
#### List shipments — `GET /shipment`
|
||||
@@ -573,10 +623,10 @@ _none_
|
||||
- Returns: `201 { attachment: T7, fileUrl: str }`
|
||||
#### List packages of a shipment — `GET /shipment/{id}/shipping`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { shippings: T14[] }`
|
||||
- Returns: `200 { shippings: T13[] }`
|
||||
#### Create package for a shipment — `POST /shipment/{id}/shipping`
|
||||
- Params: `id: int, body: { carrierId: int, type: str, state: str, trackingCode?: str, warehouseId?: int }`
|
||||
- Returns: `201 { shipping: T14 }`
|
||||
- Returns: `201 { shipping: T13 }`
|
||||
|
||||
### Section: /shipping
|
||||
|
||||
@@ -585,7 +635,7 @@ _none_
|
||||
- Returns: `204 void`
|
||||
#### Update shipping — `PATCH /shipping/{id}`
|
||||
- Params: `id: int, body: { type?: str, state?: str, trackingCode?: str, carrierId?: int, warehouseId?: int }`
|
||||
- Returns: `200 { shipping: T14 }`
|
||||
- Returns: `200 { shipping: T13 }`
|
||||
#### List packages of a shipping — `GET /shipping/{id}/package`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { packages: { id: int, shippingId: int, entityaddressId: int, number: str, type: str, state: str, details?: str|null }[] }`
|
||||
@@ -593,12 +643,6 @@ _none_
|
||||
- Params: `id: int, body: { entityaddressId: int, type: str, state: str, details?: str }`
|
||||
- Returns: `201 { package: { id: int, shippingId: int, entityaddressId: int, number: str, type: str, state: str, details?: str|null } }`
|
||||
|
||||
### Section: /smallthumb
|
||||
|
||||
#### Small thumb image by hash — `GET /smallthumb/{fullHash}`
|
||||
- Params: `fullHash: str`
|
||||
- Returns: `200 avif`
|
||||
|
||||
### Section: /stock
|
||||
|
||||
#### Accept delivery manifest item(s) — `POST /stock/accept`
|
||||
@@ -606,49 +650,31 @@ _none_
|
||||
- Returns: `200`
|
||||
#### Adjust stock manually — `POST /stock/adjust`
|
||||
- Params: `body: { sku?: str, warehouseId?: int, amount?: num, text?: str|null, lines?: { sku: str, amount: num, warehouseId?: int, text?: str }[] }`
|
||||
- Returns: `201 { manifest: { id: int, number: str, type: str, date: str, createdAt: str }, lines: { manifestarticle_id: int, sku: str, name: str, warehouse_id: int, amount: num, text: str }[], ledger: T10[] }`
|
||||
- Returns: `201 { manifest: { id: int, number: str, type: str, date: str, createdAt: str }, lines: { manifestarticle_id: int, sku: str, name: str, warehouse_id: int, amount: num, text: str }[], ledger: T9[] }`
|
||||
#### Ship shipment manifest item(s) — `POST /stock/ship`
|
||||
- Params: `body: { manifestarticleId?: int, warehouseId?: int, items?: { manifestarticleId: int, warehouseId?: int }[] }`
|
||||
- Returns: `200`
|
||||
|
||||
### Section: /subagentschedule
|
||||
|
||||
#### List subagent schedules — `GET /subagentschedule`
|
||||
_none_
|
||||
- Returns: `200 { schedules: T9[] }`
|
||||
#### Create subagent schedule — `POST /subagentschedule`
|
||||
- Params: `body: { prompt: str, cron: str, desc?: str|null, skills?: str|null, lastagentnote?: str|null, max_itr?: int }`
|
||||
- Returns: `201 { schedule: T9 }`
|
||||
#### Delete subagent schedule — `DELETE /subagentschedule/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
#### Get subagent schedule by ID — `GET /subagentschedule/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { schedule: T9 }`
|
||||
#### Update subagent schedule — `PUT /subagentschedule/{id}`
|
||||
- Params: `id: int, body: { prompt?: str, cron?: str, desc?: str|null, skills?: str|null, lastagentnote?: str|null, max_itr?: int, lastrun_at?: str|null }`
|
||||
- Returns: `200 { schedule: T9 }`
|
||||
|
||||
### Section: /supplier
|
||||
|
||||
#### List suppliers — `GET /supplier`
|
||||
_none_
|
||||
- Returns: `200 { suppliers: T26[] }`
|
||||
- Returns: `200 { suppliers: T25[] }`
|
||||
#### Create supplier — `POST /supplier`
|
||||
- Params: `body: { name: str }`
|
||||
- Returns: `201 { supplier: T26 }`
|
||||
- Returns: `201 { supplier: T25 }`
|
||||
#### Delete supplier — `DELETE /supplier/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
#### Update supplier — `PATCH /supplier/{id}`
|
||||
- Params: `id: int, body: { name: str }`
|
||||
- Returns: `200 { supplier: T26 }`
|
||||
- Returns: `200 { supplier: T25 }`
|
||||
#### List supplier articles by SKUs — `GET /supplier/{id}/articles`
|
||||
- Params: `id: int, query: skus?: str`
|
||||
- Returns: `200 { articles: { id: int, articleId: int, entityId: int, pu: num, sort: int, article: { id: int, sku: str, name?: str|null, slug?: str|null, photos?: { sort: int, fullHash: str, thumbW: int, thumbH: int, thumbHash: str }[], eans?: str[] }, supplierName?: str|null, sku?: str|null, stock?: num|null, priceId?: int|null, price?: T28|null, incoming?: { date: str, amount: num }[] }[] }`
|
||||
- Returns: `200 { articles: { id: int, articleId: int, entityId: int, pu: num, sort: int, article: { id: int, sku: str, name?: str|null, slug?: str|null, photos?: { sort: int, fullHash: str, thumbW: int, thumbH: int, thumbHash: str }[], eans?: str[] }, supplierName?: str|null, sku?: str|null, stock?: num|null, priceId?: int|null, price?: T27|null, incoming?: { date: str, amount: num }[] }[] }`
|
||||
#### Query supplier articles by SKUs (bulk) — `POST /supplier/{id}/articles`
|
||||
- Params: `id: int, body?: { skus?: str[] }`
|
||||
- Returns: `200 { articles: { id: int, articleId: int, entityId: int, pu: num, sort: int, article: { id: int, sku: str, name?: str|null, slug?: str|null, photos?: { sort: int, fullHash: str, thumbW: int, thumbH: int, thumbHash: str }[], eans?: str[] }, supplierName?: str|null, sku?: str|null, stock?: num|null, priceId?: int|null, price?: T28|null, incoming?: { date: str, amount: num }[] }[] }`
|
||||
- Returns: `200 { articles: { id: int, articleId: int, entityId: int, pu: num, sort: int, article: { id: int, sku: str, name?: str|null, slug?: str|null, photos?: { sort: int, fullHash: str, thumbW: int, thumbH: int, thumbHash: str }[], eans?: str[] }, supplierName?: str|null, sku?: str|null, stock?: num|null, priceId?: int|null, price?: T27|null, incoming?: { date: str, amount: num }[] }[] }`
|
||||
|
||||
### Section: /unit
|
||||
|
||||
@@ -657,10 +683,10 @@ _none_
|
||||
- Returns: `204 void`
|
||||
#### List units — `GET /unit`
|
||||
_none_
|
||||
- Returns: `200 { units: T19[] }`
|
||||
- Returns: `200 { units: T17[] }`
|
||||
#### Upsert unit — `PUT /unit`
|
||||
- Params: `body: { si: str, basesi: str, basesifactor: num, symbol: str, name: str }`
|
||||
- Returns: `200 { unit: T19 }`
|
||||
- Returns: `200 { unit: T17 }`
|
||||
|
||||
### Section: /warehouse
|
||||
|
||||
|
||||
30
docs/api/routes/agent/events.md
Normal file
30
docs/api/routes/agent/events.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# `GET /agent/events`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Printer agent SSE stream
|
||||
|
||||
Authorized Server-Sent Events stream for connected printer agents.
|
||||
Maintains a persistent connection with regular heartbeats (`: heartbeat\n\n`) and updates `lastseen_at` and `agentversion`.
|
||||
|
||||
|
||||
## Query parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `token` | no | string | Agent auth token if not provided via Authorization header |
|
||||
| `agentversion` | no | string | Current agent version |
|
||||
|
||||
## Response `200`
|
||||
|
||||
Event stream established
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 401 | Unauthorized |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
31
docs/api/routes/agent/pair.get.md
Normal file
31
docs/api/routes/agent/pair.get.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# `GET /agent/pair`
|
||||
|
||||
Public. No cookie required.
|
||||
|
||||
Pair printer agent via query parameters
|
||||
|
||||
Alternative GET endpoint for devices that pair via query parameters.
|
||||
|
||||
## Query parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `authCode` | no | string | Pairing PIN (or pairingpin) |
|
||||
| `pairingpin` | no | string | |
|
||||
| `serial` | no | string | |
|
||||
| `model` | no | string | |
|
||||
| `version` | no | string | |
|
||||
|
||||
## Response `200`
|
||||
|
||||
Pairing successful
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Missing or invalid pairing PIN |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
55
docs/api/routes/agent/pair.post.md
Normal file
55
docs/api/routes/agent/pair.post.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# `POST /agent/pair`
|
||||
|
||||
Public. No cookie required.
|
||||
|
||||
Pair printer agent
|
||||
|
||||
Public, unauthorized endpoint used by the printer agent to complete pairing using a 6-digit PIN.
|
||||
Updates `clientserial`, `clientmodel`, and `agentversion`, clears the pairing PIN, and returns a device authentication token.
|
||||
|
||||
|
||||
## Body (JSON)
|
||||
|
||||
| Field | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `pairingpin` | yes | string | |
|
||||
| `clientserial` | no | string | |
|
||||
| `clientmodel` | no | string | |
|
||||
| `agentversion` | no | string | |
|
||||
|
||||
```json
|
||||
{
|
||||
"pairingpin": "123456",
|
||||
"clientserial": "SN-987654321",
|
||||
"clientmodel": "Epson TM-T88VI",
|
||||
"agentversion": "1.0.0"
|
||||
}
|
||||
```
|
||||
|
||||
## Response `200`
|
||||
|
||||
Pairing successful
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"name": "…",
|
||||
"companyId": 1,
|
||||
"token": "…",
|
||||
"pairedAt": "…",
|
||||
"clientserial": "…",
|
||||
"clientmodel": "…",
|
||||
"agentversion": "…",
|
||||
"sort": 1
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Missing or invalid pairing PIN — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
53
docs/api/routes/agent/state.md
Normal file
53
docs/api/routes/agent/state.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# `POST /agent/state`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Post agent state
|
||||
|
||||
Authorized endpoint for the printer agent to report its operational status/telemetry.
|
||||
|
||||
|
||||
## Body (JSON)
|
||||
|
||||
| Field | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `state` | no | | Status text or status object |
|
||||
|
||||
```json
|
||||
{
|
||||
"state": "…"
|
||||
}
|
||||
```
|
||||
|
||||
## Response `200`
|
||||
|
||||
State recorded
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"agent": {
|
||||
"id": 1,
|
||||
"companyId": 1,
|
||||
"name": "…",
|
||||
"token": "…",
|
||||
"pairingpin": "…",
|
||||
"pairedAt": "…",
|
||||
"agentversion": "…",
|
||||
"lastseenAt": "…",
|
||||
"updatedAt": "…",
|
||||
"sort": 1,
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 401 | Unauthorized |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
51
docs/api/routes/agentprinter.md
Normal file
51
docs/api/routes/agentprinter.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# `GET /agentprinter`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
List agent printers
|
||||
|
||||
Lists agent printers for the authenticated user's selected company,
|
||||
optionally filtered by printer agent ID.
|
||||
|
||||
|
||||
## Query parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `printeragentId` | no | integer | Optional printer agent ID filter |
|
||||
|
||||
## Response `200`
|
||||
|
||||
List of agent printers
|
||||
|
||||
```json
|
||||
{
|
||||
"agentprinters": [
|
||||
{
|
||||
"id": 1,
|
||||
"printeragentId": 1,
|
||||
"type": "…",
|
||||
"model": "…",
|
||||
"serial": "…",
|
||||
"enabled": true,
|
||||
"sort": 1,
|
||||
"open": true,
|
||||
"pause": true,
|
||||
"error": true,
|
||||
"online": true,
|
||||
"labelLength": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | No company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
35
docs/api/routes/agentprinter/_id.delete.md
Normal file
35
docs/api/routes/agentprinter/_id.delete.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# `DELETE /agentprinter/{id}`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Delete agent printer
|
||||
|
||||
Deletes an agent printer from the selected company.
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | |
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `agentprinter` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `204`
|
||||
|
||||
Agent printer deleted
|
||||
|
||||
_No content_
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Invalid ID or no company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 404 | Agent printer not found — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
48
docs/api/routes/agentprinter/_id.get.md
Normal file
48
docs/api/routes/agentprinter/_id.get.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# `GET /agentprinter/{id}`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Get agent printer
|
||||
|
||||
Retrieves a single agent printer by ID.
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | |
|
||||
|
||||
## Response `200`
|
||||
|
||||
Agent printer details
|
||||
|
||||
```json
|
||||
{
|
||||
"agentprinter": {
|
||||
"id": 1,
|
||||
"printeragentId": 1,
|
||||
"type": "…",
|
||||
"model": "…",
|
||||
"serial": "…",
|
||||
"enabled": true,
|
||||
"sort": 1,
|
||||
"open": true,
|
||||
"pause": true,
|
||||
"error": true,
|
||||
"online": true,
|
||||
"labelLength": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Invalid ID or no company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 404 | Agent printer not found — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
67
docs/api/routes/agentprinter/_id.patch.md
Normal file
67
docs/api/routes/agentprinter/_id.patch.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# `PATCH /agentprinter/{id}`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Update agent printer
|
||||
|
||||
Updates enabled and/or display order (sort) of an agent printer.
|
||||
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | |
|
||||
|
||||
## Body (JSON)
|
||||
|
||||
| Field | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `enabled` | no | boolean | |
|
||||
| `sort` | no | integer | |
|
||||
|
||||
```json
|
||||
{
|
||||
"enabled": true,
|
||||
"sort": 1
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `agentprinter` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
|
||||
Updated agent printer
|
||||
|
||||
```json
|
||||
{
|
||||
"agentprinter": {
|
||||
"id": 1,
|
||||
"printeragentId": 1,
|
||||
"type": "…",
|
||||
"model": "…",
|
||||
"serial": "…",
|
||||
"enabled": true,
|
||||
"sort": 1,
|
||||
"open": true,
|
||||
"pause": true,
|
||||
"error": true,
|
||||
"online": true,
|
||||
"labelLength": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Invalid input or no company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 404 | Agent printer not found — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
51
docs/api/routes/agentprinter/order.md
Normal file
51
docs/api/routes/agentprinter/order.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# `PUT /agentprinter/order`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Reorder agent printers
|
||||
|
||||
Reorders agent printers for a specific printer agent within the selected company.
|
||||
|
||||
|
||||
## Body (JSON)
|
||||
|
||||
| Field | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `printeragentId` | no | integer | Optional agent id. If omitted, reorders all printers in the company. |
|
||||
| `agentprinterIds` | yes | integer[] | |
|
||||
|
||||
```json
|
||||
{
|
||||
"printeragentId": 1,
|
||||
"agentprinterIds": [
|
||||
1
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `agentprinter` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
|
||||
Applied order
|
||||
|
||||
```json
|
||||
{
|
||||
"agentprinterIds": [
|
||||
1
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Invalid order or no company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
@@ -17,13 +17,13 @@ Prints a label for the article using a label template.
|
||||
| Field | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `templateId` | yes | integer | |
|
||||
| `printerId` | yes | integer | |
|
||||
| `agentprinterId` | yes | integer | |
|
||||
| `quantity` | yes | integer | |
|
||||
|
||||
```json
|
||||
{
|
||||
"templateId": 1,
|
||||
"printerId": 1,
|
||||
"agentprinterId": 1,
|
||||
"quantity": 1
|
||||
}
|
||||
```
|
||||
|
||||
@@ -5,6 +5,7 @@ Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
Get article history by SKU
|
||||
|
||||
Returns `articlehistory` rows for the article, newest first (`date` DESC, `id` DESC).
|
||||
Supports pagination, search filter, and date cutoff via `seekMonths`.
|
||||
Auth like GET by SKU.
|
||||
|
||||
|
||||
@@ -18,11 +19,14 @@ Auth like GET by SKU.
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `limit` | no | integer | Maximum number of entries to return (newest first). Omit for all entries. |
|
||||
| `offset` | no | integer | Paging offset |
|
||||
| `limit` | no | integer | Page size |
|
||||
| `search` | no | string | Optional search filter for history text |
|
||||
| `seekMonths` | no | integer | Negative integer cutoff months ago (e.g. -13) |
|
||||
|
||||
## Response `200`
|
||||
|
||||
Article history (newest first)
|
||||
Paged article history list
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -37,7 +41,11 @@ Article history (newest first)
|
||||
"date": "2026-08-01T09:00:00.000Z",
|
||||
"text": "Name geändert von \"\" auf \"Tee\""
|
||||
}
|
||||
]
|
||||
],
|
||||
"total": 2,
|
||||
"unfilteredTotal": 2,
|
||||
"offset": 0,
|
||||
"limit": 50
|
||||
}
|
||||
```
|
||||
|
||||
@@ -45,7 +53,7 @@ Article history (newest first)
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Missing sku — `{"error":"…"}` |
|
||||
| 400 | Missing sku or invalid query parameters — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized — `{"error":"…"}` |
|
||||
| 404 | Article not found — `{"error":"…"}` |
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Replace POS prices by SKU (net > gross; price=net, tax=taxRate %)
|
||||
Replace POS prices by SKU (net > gross)
|
||||
|
||||
Replace-all prices for the company POS customer group.
|
||||
`net` takes precedence over `price` (legacy alias for net) and `gross`.
|
||||
`tax` and `taxRate` both specify the tax rate percentage (e.g. 19 for 19%), not monetary tax.
|
||||
`net` takes precedence over `gross`.
|
||||
`taxRate` specifies the tax rate percentage (e.g. 19 for 19%), not monetary tax.
|
||||
When `gross` is provided, net price is computed as `gross / (1 + taxRate / 100)`.
|
||||
Prices are strictly scoped to the company's designated POS customer group (customergroupId returned on GET).
|
||||
Empty `prices` clears all POS prices. Returns the same shape as GET by SKU.
|
||||
@@ -23,11 +23,9 @@ Empty `prices` clears all POS prices. Returns the same shape as GET by SKU.
|
||||
| Field | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `prices` | yes | object[] | |
|
||||
| `prices[].net` | no | number | Net price (excl. VAT). Either `net`, `gross`, or legacy `price` is required. |
|
||||
| `prices[].net` | no | number | Net price (excl. VAT). Either `net` or `gross` is required. |
|
||||
| `prices[].gross` | no | number | Gross price (incl. VAT). Net is computed as `gross / (1 + taxRate / 100)`. |
|
||||
| `prices[].price` | no | number | Legacy alias for `net`. |
|
||||
| `prices[].taxRate` | no | number | Tax rate percentage (e.g. 19 for 19%, 7 for 7%, 0 for 0%). |
|
||||
| `prices[].tax` | no | number | Alias for `taxRate` percentage. |
|
||||
| `prices[].minmultiplier` | no | number | Defaults to 1; must be unique per request. |
|
||||
|
||||
```json
|
||||
|
||||
@@ -4,7 +4,8 @@ Public. No cookie required.
|
||||
|
||||
Login with Google ID token
|
||||
|
||||
Verifies a Google ID token, checks allowlist (or creates entry when `IMPLICIT_CREATE=true`),
|
||||
Verifies a Google ID token, checks allowlist (or creates entry when `IMPLICIT_CREATE=true`
|
||||
or when the email has a pending auto-invitation),
|
||||
stores Google `sub` and profile image bytes, and sets an HTTP-only `token` cookie.
|
||||
`user.picture` is the profile image as base64 (same as GET /auth/me).
|
||||
|
||||
@@ -43,7 +44,7 @@ Login successful; `token` cookie set
|
||||
|--------|-------------|
|
||||
| 400 | Missing token or Google client not configured — `{"error":"…"}` |
|
||||
| 401 | Invalid Google token or account — `{"error":"…"}` |
|
||||
| 403 | Email not on allowlist — `{"error":"…"}` |
|
||||
| 403 | Email not on allowlist or invited — `{"error":"…"}` |
|
||||
| 500 | Server error — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
@@ -6,7 +6,7 @@ Current user
|
||||
|
||||
Returns the authenticated user from the session cookie and the Google client ID.
|
||||
`user.picture` is the stored profile image as a base64 string when present.
|
||||
Unauthenticated calls still receive `googleClientId` with 401.
|
||||
Unauthenticated calls still receive `googleClientId` and `schemaVersion` with 401.
|
||||
|
||||
|
||||
## Response `200`
|
||||
@@ -21,7 +21,10 @@ Authenticated
|
||||
"selectedCompanyId": 1,
|
||||
"picture": "…"
|
||||
},
|
||||
"googleClientId": "…"
|
||||
"googleClientId": "…",
|
||||
"schemaVersion": 1,
|
||||
"vhost": true,
|
||||
"vhostSettings": "…"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -29,7 +32,7 @@ Authenticated
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 401 | Unauthorized — still includes `googleClientId` for the frontend |
|
||||
| 401 | Unauthorized — still includes `googleClientId` and `schemaVersion` for the frontend |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -18,6 +18,10 @@ Sets the authenticated user's selected company.
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signals: `user`, `company` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
|
||||
Updated user
|
||||
@@ -39,6 +43,7 @@ Updated user
|
||||
|--------|-------------|
|
||||
| 400 | Invalid companyId — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized (the user is not a member of this company) — `{"error":"…"}` |
|
||||
| 500 | Server error — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
55
docs/api/routes/autoinvite/create.md
Normal file
55
docs/api/routes/autoinvite/create.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# `POST /autoinvite`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Create auto-invitation
|
||||
|
||||
Registers an email for automatic membership. When a user with this email registers,
|
||||
the invitation is removed from the list and the user is added to the company with the given role.
|
||||
Emails that are already registered are rejected (409); use `POST /companyuser` for those. Admin only.
|
||||
|
||||
|
||||
## Body (JSON)
|
||||
|
||||
| Field | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `email` | yes | string | |
|
||||
| `role` | no | string | |
|
||||
|
||||
```json
|
||||
{
|
||||
"email": "newhire@example.com",
|
||||
"role": "user"
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `autoinvite` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `201`
|
||||
|
||||
Created invitation
|
||||
|
||||
```json
|
||||
{
|
||||
"autoinvite": {
|
||||
"id": 1,
|
||||
"email": "…",
|
||||
"role": "admin"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | No company selected, invalid email or invalid role — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized (admin of the selected company required) — `{"error":"…"}` |
|
||||
| 409 | User already registered or invitation already exists — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
36
docs/api/routes/autoinvite/delete.md
Normal file
36
docs/api/routes/autoinvite/delete.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# `DELETE /autoinvite/{id}`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Delete auto-invitation
|
||||
|
||||
Deletes a pending auto-invitation of the selected company. Admin only.
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | |
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `autoinvite` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `204`
|
||||
|
||||
Deleted
|
||||
|
||||
_No content_
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Invalid id or no company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized (admin of the selected company required) — `{"error":"…"}` |
|
||||
| 404 | Invitation not found — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
36
docs/api/routes/autoinvite/list.md
Normal file
36
docs/api/routes/autoinvite/list.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# `GET /autoinvite`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
List auto-invitations
|
||||
|
||||
Lists pending auto-invitations of the selected company. Admin only.
|
||||
|
||||
## Response `200`
|
||||
|
||||
Pending invitations
|
||||
|
||||
```json
|
||||
{
|
||||
"autoinvites": [
|
||||
{
|
||||
"id": 1,
|
||||
"email": "…",
|
||||
"role": "admin",
|
||||
"createdAt": "…"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | No company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized (admin of the selected company required) — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
64
docs/api/routes/category/_id/image/generate.md
Normal file
64
docs/api/routes/category/_id/image/generate.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# `POST /category/{id}/image/generate`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Generate category mosaic image from contents
|
||||
|
||||
Generates a 2x2, 3x3, or 4x4 mosaic image from the category's and its subcategories'
|
||||
articles (grouped by subcategory) and sets it as the new main picture for the category.
|
||||
If size is not specified, defaults to 3 (3x3), falling back to 2 (2x2) if fewer than 7 images are available.
|
||||
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | Category id |
|
||||
|
||||
## Body (JSON) — _optional_
|
||||
|
||||
| Field | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `size` | no | integer | Mosaic grid size (2 for 2x2, 3 for 3x3, 4 for 4x4). Defaults to 3x3 (or 2x2 if < 7 images). |
|
||||
|
||||
```json
|
||||
{
|
||||
"size": 1
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `category` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
|
||||
Mosaic image generated and linked as category main picture
|
||||
|
||||
```json
|
||||
{
|
||||
"category": {
|
||||
"id": 1,
|
||||
"fullHash": "…",
|
||||
"thumbW": 1,
|
||||
"thumbH": 1,
|
||||
"thumbHash": "…",
|
||||
"size": 1,
|
||||
"grid": "…",
|
||||
"articleCount": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Invalid category ID or size — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized — `{"error":"…"}` |
|
||||
| 404 | Category not found or no article images found — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
@@ -4,7 +4,7 @@ Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Articles in category
|
||||
|
||||
Returns articles in a category the user is authorized for (omits child articles of a parent article), sorted alphabetically by name. Each article includes `childCount` (the number of its child articles) and small thumbnail fields (`smallThumbW`, `smallThumbH`, `smallThumbBinary`).
|
||||
Returns articles in a category the user is authorized for, sorted alphabetically by name. By default includes child articles (variants); pass `includeChildren=false` to omit them. Each article includes `childCount` (the number of its child articles) and small thumbnail fields (`smallThumbW`, `smallThumbH`, `smallThumbBinary`).
|
||||
|
||||
## Path parameters
|
||||
|
||||
@@ -12,6 +12,12 @@ Returns articles in a category the user is authorized for (omits child articles
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | Category id |
|
||||
|
||||
## Query parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `includeChildren` | no | boolean | When true (default), includes child articles (variants) alongside parent articles. Set to false to omit child articles. |
|
||||
|
||||
## Response `200`
|
||||
|
||||
Articles list
|
||||
|
||||
@@ -24,6 +24,10 @@ Creates a company and selects it for the current user.
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signals: `user`, `company` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `201`
|
||||
|
||||
Created; selected company updated
|
||||
@@ -38,7 +42,8 @@ Created; selected company updated
|
||||
"iso639": "…",
|
||||
"taxrate": 1,
|
||||
"reducedtaxrate": 1,
|
||||
"taxfreerate": 1
|
||||
"taxfreerate": 1,
|
||||
"role": "admin"
|
||||
},
|
||||
"user": {
|
||||
"id": 1,
|
||||
@@ -55,6 +60,7 @@ Created; selected company updated
|
||||
|--------|-------------|
|
||||
| 400 | Validation error — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized (invited users cannot create companies when implicit create is disabled) — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -12,6 +12,10 @@ Deletes a company.
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | |
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signals: `user`, `company` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `204`
|
||||
|
||||
Deleted
|
||||
|
||||
@@ -21,7 +21,8 @@ Company list
|
||||
"iso639": "…",
|
||||
"taxrate": 1,
|
||||
"reducedtaxrate": 1,
|
||||
"taxfreerate": 1
|
||||
"taxfreerate": 1,
|
||||
"role": "admin"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -30,6 +30,10 @@ Updates a company.
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `company` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
|
||||
Updated
|
||||
@@ -44,7 +48,8 @@ Updated
|
||||
"iso639": "…",
|
||||
"taxrate": 1,
|
||||
"reducedtaxrate": 1,
|
||||
"taxfreerate": 1
|
||||
"taxfreerate": 1,
|
||||
"role": "admin"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
58
docs/api/routes/companyuser/create.md
Normal file
58
docs/api/routes/companyuser/create.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# `POST /companyuser`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Add an existing user to the company
|
||||
|
||||
Adds an existing (registered) user, identified by email, to the selected company. Admin only.
|
||||
The added user can then switch to this company via `PUT /auth/selected-company`.
|
||||
For emails that are not registered yet use `POST /autoinvite`.
|
||||
|
||||
|
||||
## Body (JSON)
|
||||
|
||||
| Field | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `email` | yes | string | |
|
||||
| `role` | no | string | |
|
||||
|
||||
```json
|
||||
{
|
||||
"email": "colleague@example.com",
|
||||
"role": "user"
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `companyuser` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `201`
|
||||
|
||||
Created company user
|
||||
|
||||
```json
|
||||
{
|
||||
"companyuser": {
|
||||
"id": 1,
|
||||
"googleAuthId": 1,
|
||||
"email": "…",
|
||||
"picture": "…",
|
||||
"role": "admin"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | No company selected, invalid email or invalid role — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized (admin of the selected company required) — `{"error":"…"}` |
|
||||
| 404 | No registered user with this email — `{"error":"…"}` |
|
||||
| 409 | User already in company — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
40
docs/api/routes/companyuser/delete.md
Normal file
40
docs/api/routes/companyuser/delete.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# `DELETE /companyuser/{id}`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Remove a user from the company
|
||||
|
||||
Removes a member from the selected company. History entries stay but lose their author link;
|
||||
if the removed user had this company selected, their selection is cleared.
|
||||
The last admin cannot be removed. Admin only.
|
||||
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | |
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `companyuser` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `204`
|
||||
|
||||
Removed
|
||||
|
||||
_No content_
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Invalid id or no company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized (admin of the selected company required) — `{"error":"…"}` |
|
||||
| 404 | Company user not found — `{"error":"…"}` |
|
||||
| 409 | Cannot remove the last admin — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
37
docs/api/routes/companyuser/list.md
Normal file
37
docs/api/routes/companyuser/list.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# `GET /companyuser`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
List company users
|
||||
|
||||
Lists the members of the selected company with their role. Admin only.
|
||||
|
||||
## Response `200`
|
||||
|
||||
Company members
|
||||
|
||||
```json
|
||||
{
|
||||
"companyusers": [
|
||||
{
|
||||
"id": 1,
|
||||
"googleAuthId": 1,
|
||||
"email": "…",
|
||||
"picture": "…",
|
||||
"role": "admin"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | No company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized (admin of the selected company required) — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
59
docs/api/routes/companyuser/update.md
Normal file
59
docs/api/routes/companyuser/update.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# `PATCH /companyuser/{id}`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Change a company user's role
|
||||
|
||||
Changes the role of a member of the selected company. The last admin cannot be demoted. Admin only.
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | |
|
||||
|
||||
## Body (JSON)
|
||||
|
||||
| Field | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `role` | yes | string | |
|
||||
|
||||
```json
|
||||
{
|
||||
"role": "admin"
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `companyuser` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
|
||||
Updated company user
|
||||
|
||||
```json
|
||||
{
|
||||
"companyuser": {
|
||||
"id": 1,
|
||||
"googleAuthId": 1,
|
||||
"email": "…",
|
||||
"picture": "…",
|
||||
"role": "admin"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Invalid id, role or no company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized (admin of the selected company required) — `{"error":"…"}` |
|
||||
| 404 | Company user not found — `{"error":"…"}` |
|
||||
| 409 | Cannot demote the last admin — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
@@ -4,42 +4,54 @@ Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Subscribe to update signals (SSE)
|
||||
|
||||
Opens a Server-Sent Events stream for the authenticated user's
|
||||
**selected company**. Clients receive named signals when another
|
||||
request successfully mutates shared data for that company
|
||||
(including the same browser's other tabs).
|
||||
Opens a Server-Sent Events stream for the authenticated user.
|
||||
Can be opened before a company is selected (`selectedCompanyId == null`);
|
||||
when a company is selected or changed, the stream receives `user`
|
||||
(`{ selectedCompanyId }`) and `company` (`{ companyId }`) events and
|
||||
updates its company scope in-place.
|
||||
Clients also receive named signals when another request successfully
|
||||
mutates shared data for the active company (including the same
|
||||
browser's other tabs).
|
||||
|
||||
Use `EventSource` with credentials so the session cookie is sent:
|
||||
|
||||
```js
|
||||
const es = new EventSource('https://…/api/events', { withCredentials: true });
|
||||
es.addEventListener('user', () => { refetchAuthMe(); });
|
||||
es.addEventListener('company', () => { refetchCompany(); });
|
||||
es.addEventListener('category', () => { refetchCategoryTree(); });
|
||||
es.addEventListener('articles', () => { refetchArticleIndex(); });
|
||||
es.addEventListener('article-42000045', () => { refetchArticle('42000045'); });
|
||||
```
|
||||
|
||||
Keep-alive comments (`: heartbeat`) are sent roughly every 20s.
|
||||
Reconnect after changing the selected company (the stream is bound
|
||||
to the company at connect time).
|
||||
|
||||
## Signals
|
||||
|
||||
Every SSE event uses the event name as the signal id; payloads are
|
||||
JSON and most events send an empty object `{}`. Only `brand` emits a
|
||||
richer payload.
|
||||
JSON and most events send an empty object `{}`. `user` emits
|
||||
`{ selectedCompanyId }`, `company` emits `{ companyId }`, and `brand`
|
||||
emits `{ sender, brandId }`.
|
||||
|
||||
| Signal | Payload | Emitted after successful |
|
||||
|--------|---------|--------------------------|
|
||||
| `user` | `{ selectedCompanyId }` | `PUT /auth/selected-company`, `POST /company`, `DELETE /company/{id}` |
|
||||
| `company` | `{ companyId }` | `PUT /auth/selected-company`, `POST /company`, `PUT /company/{id}`, `DELETE /company/{id}` |
|
||||
| `category` | `{}` | `POST /category`, `PATCH /category/{id}`, `PUT /category/order`, `DELETE /category/{id}`, `POST /category/{id}/image`, `DELETE /category/{id}/image`, `PUT /category/{id}/property` |
|
||||
| `articles` | `{}` | `POST /article`, `PATCH /article/{sku}`, `DELETE /article/{sku}`, `PUT /article/{sku}/articles`-style list-level changes, `POST /category/{id}/article` and related article-assigning category mutations |
|
||||
| `article-<sku>` | `{}` | `PUT /article/{sku}/weight`, `PUT /article/{sku}/prices`, `PUT /article/{sku}/eans`, `PUT /article/{sku}/categories`, `PUT /article/{sku}/brand`, `PUT /article/{sku}/images/order`, `POST /article/{sku}/image`, `DELETE /article/{sku}/image/{fullHash}`, supplier/article-property mutations affecting the article |
|
||||
| `stock` | `{}` | `POST /stock/adjust` |
|
||||
| `stock` | `{}` | `POST /stock/adjust`, `POST /company/import` (also `category`, `articles`, `brand`, `attributename`, `warehouse`, `carrier`, `supplier`, `order`, `shipment`, `ledger`) |
|
||||
| `ledger` | `{}` | `POST /stock/adjust` |
|
||||
| `attributename` | `{}` | `POST /attributename`, `PUT /attributename/order`, `PATCH /attributename/{id}`, `DELETE /attributename/{id}` |
|
||||
| `propertyname` | `{}` | `POST /propertyname`, `PUT /propertyname/order`, `PATCH /propertyname/{id}`, `DELETE /propertyname/{id}` |
|
||||
| `labeltemplate` | `{}` | `POST /labeltemplate`, `PUT /labeltemplate/{id}`, `PATCH /labeltemplate/{id}`, `DELETE /labeltemplate/{id}` |
|
||||
| `printer` | `{}` | `POST /printer`, `PUT /printer/{id}`, `PATCH /printer/{id}`, `DELETE /printer/{id}` |
|
||||
| `printeragent` | `{}` | `PUT /printeragent`, `PATCH /printeragent/{id}`, `DELETE /printeragent/{id}`, printer agent connect/disconnect/state |
|
||||
| `agentprinter` | `{ printers }` or `{}` | `PATCH /agentprinter/{id}`, `PUT /agentprinter/order`, `DELETE /agentprinter/{id}`, agent state updates / printer discovery |
|
||||
| `companyuser` | `{}` | `POST /companyuser`, `PATCH /companyuser/{id}`, `DELETE /companyuser/{id}` |
|
||||
| `autoinvite` | `{}` | `POST /autoinvite`, `DELETE /autoinvite/{id}` |
|
||||
| `warehouse` | `{}` | `POST /warehouse`, `PUT /warehouse/{id}`, `PATCH /warehouse/{id}`, `DELETE /warehouse/{id}` |
|
||||
| `supplier` | `{}` | `POST /supplier`, `PATCH /supplier/{id}`, `DELETE /supplier/{id}` |
|
||||
| `vfs` | `{}` | VFS uploads and filesystem mutations such as `POST /vfs/upload`, `POST /vfs/mkdir`, `POST /vfs/rename`, `PUT /vfs/{*path}`, `DELETE /vfs/{*path}` |
|
||||
| `modelconversation` | `{}` | `POST /modelconversation`, `DELETE /modelconversation/{id}` |
|
||||
| `modelconversation-<id>` | `{}` | Conversation-specific updates on the same model conversation thread; the concrete ID is used in the event name |
|
||||
@@ -60,14 +72,15 @@ runtime (for example `article-42000045` and `modelconversation-123`).
|
||||
|
||||
SSE stream (`text/event-stream`). Each signal is an SSE event
|
||||
whose name is the signal id. Most signals send `{}` as data;
|
||||
`brand` sends `{ "sender": "<x-client-id>", "brandId": 12 }`.
|
||||
`user` sends `{ "selectedCompanyId": 1 }`, `company` sends
|
||||
`{ "companyId": 1 }`, and `brand` sends
|
||||
`{ "sender": "<x-client-id>", "brandId": 12 }`.
|
||||
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | No company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
57
docs/api/routes/labeltemplate/testprint.md
Normal file
57
docs/api/routes/labeltemplate/testprint.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# `POST /labeltemplate/testprint`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Test print label template
|
||||
|
||||
Dispatches a test print job for a label template or unsaved canvas objects to a specified ZPL printer.
|
||||
Placeholders in text and barcodes are interpolated using a sample article or the specified article SKU.
|
||||
|
||||
|
||||
## Body (JSON)
|
||||
|
||||
| Field | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `agentprinterId` | yes | integer | Agent printer ID |
|
||||
| `templateId` | no | integer | |
|
||||
| `objects` | no | any[] | |
|
||||
| `width` | no | integer | |
|
||||
| `height` | no | integer | |
|
||||
| `dpi` | no | integer | |
|
||||
| `sku` | no | string | |
|
||||
| `quantity` | no | integer | |
|
||||
|
||||
```json
|
||||
{
|
||||
"agentprinterId": 1,
|
||||
"templateId": 1,
|
||||
"objects": [],
|
||||
"width": 1,
|
||||
"height": 1,
|
||||
"dpi": 1,
|
||||
"sku": "…",
|
||||
"quantity": 1
|
||||
}
|
||||
```
|
||||
|
||||
## Response `200`
|
||||
|
||||
Print job created
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Invalid parameters |
|
||||
| 404 | Printer or template not found |
|
||||
| 500 | Server error |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
34
docs/api/routes/pos/cimage.md
Normal file
34
docs/api/routes/pos/cimage.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# `GET /v1/cimage`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
POS category image delivery
|
||||
|
||||
Returns category image by hash (`path` query param) scaled to preview size (padded to 1:1 with white background).
|
||||
|
||||
|
||||
## Query parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `path` | yes | string | SHA-256 hash of the category image |
|
||||
| `size` | no | integer | Max dimension (width & height, capped to 200) |
|
||||
| `w` | no | integer | Max width (capped to 200) |
|
||||
| `h` | no | integer | Max height (capped to 200) |
|
||||
| `format` | no | string | Optional target format (defaults to jpeg/png or client Accept preference) |
|
||||
|
||||
## Response `200`
|
||||
|
||||
Resized image binary
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 304 | Image not modified |
|
||||
| 400 | Missing required query parameter 'path' |
|
||||
| 404 | Image not found |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
@@ -15,6 +15,7 @@ Special API for POS bind and sync.
|
||||
|-------|----------|------|-------------|
|
||||
| `authCode` | yes | string | Discovery code (1-4 digits) or pairing PIN (6 digits) |
|
||||
| `name` | no | string | Client device name or serial identifier (default 'JTL-POS') |
|
||||
| `clientversion` | no | string | Optional client app version (for future POS clients during pairing) |
|
||||
|
||||
## Response `200`
|
||||
|
||||
|
||||
@@ -4,20 +4,21 @@ Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
POS sync initialization counts
|
||||
|
||||
Returns entity change counts since the provided `lastChanged*` unix timestamp cursors
|
||||
for the authenticated POS terminal (`Authorization: Bearer <authToken>`).
|
||||
Returns entity change counts since the provided `lastChanged*` sync queue ID cursors
|
||||
(`posterminalsyncqueue.id` / `posterminalobituary.id`) for the authenticated POS terminal
|
||||
(`Authorization: Bearer <authToken>`).
|
||||
|
||||
|
||||
## Query parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `lastChangedProduct` | no | integer | Unix timestamp of last synced product update |
|
||||
| `lastChangedCategory` | no | integer | Unix timestamp of last synced category update |
|
||||
| `lastChangedCustomer` | no | integer | Unix timestamp of last synced customer update |
|
||||
| `lastChangedCustomerGroup` | no | integer | Unix timestamp of last synced customer group update |
|
||||
| `lastChangedCompositeProduct` | no | integer | Unix timestamp of last synced composite product update |
|
||||
| `lastChangedDeletedEntity` | no | integer | Unix timestamp of last synced deleted entity |
|
||||
| `lastChangedProduct` | no | integer | Sequential ID cursor of last synced product entry (`posterminalsyncqueue.id`) |
|
||||
| `lastChangedCategory` | no | integer | Sequential ID cursor of last synced category entry (`posterminalsyncqueue.id`) |
|
||||
| `lastChangedCustomer` | no | integer | Sequential ID cursor of last synced customer entry (`posterminalsyncqueue.id`) |
|
||||
| `lastChangedCustomerGroup` | no | integer | Sequential ID cursor of last synced customer group entry (`posterminalsyncqueue.id`) |
|
||||
| `lastChangedCompositeProduct` | no | integer | Sequential ID cursor of last synced composite product entry (`posterminalsyncqueue.id`) |
|
||||
| `lastChangedDeletedEntity` | no | integer | Sequential ID cursor of last synced deleted entity (`posterminalobituary.id`) |
|
||||
|
||||
## Response `200`
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ Returns product image by hash (`path` query param) scaled to preview size.
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `path` | yes | string | SHA-256 hash of the product image |
|
||||
| `size` | no | integer | Max dimension (width & height) |
|
||||
| `w` | no | integer | Max width |
|
||||
| `h` | no | integer | Max height |
|
||||
| `format` | no | string | Optional target format (defaults to jpeg/png or client Accept preference) |
|
||||
|
||||
@@ -22,6 +22,9 @@ Posterminal list
|
||||
"clientserial": "…",
|
||||
"rootCategoryId": 1,
|
||||
"syncRootArticles": true,
|
||||
"sort": 1,
|
||||
"enabled": true,
|
||||
"clientversion": "…",
|
||||
"lastseenAt": "…",
|
||||
"updatedAt": "…",
|
||||
"categoryIds": [
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Disable category on terminal
|
||||
Disable category and subcategories on terminal
|
||||
|
||||
Removes a single category's visibility on a terminal (idempotent).
|
||||
Removes a category and all its descendant subcategories from a terminal (idempotent).
|
||||
|
||||
## Path parameters
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Enable category on terminal
|
||||
Enable category and subcategories on terminal
|
||||
|
||||
Toggles a single category's visibility on a terminal (idempotent).
|
||||
Enables a category and all its descendant subcategories on a terminal (idempotent).
|
||||
|
||||
## Path parameters
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ Updates a POS terminal configuration (name, root category, sync settings, or pai
|
||||
| `name` | no | string | |
|
||||
| `rootCategoryId` | no | integer | |
|
||||
| `syncRootArticles` | no | boolean | |
|
||||
| `sort` | no | integer | |
|
||||
| `enabled` | no | boolean | |
|
||||
| `pairingpin` | no | string | |
|
||||
|
||||
```json
|
||||
@@ -44,6 +46,9 @@ Updated posterminal
|
||||
"clientserial": "…",
|
||||
"rootCategoryId": 1,
|
||||
"syncRootArticles": true,
|
||||
"sort": 1,
|
||||
"enabled": true,
|
||||
"clientversion": "…",
|
||||
"lastseenAt": "…",
|
||||
"updatedAt": "…",
|
||||
"categoryIds": [
|
||||
|
||||
@@ -15,6 +15,8 @@ The pairingpin is randomly generated server-side and returned in the response.
|
||||
| `name` | yes | string | |
|
||||
| `rootCategoryId` | no | integer | |
|
||||
| `syncRootArticles` | no | boolean | |
|
||||
| `sort` | no | integer | |
|
||||
| `enabled` | no | boolean | |
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -37,6 +39,9 @@ Created posterminal with generated pairingpin
|
||||
"clientserial": "…",
|
||||
"rootCategoryId": 1,
|
||||
"syncRootArticles": true,
|
||||
"sort": 1,
|
||||
"enabled": true,
|
||||
"clientversion": "…",
|
||||
"lastseenAt": "…",
|
||||
"updatedAt": "…",
|
||||
"categoryIds": [
|
||||
|
||||
37
docs/api/routes/printer/_id/state.md
Normal file
37
docs/api/routes/printer/_id/state.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# `GET /printer/{id}/state`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Get live state for a printer
|
||||
|
||||
Retrieves live operational status for a single printer by configured printer ID,
|
||||
serial number, or device identifier for the authenticated user's selected company.
|
||||
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | string | Configured printer ID, serial number, or device identifier |
|
||||
|
||||
## Response `200`
|
||||
|
||||
Live printer state
|
||||
|
||||
```json
|
||||
{
|
||||
"printer": {}
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | No company selected or invalid ID — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 404 | Printer not found — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
39
docs/api/routes/printer/state.md
Normal file
39
docs/api/routes/printer/state.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# `GET /printer/state`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Get live printer states
|
||||
|
||||
Retrieves real-time operational status and telemetry for all discovered printers
|
||||
reported by active printer agents for the authenticated user's selected company.
|
||||
|
||||
|
||||
## Query parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `serial` | no | string | Optional serial number filter |
|
||||
| `agentId` | no | integer | Optional agent ID filter |
|
||||
|
||||
## Response `200`
|
||||
|
||||
Live printer states
|
||||
|
||||
```json
|
||||
{
|
||||
"printers": [
|
||||
{}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | No company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
44
docs/api/routes/printeragent.get.md
Normal file
44
docs/api/routes/printeragent.get.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# `GET /printeragent`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
List printer agents
|
||||
|
||||
Lists printer agents for the authenticated user's selected company.
|
||||
|
||||
## Response `200`
|
||||
|
||||
Printer agent list
|
||||
|
||||
```json
|
||||
{
|
||||
"printeragents": [
|
||||
{
|
||||
"id": 1,
|
||||
"companyId": 1,
|
||||
"name": "…",
|
||||
"token": "…",
|
||||
"pairingpin": "…",
|
||||
"pairedAt": "…",
|
||||
"agentversion": "…",
|
||||
"lastseenAt": "…",
|
||||
"updatedAt": "…",
|
||||
"sort": 1,
|
||||
"enabled": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | No company selected or invalid input — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized — `{"error":"…"}` |
|
||||
| 404 | Company not found — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
58
docs/api/routes/printeragent.put.md
Normal file
58
docs/api/routes/printeragent.put.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# `PUT /printeragent`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Create printer agent
|
||||
|
||||
Creates an unpaired printer agent for the selected company.
|
||||
The pairingpin is randomly generated server-side and returned in the response.
|
||||
|
||||
|
||||
## Body (JSON)
|
||||
|
||||
| Field | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `name` | yes | string | |
|
||||
| `sort` | no | integer | |
|
||||
| `enabled` | no | boolean | |
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Bar printer"
|
||||
}
|
||||
```
|
||||
|
||||
## Response `200`
|
||||
|
||||
Created printer agent with generated pairingpin
|
||||
|
||||
```json
|
||||
{
|
||||
"printeragent": {
|
||||
"id": 1,
|
||||
"companyId": 1,
|
||||
"name": "…",
|
||||
"token": "…",
|
||||
"pairingpin": "…",
|
||||
"pairedAt": "…",
|
||||
"agentversion": "…",
|
||||
"lastseenAt": "…",
|
||||
"updatedAt": "…",
|
||||
"sort": 1,
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | No company selected or invalid input — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized — `{"error":"…"}` |
|
||||
| 404 | Company not found — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
30
docs/api/routes/printeragent/_id.delete.md
Normal file
30
docs/api/routes/printeragent/_id.delete.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# `DELETE /printeragent/{id}`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Delete printer agent
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | |
|
||||
|
||||
## Response `204`
|
||||
|
||||
Deleted
|
||||
|
||||
_No content_
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | No company selected or invalid id — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized — `{"error":"…"}` |
|
||||
| 404 | Printeragent not found — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
64
docs/api/routes/printeragent/_id.patch.md
Normal file
64
docs/api/routes/printeragent/_id.patch.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# `PATCH /printeragent/{id}`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Update printer agent
|
||||
|
||||
Updates name and/or display order (sort) of a printer agent.
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | |
|
||||
|
||||
## Body (JSON)
|
||||
|
||||
| Field | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `name` | no | string | |
|
||||
| `sort` | no | integer | |
|
||||
| `enabled` | no | boolean | |
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "…",
|
||||
"sort": 1,
|
||||
"enabled": true
|
||||
}
|
||||
```
|
||||
|
||||
## Response `200`
|
||||
|
||||
Updated printer agent
|
||||
|
||||
```json
|
||||
{
|
||||
"printeragent": {
|
||||
"id": 1,
|
||||
"companyId": 1,
|
||||
"name": "…",
|
||||
"token": "…",
|
||||
"pairingpin": "…",
|
||||
"pairedAt": "…",
|
||||
"agentversion": "…",
|
||||
"lastseenAt": "…",
|
||||
"updatedAt": "…",
|
||||
"sort": 1,
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | No company selected or invalid input — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized — `{"error":"…"}` |
|
||||
| 404 | Printeragent not found — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
46
docs/api/routes/printerjob.get.md
Normal file
46
docs/api/routes/printerjob.get.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# `GET /printerjob`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
List printer jobs
|
||||
|
||||
Lists printer jobs for the selected company, optionally filtered by agent printer or state.
|
||||
|
||||
## Query parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `agentprinterId` | no | integer | Optional agent printer ID filter |
|
||||
| `state` | no | string | Optional job state filter |
|
||||
|
||||
## Response `200`
|
||||
|
||||
List of printer jobs
|
||||
|
||||
```json
|
||||
{
|
||||
"printerjobs": [
|
||||
{
|
||||
"id": 1,
|
||||
"agentprinterId": 1,
|
||||
"printeragentId": 1,
|
||||
"type": "zpl",
|
||||
"state": "pending",
|
||||
"data": "…",
|
||||
"createdAt": "2026-08-10T00:00:00.000Z",
|
||||
"completedAt": "2026-08-10T00:00:00.000Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | No company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
46
docs/api/routes/printerjob.post.md
Normal file
46
docs/api/routes/printerjob.post.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# `POST /printerjob`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Create print job
|
||||
|
||||
Creates a new print job for an agent printer. Notifies the agent in real time.
|
||||
|
||||
## Body (JSON)
|
||||
|
||||
| Field | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `agentprinterId` | yes | integer | |
|
||||
| `type` | no | string | |
|
||||
| `data` | yes | string | |
|
||||
|
||||
```json
|
||||
{
|
||||
"agentprinterId": 1,
|
||||
"type": "zpl",
|
||||
"data": "…"
|
||||
}
|
||||
```
|
||||
|
||||
## Response `201`
|
||||
|
||||
Printer job created
|
||||
|
||||
```json
|
||||
{
|
||||
"printerjob": {
|
||||
"id": 1,
|
||||
"agentprinterId": 1,
|
||||
"printeragentId": 1,
|
||||
"type": "zpl",
|
||||
"state": "pending",
|
||||
"data": "…",
|
||||
"createdAt": "2026-08-10T00:00:00.000Z",
|
||||
"completedAt": "2026-08-10T00:00:00.000Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
39
docs/api/routes/printerjob/_id.delete.md
Normal file
39
docs/api/routes/printerjob/_id.delete.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# `DELETE /printerjob/{id}`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Cancel and delete printer job
|
||||
|
||||
Cancels and deletes a print job. If the job was pending or processing, sends a cancellation
|
||||
event to the connected printer agent before deletion.
|
||||
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | |
|
||||
|
||||
## Response `200`
|
||||
|
||||
Job cancelled and deleted
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"deletedJob": {
|
||||
"id": 1,
|
||||
"agentprinterId": 1,
|
||||
"printeragentId": 1,
|
||||
"type": "zpl",
|
||||
"state": "pending",
|
||||
"data": "…",
|
||||
"createdAt": "2026-08-10T00:00:00.000Z",
|
||||
"completedAt": "2026-08-10T00:00:00.000Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
44
docs/api/routes/printerjob/_id.get.md
Normal file
44
docs/api/routes/printerjob/_id.get.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# `GET /printerjob/{id}`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Get printer job
|
||||
|
||||
Retrieves details of a specific printer job by ID.
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | |
|
||||
|
||||
## Response `200`
|
||||
|
||||
Printer job details
|
||||
|
||||
```json
|
||||
{
|
||||
"printerjob": {
|
||||
"id": 1,
|
||||
"agentprinterId": 1,
|
||||
"printeragentId": 1,
|
||||
"type": "zpl",
|
||||
"state": "pending",
|
||||
"data": "…",
|
||||
"createdAt": "2026-08-10T00:00:00.000Z",
|
||||
"completedAt": "2026-08-10T00:00:00.000Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Invalid ID or no company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 404 | Printer job not found — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
37
docs/api/routes/printerjob/_id/cancel.md
Normal file
37
docs/api/routes/printerjob/_id/cancel.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# `POST /printerjob/{id}/cancel`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Cancel printer job
|
||||
|
||||
Marks a print job as cancelled and notifies the connected agent in real time.
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | |
|
||||
|
||||
## Response `200`
|
||||
|
||||
Printer job cancelled
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"printerjob": {
|
||||
"id": 1,
|
||||
"agentprinterId": 1,
|
||||
"printeragentId": 1,
|
||||
"type": "zpl",
|
||||
"state": "pending",
|
||||
"data": "…",
|
||||
"createdAt": "2026-08-10T00:00:00.000Z",
|
||||
"completedAt": "2026-08-10T00:00:00.000Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
48
docs/api/routes/printerjob/cancel-all.md
Normal file
48
docs/api/routes/printerjob/cancel-all.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# `POST /printerjob/cancel-all`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Cancel all pending and processing printer jobs
|
||||
|
||||
Cancels all queued or in-flight print jobs for the selected company, optionally filtered by agentprinterId.
|
||||
Notifies connected agents in real time.
|
||||
|
||||
|
||||
## Body (JSON)
|
||||
|
||||
| Field | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `agentprinterId` | no | integer | |
|
||||
|
||||
```json
|
||||
{
|
||||
"agentprinterId": 1
|
||||
}
|
||||
```
|
||||
|
||||
## Response `200`
|
||||
|
||||
All matching jobs cancelled
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"cancelledCount": 1,
|
||||
"jobs": [
|
||||
{
|
||||
"id": 1,
|
||||
"agentprinterId": 1,
|
||||
"printeragentId": 1,
|
||||
"type": "zpl",
|
||||
"state": "pending",
|
||||
"data": "…",
|
||||
"createdAt": "2026-08-10T00:00:00.000Z",
|
||||
"completedAt": "2026-08-10T00:00:00.000Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
36
docs/api/routes/retoure.get.md
Normal file
36
docs/api/routes/retoure.get.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# `GET /retoure`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
List retoures
|
||||
|
||||
Lists customer return manifests (`manifest` rows with `type = 'retoure'`)
|
||||
for the authenticated user's selected company.
|
||||
|
||||
|
||||
## Query parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `offset` | no | integer | |
|
||||
| `limit` | no | integer | |
|
||||
| `search` | no | string | |
|
||||
| `onlyUnpaid` | no | boolean | |
|
||||
| `onlyUndelivered` | no | boolean | |
|
||||
| `entityId` | no | integer | |
|
||||
| `seekMonths` | no | integer | |
|
||||
|
||||
## Response `200`
|
||||
|
||||
List of retoures
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Validation error |
|
||||
| 403 | Not authorized |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
33
docs/api/routes/retoure.post.md
Normal file
33
docs/api/routes/retoure.post.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# `POST /retoure`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Create retoure
|
||||
|
||||
## Body (JSON)
|
||||
|
||||
| Field | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `number` | no | string | |
|
||||
| `date` | yes | string | |
|
||||
| `entityId` | no | integer | |
|
||||
| `externalNumber` | no | string | |
|
||||
| `lines` | no | any[] | |
|
||||
|
||||
```json
|
||||
{
|
||||
"number": "…",
|
||||
"date": "…",
|
||||
"entityId": 1,
|
||||
"externalNumber": "…",
|
||||
"lines": []
|
||||
}
|
||||
```
|
||||
|
||||
## Response `201`
|
||||
|
||||
Retoure created
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
21
docs/api/routes/retoure/_id.delete.md
Normal file
21
docs/api/routes/retoure/_id.delete.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# `DELETE /retoure/{id}`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Delete retoure
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | |
|
||||
|
||||
## Response `204`
|
||||
|
||||
Retoure deleted
|
||||
|
||||
_No content_
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
25
docs/api/routes/retoure/_id.get.md
Normal file
25
docs/api/routes/retoure/_id.get.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# `GET /retoure/{id}`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Get retoure by ID
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | |
|
||||
|
||||
## Response `200`
|
||||
|
||||
Retoure details
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 404 | Retoure not found |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
25
docs/api/routes/retoure/_id.put.md
Normal file
25
docs/api/routes/retoure/_id.put.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# `PUT /retoure/{id}`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Update retoure
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | |
|
||||
|
||||
## Body (JSON)
|
||||
|
||||
```json
|
||||
{}
|
||||
```
|
||||
|
||||
## Response `200`
|
||||
|
||||
Retoure updated
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
19
docs/api/routes/retoure/_id/shipment.md
Normal file
19
docs/api/routes/retoure/_id/shipment.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# `POST /retoure/{id}/shipment`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Create shipment for retoure
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | |
|
||||
|
||||
## Response `201`
|
||||
|
||||
Shipment created
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
13
docs/api/routes/retoure/rebuild-summaries.md
Normal file
13
docs/api/routes/retoure/rebuild-summaries.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# `POST /retoure/rebuild-summaries`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Rebuild retoure summaries
|
||||
|
||||
## Response `200`
|
||||
|
||||
Summaries rebuilt
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
23
docs/api/routes/return.get.md
Normal file
23
docs/api/routes/return.get.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# `GET /return`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
List returns
|
||||
|
||||
## Query parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `offset` | no | integer | |
|
||||
| `limit` | no | integer | |
|
||||
| `search` | no | string | |
|
||||
| `onlyUnbooked` | no | boolean | |
|
||||
| `supplierId` | no | integer | |
|
||||
|
||||
## Response `200`
|
||||
|
||||
List of returns
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
19
docs/api/routes/return.post.md
Normal file
19
docs/api/routes/return.post.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# `POST /return`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Create return
|
||||
|
||||
## Body (JSON)
|
||||
|
||||
```json
|
||||
{}
|
||||
```
|
||||
|
||||
## Response `201`
|
||||
|
||||
Return created
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
21
docs/api/routes/return/_id.delete.md
Normal file
21
docs/api/routes/return/_id.delete.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# `DELETE /return/{id}`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Delete return
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | |
|
||||
|
||||
## Response `204`
|
||||
|
||||
Return deleted
|
||||
|
||||
_No content_
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
19
docs/api/routes/return/_id.get.md
Normal file
19
docs/api/routes/return/_id.get.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# `GET /return/{id}`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Get return by ID
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | |
|
||||
|
||||
## Response `200`
|
||||
|
||||
Return details
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
19
docs/api/routes/return/_id.put.md
Normal file
19
docs/api/routes/return/_id.put.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# `PUT /return/{id}`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Update return
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | |
|
||||
|
||||
## Response `200`
|
||||
|
||||
Return updated
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
19
docs/api/routes/return/_id/book.md
Normal file
19
docs/api/routes/return/_id/book.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# `POST /return/{id}/book`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Book return to ledger
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | |
|
||||
|
||||
## Response `200`
|
||||
|
||||
Return booked
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
13
docs/api/routes/return/rebuild-summaries.md
Normal file
13
docs/api/routes/return/rebuild-summaries.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# `POST /return/rebuild-summaries`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Rebuild return summaries
|
||||
|
||||
## Response `200`
|
||||
|
||||
Summaries rebuilt
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
@@ -4,7 +4,7 @@ Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Update shipment state or metadata
|
||||
|
||||
Updates delivery state (`new`, `delivered`, `returned`) for the shipment.
|
||||
Updates delivery state (`new`, `delivered`) for the shipment.
|
||||
Emits SSE events (`shipment`, `order`) so connected clients rerender in real time.
|
||||
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ Ship shipment manifest item(s)
|
||||
Books shipment for a shipment manifest item on the ledger (warehouse_id = null).
|
||||
If the connected article has stock tracking enabled, an adjustment entry is also
|
||||
booked to deduct physical stock from the target warehouse.
|
||||
If line amount is negative, books as a customer retoure (incoming).
|
||||
|
||||
|
||||
## Body (JSON)
|
||||
|
||||
@@ -19,6 +19,10 @@ Creates a supplier in the company `Lieferanten` group (created on first use).
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `supplier` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `201`
|
||||
|
||||
Created supplier
|
||||
|
||||
@@ -14,6 +14,10 @@ Related `entityhistory` cascades; `manifest.entity_id` is set null.
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | |
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `supplier` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `204`
|
||||
|
||||
Deleted
|
||||
|
||||
@@ -24,6 +24,10 @@ Renames a supplier for the selected company.
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `supplier` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
|
||||
Updated supplier
|
||||
|
||||
@@ -10,7 +10,7 @@ Returns category hierarchy modified after lastChangedCategory cursor for the aut
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `lastChangedCategory` | no | string | Unix timestamp cursor of last category sync |
|
||||
| `lastChangedCategory` | no | string | Sequential ID cursor of last synced category entry (`posterminalsyncqueue.id`) |
|
||||
| `limit` | no | integer | Maximum number of categories to return |
|
||||
|
||||
## Response `200`
|
||||
|
||||
56
docs/api/routes/v1/customer.md
Normal file
56
docs/api/routes/v1/customer.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# `GET /v1/customer`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
JTL-POS customer catalog synchronization
|
||||
|
||||
Returns customer list modified after lastChangedCustomer cursor for the authenticated POS register.
|
||||
|
||||
## Query parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `lastChangedCustomer` | no | string | Sequential ID cursor of last synced customer entry (`posterminalsyncqueue.id`) |
|
||||
| `limit` | no | integer | Maximum number of customers to return |
|
||||
|
||||
## Response `200`
|
||||
|
||||
Array of customer objects for JTL-POS
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "…",
|
||||
"customerNumber": "…",
|
||||
"firstname": "…",
|
||||
"lastname": "…",
|
||||
"title": "…",
|
||||
"company": "…",
|
||||
"address": "…",
|
||||
"addressSupplement": "…",
|
||||
"city": "…",
|
||||
"postalCode": "…",
|
||||
"state": "…",
|
||||
"country": "…",
|
||||
"phone": "…",
|
||||
"email": "…",
|
||||
"customerGroupId": "…",
|
||||
"salutation": "…",
|
||||
"birthday": "…",
|
||||
"discount": "…",
|
||||
"taxIdNumber": "…",
|
||||
"lastChanged": "…",
|
||||
"debtorNumber": "…"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 401 | Unauthorized |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
40
docs/api/routes/v1/customergroup.md
Normal file
40
docs/api/routes/v1/customergroup.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# `GET /v1/customergroup`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
JTL-POS customer group synchronization
|
||||
|
||||
Returns customer groups modified after lastChangedCustomerGroup cursor for the authenticated POS register, excluding 'Lieferanten'.
|
||||
|
||||
## Query parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `lastChangedCustomerGroup` | no | string | Sequential ID cursor of last synced customer group entry (`posterminalsyncqueue.id`) |
|
||||
| `limit` | no | integer | Maximum number of customer groups to return |
|
||||
|
||||
## Response `200`
|
||||
|
||||
Array of customer group objects for JTL-POS
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"customerGroupId": "1",
|
||||
"name": "Endkunden",
|
||||
"standard": "1",
|
||||
"discountPercent": "0.000000",
|
||||
"lastChanged": "12"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 401 | Unauthorized |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
38
docs/api/routes/v1/deletedentity.md
Normal file
38
docs/api/routes/v1/deletedentity.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# `GET /v1/deletedentity`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
JTL-POS deleted entity synchronization
|
||||
|
||||
Returns deleted entities after lastChangedDeletedEntity cursor for the authenticated POS register.
|
||||
|
||||
## Query parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `lastChangedDeletedEntity` | no | string | Sequential ID cursor of last processed obituary |
|
||||
| `limit` | no | integer | Maximum number of deleted entities to return |
|
||||
|
||||
## Response `200`
|
||||
|
||||
Array of deleted entity objects for JTL-POS
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"entityId": "123",
|
||||
"entityType": 1,
|
||||
"lastChanged": 45
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 401 | Unauthorized |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
52
docs/api/routes/v1/order.md
Normal file
52
docs/api/routes/v1/order.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# `POST /v1/order`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
JTL-POS order upload
|
||||
|
||||
Imports orders from JTL-POS, creating order and retoure manifests, payments, and shipments with stock adjustments.
|
||||
|
||||
## Query parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `mandantId` | no | string | |
|
||||
|
||||
## Body (JSON)
|
||||
|
||||
| Field | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `orders` | no | object[] | |
|
||||
|
||||
```json
|
||||
{
|
||||
"orders": [
|
||||
{}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Response `200`
|
||||
|
||||
Array of sync results per order
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"status": "OK",
|
||||
"externalOrderId": "2",
|
||||
"message": ""
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 401 | Unauthorized |
|
||||
| 500 | Internal server error |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
@@ -10,7 +10,7 @@ Returns product catalog with prices, stock, variants, and image hashes modified
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `lastChangedProduct` | no | string | Unix timestamp cursor of last product sync |
|
||||
| `lastChangedProduct` | no | string | Sequential ID cursor of last synced product entry (`posterminalsyncqueue.id`) |
|
||||
| `limit` | no | integer | Maximum number of products to return |
|
||||
|
||||
## Response `200`
|
||||
|
||||
@@ -20,7 +20,7 @@ Applets return typed CSV, not JSON: `result` is a `;`-separated CSV string with
|
||||
response also carries `columns` (name/type) and `rows` (data row count). Only declared columns are
|
||||
emitted, in header order; missing values become empty cells. Execution runs in the same isolated worker
|
||||
sandbox as the `javascript_execute` tool — including authenticated `fetch()` against this API,
|
||||
`fs`/`vfs`, `sharp`, ExcelJS, PDFKit and WebCrypto globals.
|
||||
`fs`/`vfs`, `optimizeImage`, ExcelJS, PDFKit and WebCrypto globals.
|
||||
|
||||
The path is taken from the URL (like `DELETE /vfs/{*path}`); the run arguments are the JSON body.
|
||||
Path traversal (`..`), null bytes, and backslashes are rejected with HTTP 400, as is a path that does
|
||||
|
||||
56
docs/api/routes/zpljob.md
Normal file
56
docs/api/routes/zpljob.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# `POST /zpljob`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Create ZPL print job
|
||||
|
||||
Issues a new ZPL print job to an agent printer. If copiescount > 1, the ZPL quantity command (^PQ)
|
||||
is automatically applied. The connected printer agent receives an immediate real-time event.
|
||||
|
||||
|
||||
## Body (JSON)
|
||||
|
||||
| Field | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `agentprinterId` | yes | integer | Target agent printer ID |
|
||||
| `copiescount` | no | integer | Optional copy count (defaults to 1) |
|
||||
| `data` | yes | string | Raw ZPL string |
|
||||
|
||||
```json
|
||||
{
|
||||
"agentprinterId": 1,
|
||||
"copiescount": 2,
|
||||
"data": "^XA^FO50,50^ADN,36,20^FDHello Zebra^FS^XZ"
|
||||
}
|
||||
```
|
||||
|
||||
## Response `201`
|
||||
|
||||
Print job created
|
||||
|
||||
```json
|
||||
{
|
||||
"printerjob": {
|
||||
"id": 1,
|
||||
"agentprinterId": 1,
|
||||
"printeragentId": 1,
|
||||
"type": "zpl",
|
||||
"state": "pending",
|
||||
"data": "…",
|
||||
"createdAt": "2026-08-10T00:00:00.000Z",
|
||||
"completedAt": "2026-08-10T00:00:00.000Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Invalid input or missing fields — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 404 | Agent printer not found — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
41
docs/dash.sh
Executable file
41
docs/dash.sh
Executable file
@@ -0,0 +1,41 @@
|
||||
#!/bin/bash
|
||||
# Ensure private Docker network exists and sql_server is connected
|
||||
docker network create dash_net 2>/dev/null || true
|
||||
docker network connect dash_net sql_server 2>/dev/null || true
|
||||
|
||||
docker rm -f dashback 2>/dev/null
|
||||
|
||||
docker run -d \
|
||||
--name dashback \
|
||||
--log-opt max-size=10m \
|
||||
--log-opt max-file=3 \
|
||||
--restart always \
|
||||
--network dash_net \
|
||||
--read-only \
|
||||
--tmpfs /tmp:rw,noexec,nosuid,size=512m \
|
||||
--tmpfs /run:rw,noexec,nosuid,size=16m \
|
||||
-u $(id -u):$(id -g) \
|
||||
-p 127.0.0.1:4211:4211 \
|
||||
-e HOST=0.0.0.0 \
|
||||
-e PORT=4211 \
|
||||
-e HTTPS_PORT=0 \
|
||||
-e MSSQL_SERVER=sql_server \
|
||||
-e HEALTH_MONITOR_ENABLED=false \
|
||||
-e SQLITE_PATH=/app/data/dash.db \
|
||||
-e STORAGE_DIR=/app/data/storage \
|
||||
-e BACKUP_DIR=/app/data/backups \
|
||||
-e GOOGLE_CLIENT_ID=928121624463-m9du45ek2d5f6p9cke8qpnf89ii9no20.apps.googleusercontent.com \
|
||||
-e JWT_SECRET=dfhjkswezui32476sdjkhvbn347865 \
|
||||
-e IMPLICIT_CREATE=true \
|
||||
-e VHOST_SETTINGS="" \
|
||||
-e DB_PROVIDER=mssql \
|
||||
-e MSSQL_DATABASE=dashback \
|
||||
-e MSSQL_USER=sa \
|
||||
-e MSSQL_PASSWORD=420Green \
|
||||
-e MSSQL_PORT=1433 \
|
||||
-e MSSQL_ENCRYPT=false \
|
||||
-e MSSQL_TRUST_SERVER_CERTIFICATE=false \
|
||||
-v "/home/ubuntu/src/docker/dashback_data:/app/data:rw" \
|
||||
-v "/home/ubuntu/src/docker/dashback/dist:/app/dist:ro" \
|
||||
-v "/home/ubuntu/src/docker/dashback/dist/dashback_current:/app/dist/dashback:ro" \
|
||||
dashback:latest
|
||||
27
docs/dashdemo.sh
Executable file
27
docs/dashdemo.sh
Executable file
@@ -0,0 +1,27 @@
|
||||
#!/bin/bash
|
||||
docker rm -f dashdemo 2>/dev/null
|
||||
|
||||
docker run -d \
|
||||
--name dashdemo \
|
||||
--log-opt max-size=10m \
|
||||
--log-opt max-file=3 \
|
||||
--restart always \
|
||||
--read-only \
|
||||
--tmpfs /tmp:rw,noexec,nosuid,size=512m \
|
||||
--tmpfs /run:rw,noexec,nosuid,size=16m \
|
||||
-u $(id -u):$(id -g) \
|
||||
-p 127.0.0.1:4209:4209 \
|
||||
-e HOST=0.0.0.0 \
|
||||
-e PORT=4209 \
|
||||
-e HTTPS_PORT=0 \
|
||||
-e HEALTH_MONITOR_ENABLED=false \
|
||||
-e SQLITE_PATH=/app/data/dash.db \
|
||||
-e STORAGE_DIR=/app/data/storage \
|
||||
-e BACKUP_DIR=/app/data/backups \
|
||||
-e GOOGLE_CLIENT_ID=928121624463-m9du45ek2d5f6p9cke8qpnf89ii9no20.apps.googleusercontent.com \
|
||||
-e JWT_SECRET=dfhjkswezui32476sdjkhvbn347865 \
|
||||
-e IMPLICIT_CREATE=true \
|
||||
-v "/home/ubuntu/dashdemo:/app/data:rw" \
|
||||
-v "/home/ubuntu/src/docker/dashback/dist:/app/dist:ro" \
|
||||
-v "/home/ubuntu/src/docker/dashback/dist/dashback_current:/app/dist/dashback:ro" \
|
||||
dashback:latest
|
||||
14
docs/mssql.sh
Executable file
14
docs/mssql.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
docker run -d \
|
||||
--name sql_server \
|
||||
--restart always \
|
||||
-e "ACCEPT_EULA=Y" \
|
||||
-e "MSSQL_PID=Standard" \
|
||||
-e "MSSQL_SA_PASSWORD=420Green" \
|
||||
-e "MSSQL_COLLATION=Latin1_General_CI_AS" \
|
||||
-p 127.0.0.1:1433:1433 \
|
||||
-p 192.168.122.1:1433:1433 \
|
||||
-v /home/ubuntu/mssql_data:/var/opt/mssql \
|
||||
-v /home/ubuntu/shared_backups:/shared \
|
||||
mcr.microsoft.com/mssql/server:2025-latest
|
||||
|
||||
|
||||
74
docs/update.sh
Executable file
74
docs/update.sh
Executable file
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
echo "=== 1. Pulling latest changes in all repositories ==="
|
||||
for dir in "$ROOT_DIR"/*/; do
|
||||
if [ -d "${dir}.git" ]; then
|
||||
repo_name="$(basename "$dir")"
|
||||
echo "-> git pull in ${repo_name}"
|
||||
git -C "$dir" pull
|
||||
fi
|
||||
done
|
||||
|
||||
echo "=== 2. Running npm ci in dashfront, dashdbschema, and dashback ==="
|
||||
for pkg in dashfront dashdbschema dashback; do
|
||||
echo "-> npm ci in ${pkg}"
|
||||
npm --prefix "${ROOT_DIR}/${pkg}" ci
|
||||
done
|
||||
|
||||
echo "=== 3. Building dashfront ==="
|
||||
npm --prefix "${ROOT_DIR}/dashfront" run build
|
||||
|
||||
echo "=== 4. Building SEA in dashback ==="
|
||||
npm --prefix "${ROOT_DIR}/dashback" run sea
|
||||
|
||||
DOCKER_DIST_DIR="/home/ubuntu/src/docker/dashback/dist"
|
||||
mkdir -p "$DOCKER_DIST_DIR"
|
||||
TIMESTAMP="$(date +%Y%m%d%H%M%S)"
|
||||
NEW_SEA="${DOCKER_DIST_DIR}/dashback_${TIMESTAMP}"
|
||||
CURRENT_SEA="${DOCKER_DIST_DIR}/dashback_current"
|
||||
PREV_SEA="$(readlink -f "$CURRENT_SEA" 2>/dev/null || true)"
|
||||
|
||||
echo "-> Copying SEA to ${NEW_SEA} and linking ${CURRENT_SEA}..."
|
||||
touch "${DOCKER_DIST_DIR}/dashback"
|
||||
cp "${ROOT_DIR}/dashback/dist/dashback" "$NEW_SEA"
|
||||
chmod +x "$NEW_SEA"
|
||||
ln -sfn "$NEW_SEA" "$CURRENT_SEA"
|
||||
|
||||
echo "=== 5. Running self-test on dashback_current in test container ==="
|
||||
exec 3>&1
|
||||
set +e
|
||||
SELFTEST_OUTPUT=$(docker run --rm \
|
||||
--read-only \
|
||||
--tmpfs /tmp:rw,noexec,nosuid,size=512m \
|
||||
--tmpfs /run:rw,noexec,nosuid,size=16m \
|
||||
--tmpfs /app/data:rw,noexec,nosuid,size=64m \
|
||||
-u "$(id -u):$(id -g)" \
|
||||
-v "${DOCKER_DIST_DIR}:/app/dist:ro" \
|
||||
-v "${CURRENT_SEA}:/app/dist/dashback:ro" \
|
||||
dashback:latest \
|
||||
./dist/dashback --selftest 2>&1 | tee /dev/fd/3; exit "${PIPESTATUS[0]}")
|
||||
SELFTEST_EXIT=$?
|
||||
set -e
|
||||
exec 3>&-
|
||||
|
||||
if [ "$SELFTEST_EXIT" -ne 0 ] || ! grep -q "Self-test PASSED" <<< "$SELFTEST_OUTPUT"; then
|
||||
echo "ERROR: Self-test did not confirm 'Self-test PASSED'. Aborting container restart." >&2
|
||||
if [ -n "$PREV_SEA" ] && [ -f "$PREV_SEA" ]; then
|
||||
echo "-> Restoring ${CURRENT_SEA} to ${PREV_SEA}..." >&2
|
||||
ln -sfn "$PREV_SEA" "$CURRENT_SEA"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "=== 6. Restarting dashback containers ==="
|
||||
CONTAINERS=$(docker ps -q --filter "ancestor=dashback:latest")
|
||||
if [ -n "$CONTAINERS" ]; then
|
||||
echo "-> Restarting dashback containers ($(docker ps --filter "ancestor=dashback:latest" --format '{{.Names}}' | paste -sd ', ' -))..."
|
||||
docker restart $CONTAINERS
|
||||
fi
|
||||
|
||||
echo "=== Update complete! ==="
|
||||
|
||||
1133
package-lock.json
generated
1133
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
15
package.json
15
package.json
@@ -9,11 +9,17 @@
|
||||
"scripts": {
|
||||
"start": "node src/index.js",
|
||||
"dev": "cross-env DEV_BACKEND_MONITOR=true node --watch-path=./src --watch-path=./.env --watch-path=../dashdbschema/src --watch-path=../llmorbiter/src src/index.js",
|
||||
"self-test": "node src/index.js --self-test",
|
||||
"manage-users": "node scripts/manageUsers.js",
|
||||
"wipe-company": "node scripts/wipeCompany.js",
|
||||
"downgrade": "node scripts/downgradeSchema.js",
|
||||
"docs:api": "node scripts/generateApiDocs.js",
|
||||
"api-graph": "node generate-api-graph.js",
|
||||
"review:functions": "node scripts/extractFunctions.js",
|
||||
"build:sea": "node scripts/buildSea.js",
|
||||
"sea": "npm run build:sea",
|
||||
"docker:build": "docker build -t dashback:latest -t dashback:1.0.0 .",
|
||||
"docker": "npm run docker:build",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -37,12 +43,12 @@
|
||||
"pdfconvert-wasm": "^0.3.0",
|
||||
"pdfkit": "^0.20.2",
|
||||
"react": "^19.3.1",
|
||||
"react-canvas-label-editor": "github:sebseb7/react-canvas-label-editor",
|
||||
"react-canvas-label-editor": "github:sebseb7/react-canvas-label-editor#v20.0.0",
|
||||
"selfsigned": "^5.5.0",
|
||||
"sharp": "^0.35.5",
|
||||
"skelehash-wasm": "^0.1.0",
|
||||
"skelehash-wasm": "^0.1.1",
|
||||
"swagger-ui-dist": "^5.33.3",
|
||||
"vm2": "^3.12.2",
|
||||
"wasm-image-optimization": "^2.0.13",
|
||||
"zod": "^4.6.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -51,8 +57,7 @@
|
||||
"swagger-jsdoc": "^6.3.0"
|
||||
},
|
||||
"allowScripts": {
|
||||
"github:sebseb7/react-canvas-label-editor#7f0e31b66ff22da011e872b201017398b14e9dd9": true,
|
||||
"canvas@3.2.3": true,
|
||||
"react-canvas-label-editor@20.0.0": true,
|
||||
"better-sqlite3@13.0.3": true
|
||||
},
|
||||
"overrides": {
|
||||
|
||||
BIN
scratch/curl-pimage.jpg
Normal file
BIN
scratch/curl-pimage.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.1 KiB |
172
scripts/buildSea.js
Normal file
172
scripts/buildSea.js
Normal file
@@ -0,0 +1,172 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import zlib from 'node:zlib';
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const rootDir = path.resolve(__dirname, '..');
|
||||
const distDir = path.join(rootDir, 'dist');
|
||||
const srcDir = path.join(rootDir, 'src');
|
||||
const configPath = path.join(rootDir, 'sea-config.json');
|
||||
const payloadPath = path.join(distDir, 'app-payload.bin');
|
||||
|
||||
const dbschemaDir = path.resolve(rootDir, '../dashdbschema');
|
||||
const llmorbiterDir = path.resolve(rootDir, '../llmorbiter');
|
||||
|
||||
if (!fs.existsSync(distDir)) {
|
||||
fs.mkdirSync(distDir, { recursive: true });
|
||||
}
|
||||
|
||||
console.log('Packaging application, siblings, and JavaScript dependencies into SEA payload (excluding native binaries)...');
|
||||
|
||||
const nativeNodes = {};
|
||||
|
||||
function findNearestPackageJson(startDir) {
|
||||
let dir = startDir;
|
||||
while (dir && dir !== path.dirname(dir)) {
|
||||
const pkgFile = path.join(dir, 'package.json');
|
||||
if (fs.existsSync(pkgFile)) {
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(pkgFile, 'utf8'));
|
||||
} catch {}
|
||||
}
|
||||
dir = path.dirname(dir);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getVersionedNodeFilename(fullPath) {
|
||||
const base = path.basename(fullPath, '.node');
|
||||
const pkg = findNearestPackageJson(path.dirname(fullPath));
|
||||
if (!pkg || !pkg.name || !pkg.version) {
|
||||
return `${base}.node`;
|
||||
}
|
||||
const shortName = pkg.name.replace(/^@[^/]+\//, '');
|
||||
if (base.includes(pkg.version)) {
|
||||
return `${base}.node`;
|
||||
}
|
||||
if (base === shortName) {
|
||||
return `${shortName}-${process.platform}-${process.arch}-${pkg.version}.node`;
|
||||
}
|
||||
return `${shortName}-${base}-${pkg.version}.node`;
|
||||
}
|
||||
|
||||
function isNativeBinary(name) {
|
||||
return (
|
||||
name.endsWith('.node') ||
|
||||
name.endsWith('.so') ||
|
||||
name.includes('.so.') ||
|
||||
name.endsWith('.dylib') ||
|
||||
name.endsWith('.dll') ||
|
||||
name.endsWith('.a') ||
|
||||
name.endsWith('.o') ||
|
||||
name.endsWith('.cc') ||
|
||||
name.endsWith('.cpp') ||
|
||||
name.endsWith('.c') ||
|
||||
name.endsWith('.h')
|
||||
);
|
||||
}
|
||||
|
||||
function packDirectory(dir, prefix, result) {
|
||||
if (!fs.existsSync(dir)) return;
|
||||
try {
|
||||
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
||||
const full = path.join(dir, entry.name);
|
||||
const rel = path.join(prefix, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
if (entry.name === 'test' || entry.name === 'tests' || entry.name === 'docs' || entry.name === '.github' || entry.name === '.git' || entry.name === 'obj.target') continue;
|
||||
packDirectory(full, rel, result);
|
||||
} else if (entry.isFile()) {
|
||||
if (entry.name.endsWith('.node')) {
|
||||
nativeNodes[rel] = getVersionedNodeFilename(full);
|
||||
continue;
|
||||
}
|
||||
if (isNativeBinary(entry.name)) continue;
|
||||
result[rel] = fs.readFileSync(full).toString('base64');
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
|
||||
const payload = {};
|
||||
|
||||
// 1. Pack dashback src and package.json
|
||||
packDirectory(srcDir, 'src', payload);
|
||||
const pkgPath = path.join(rootDir, 'package.json');
|
||||
if (fs.existsSync(pkgPath)) {
|
||||
payload['package.json'] = fs.readFileSync(pkgPath).toString('base64');
|
||||
}
|
||||
|
||||
// 2. Pack sibling dependencies (libdashstore and libllmorbiter) directly into node_modules
|
||||
if (fs.existsSync(path.join(dbschemaDir, 'src'))) {
|
||||
packDirectory(path.join(dbschemaDir, 'src'), 'node_modules/libdashstore/src', payload);
|
||||
const dbschemaPkg = path.join(dbschemaDir, 'package.json');
|
||||
if (fs.existsSync(dbschemaPkg)) {
|
||||
payload['node_modules/libdashstore/package.json'] = fs.readFileSync(dbschemaPkg).toString('base64');
|
||||
}
|
||||
}
|
||||
|
||||
if (fs.existsSync(path.join(llmorbiterDir, 'src'))) {
|
||||
packDirectory(path.join(llmorbiterDir, 'src'), 'node_modules/libllmorbiter/src', payload);
|
||||
const llmorbiterPkg = path.join(llmorbiterDir, 'package.json');
|
||||
if (fs.existsSync(llmorbiterPkg)) {
|
||||
payload['node_modules/libllmorbiter/package.json'] = fs.readFileSync(llmorbiterPkg).toString('base64');
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Pack all node_modules dependencies
|
||||
function packNodeModules(nmPath) {
|
||||
if (!fs.existsSync(nmPath)) return;
|
||||
for (const name of fs.readdirSync(nmPath)) {
|
||||
if (name.startsWith('.') || name === 'libdashstore' || name === 'libllmorbiter') continue;
|
||||
const pkgDir = path.join(nmPath, name);
|
||||
if (name.startsWith('@')) {
|
||||
for (const sub of fs.readdirSync(pkgDir)) {
|
||||
packDirectory(path.join(pkgDir, sub), `node_modules/${name}/${sub}`, payload);
|
||||
}
|
||||
} else {
|
||||
packDirectory(pkgDir, `node_modules/${name}`, payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
packNodeModules(path.join(rootDir, 'node_modules'));
|
||||
packNodeModules(path.join(dbschemaDir, 'node_modules'));
|
||||
|
||||
payload['.native-nodes.json'] = Buffer.from(JSON.stringify(nativeNodes)).toString('base64');
|
||||
|
||||
const compressedPayload = zlib.deflateSync(Buffer.from(JSON.stringify(payload)));
|
||||
fs.writeFileSync(payloadPath, compressedPayload);
|
||||
|
||||
console.log(`Packed ${Object.keys(payload).length} files (${(compressedPayload.length / 1024 / 1024).toFixed(2)} MB compressed)`);
|
||||
|
||||
// Prepare sea-config.json
|
||||
const config = {
|
||||
main: 'src/sea-entry.cjs',
|
||||
output: 'dist/dashback',
|
||||
assets: {
|
||||
'app-payload.bin': 'dist/app-payload.bin',
|
||||
},
|
||||
disableExperimentalSEAWarning: true,
|
||||
};
|
||||
|
||||
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
|
||||
|
||||
console.log('Generating Single Executable Application (SEA)...');
|
||||
try {
|
||||
execFileSync(process.execPath, ['--build-sea', 'sea-config.json'], {
|
||||
cwd: rootDir,
|
||||
stdio: 'inherit',
|
||||
});
|
||||
|
||||
const outputPath = path.join(distDir, 'dashback');
|
||||
if (process.platform !== 'win32' && fs.existsSync(outputPath)) {
|
||||
fs.chmodSync(outputPath, 0o755);
|
||||
}
|
||||
|
||||
console.log(`\nSuccessfully built standalone SEA: ${path.relative(rootDir, outputPath)}`);
|
||||
} catch (err) {
|
||||
console.error('\nFailed to build SEA:', err.message);
|
||||
process.exit(1);
|
||||
}
|
||||
30
scripts/downgradeSchema.js
Normal file
30
scripts/downgradeSchema.js
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Downgrades the configured database (from `.env`) to a target schema version.
|
||||
*
|
||||
* npm run downgrade -- <targetVersion>
|
||||
*
|
||||
* Uses libdashstore's `src/providers/<provider>/downgrade/<from>_to_<to>.js`.
|
||||
* Stop the API first; starting it again upgrades back to the latest version.
|
||||
*/
|
||||
import { createProvider } from '../src/db/provider.js';
|
||||
import env from '../src/config/env.js';
|
||||
|
||||
const [rawTarget] = process.argv.slice(2);
|
||||
const target = Number(rawTarget);
|
||||
if (!rawTarget || !Number.isInteger(target) || target < 1) {
|
||||
console.error('Usage: npm run downgrade -- <targetVersion>');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const provider = createProvider();
|
||||
try {
|
||||
const before = await provider.getSchemaVersion();
|
||||
const steps = await provider.downgradeSchema(target);
|
||||
console.log(`Schema ${env.dbProvider}: ${before} -> ${target} (${steps} step(s))`);
|
||||
} catch (err) {
|
||||
console.error(`Downgrade failed: ${err.message}`);
|
||||
process.exitCode = 1;
|
||||
} finally {
|
||||
await provider.close();
|
||||
}
|
||||
|
||||
@@ -39,10 +39,16 @@ const OMITTED_ROUTES = new Set([
|
||||
'POST /serper/image',
|
||||
'POST /serper/images',
|
||||
'GET /shipment/{id}/file/{fileId}',
|
||||
'GET /smallthumb/{fullHash}',
|
||||
'GET /thumb/{fullHash}',
|
||||
'GET /v1/category',
|
||||
'GET /v1/cimage',
|
||||
'GET /v1/client',
|
||||
'GET /v1/customer',
|
||||
'GET /v1/customergroup',
|
||||
'GET /v1/deletedentity',
|
||||
'GET /v1/init',
|
||||
'POST /v1/order',
|
||||
'GET /v1/pimage',
|
||||
'GET /v1/product',
|
||||
]);
|
||||
@@ -78,6 +84,36 @@ function isRouteOmitted(method, apiPath) {
|
||||
if (apiPath === '/auth' || apiPath.startsWith('/auth/')) {
|
||||
return true;
|
||||
}
|
||||
if (apiPath === '/agent' || apiPath.startsWith('/agent/')) {
|
||||
return true;
|
||||
}
|
||||
if (apiPath === '/agentprinter' || apiPath.startsWith('/agentprinter/')) {
|
||||
return true;
|
||||
}
|
||||
if (apiPath === '/printer' || apiPath.startsWith('/printer/')) {
|
||||
return true;
|
||||
}
|
||||
if (apiPath === '/printeragent' || apiPath.startsWith('/printeragent/')) {
|
||||
return true;
|
||||
}
|
||||
if (apiPath === '/printerjob' || apiPath.startsWith('/printerjob/')) {
|
||||
return true;
|
||||
}
|
||||
if (apiPath === '/smallthumb' || apiPath.startsWith('/smallthumb/')) {
|
||||
return true;
|
||||
}
|
||||
if (apiPath === '/v1' || apiPath.startsWith('/v1/')) {
|
||||
return true;
|
||||
}
|
||||
if (apiPath === '/health' || apiPath.startsWith('/health/')) {
|
||||
return true;
|
||||
}
|
||||
if (apiPath === '/subagentschedule' || apiPath.startsWith('/subagentschedule/')) {
|
||||
return true;
|
||||
}
|
||||
if (apiPath === '/zpljob' || apiPath.startsWith('/zpljob/')) {
|
||||
return true;
|
||||
}
|
||||
return OMITTED_ROUTES.has(`${method.toUpperCase()} ${apiPath}`);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
-- Rename article "father" columns to "parent" (SQL Server / MSSQL).
|
||||
--
|
||||
-- One-off manual migration (no migration code is kept in the repo).
|
||||
-- sqlcmd -S <server> -d <db> -E -i scripts/migrate-parent-rename.mssql.sql
|
||||
--
|
||||
-- Guarded and safe to re-run. Safe to retry after a partial run.
|
||||
--
|
||||
-- NOTE ON BATCHING: sp_rename is deferred and its effect is not visible to
|
||||
-- subsequent statements in the SAME batch. Each rename therefore runs in its
|
||||
-- own batch (GO), and constraint/index recreation happens after a GO so the
|
||||
-- new column names resolve.
|
||||
|
||||
SET XACT_ABORT ON;
|
||||
GO
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
GO
|
||||
|
||||
-- Drop the old filtered unique index (references fathersort).
|
||||
IF EXISTS (SELECT 1 FROM sys.indexes WHERE name = 'UQ_article_fatherarticle_fathersort')
|
||||
DROP INDEX UQ_article_fatherarticle_fathersort ON article;
|
||||
GO
|
||||
|
||||
-- Drop the default constraints bound to the old column names.
|
||||
IF EXISTS (SELECT 1 FROM sys.default_constraints WHERE name = 'DF_article_is_father')
|
||||
ALTER TABLE article DROP CONSTRAINT DF_article_is_father;
|
||||
IF EXISTS (SELECT 1 FROM sys.default_constraints WHERE name = 'DF_article_fathersort')
|
||||
ALTER TABLE article DROP CONSTRAINT DF_article_fathersort;
|
||||
GO
|
||||
|
||||
-- Drop foreign keys bound to the old columns.
|
||||
IF EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = 'FK_article_fatherarticle')
|
||||
ALTER TABLE article DROP CONSTRAINT FK_article_fatherarticle;
|
||||
IF EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = 'FK_article_fatherattributename')
|
||||
ALTER TABLE article DROP CONSTRAINT FK_article_fatherattributename;
|
||||
GO
|
||||
|
||||
-- Rename the columns (each sp_rename must be its own batch).
|
||||
IF COL_LENGTH('article', 'fatherarticle_id') IS NOT NULL
|
||||
AND COL_LENGTH('article', 'parentarticle_id') IS NULL
|
||||
EXEC sp_rename 'article.fatherarticle_id', 'parentarticle_id', 'COLUMN';
|
||||
GO
|
||||
|
||||
IF COL_LENGTH('article', 'fatherattributename_id') IS NOT NULL
|
||||
AND COL_LENGTH('article', 'parentattributename_id') IS NULL
|
||||
EXEC sp_rename 'article.fatherattributename_id', 'parentattributename_id', 'COLUMN';
|
||||
GO
|
||||
|
||||
IF COL_LENGTH('article', 'fathersort') IS NOT NULL
|
||||
AND COL_LENGTH('article', 'parentsort') IS NULL
|
||||
EXEC sp_rename 'article.fathersort', 'parentsort', 'COLUMN';
|
||||
GO
|
||||
|
||||
IF COL_LENGTH('article', 'is_father') IS NOT NULL
|
||||
AND COL_LENGTH('article', 'is_parent') IS NULL
|
||||
EXEC sp_rename 'article.is_father', 'is_parent', 'COLUMN';
|
||||
GO
|
||||
|
||||
COMMIT TRANSACTION;
|
||||
GO
|
||||
|
||||
-- Recreate the constraints under their new names (after the rename batches).
|
||||
IF NOT EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = 'FK_article_parentarticle')
|
||||
ALTER TABLE article ADD CONSTRAINT FK_article_parentarticle
|
||||
FOREIGN KEY (parentarticle_id) REFERENCES article(id) ON DELETE NO ACTION;
|
||||
GO
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = 'FK_article_parentattributename')
|
||||
ALTER TABLE article ADD CONSTRAINT FK_article_parentattributename
|
||||
FOREIGN KEY (parentattributename_id) REFERENCES attributename(id) ON DELETE NO ACTION;
|
||||
GO
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM sys.default_constraints WHERE name = 'DF_article_is_parent')
|
||||
ALTER TABLE article ADD CONSTRAINT DF_article_is_parent DEFAULT (0) FOR is_parent;
|
||||
GO
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM sys.default_constraints WHERE name = 'DF_article_parentsort')
|
||||
ALTER TABLE article ADD CONSTRAINT DF_article_parentsort DEFAULT (0) FOR parentsort;
|
||||
GO
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = 'UQ_article_parentarticle_parentsort')
|
||||
CREATE UNIQUE INDEX UQ_article_parentarticle_parentsort
|
||||
ON article (parentarticle_id, parentsort)
|
||||
WHERE parentarticle_id IS NOT NULL;
|
||||
GO
|
||||
|
||||
-- Verify
|
||||
SELECT 'COL:' + c.name AS result
|
||||
FROM sys.columns c
|
||||
WHERE c.object_id = OBJECT_ID('article')
|
||||
AND (c.name LIKE '%father%' OR c.name LIKE '%parent%');
|
||||
GO
|
||||
@@ -1,14 +0,0 @@
|
||||
-- Rename article "father" columns to "parent".
|
||||
--
|
||||
-- One-off manual migration (no migration code is kept in the repo).
|
||||
-- sqlite3 data/dash.db < scripts/migrate-parent-rename.sqlite.sql
|
||||
--
|
||||
-- Safe to re-run: every step is guarded by a column-existence check.
|
||||
|
||||
ALTER TABLE article RENAME COLUMN fatherarticle_id TO parentarticle_id;
|
||||
ALTER TABLE article RENAME COLUMN fatherattributename_id TO parentattributename_id;
|
||||
ALTER TABLE article RENAME COLUMN fathersort TO parentsort;
|
||||
ALTER TABLE article RENAME COLUMN is_father TO is_parent;
|
||||
|
||||
-- Verify
|
||||
PRAGMA table_info(article);
|
||||
@@ -1,73 +1,46 @@
|
||||
#!/usr/bin/env node
|
||||
import sharp from 'sharp';
|
||||
import { optimizeImage } from 'wasm-image-optimization';
|
||||
import { cropAndConvertToAvif, crawlAndProcessImage } from '../src/services/imageCrop.js';
|
||||
|
||||
async function run() {
|
||||
console.log('--- 1. Testing synthetic images ---');
|
||||
|
||||
// Synthetic test 1: White border
|
||||
const whiteImg = await sharp({
|
||||
create: { width: 300, height: 300, channels: 4, background: { r: 255, g: 255, b: 255, alpha: 1 } },
|
||||
})
|
||||
.composite([
|
||||
{
|
||||
input: Buffer.from('<svg width="100" height="100"><rect width="100" height="100" fill="purple"/></svg>'),
|
||||
top: 100,
|
||||
left: 100,
|
||||
},
|
||||
])
|
||||
.png()
|
||||
.toBuffer();
|
||||
const whiteSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="300" height="300">
|
||||
<rect width="300" height="300" fill="#ffffff"/>
|
||||
<rect x="100" y="100" width="100" height="100" fill="purple"/>
|
||||
</svg>`;
|
||||
const whiteImg = Buffer.from((await optimizeImage({ image: whiteSvg, format: 'png' })).data);
|
||||
|
||||
const res1 = await cropAndConvertToAvif(whiteImg);
|
||||
console.log(`White border: 300x300 -> ${res1.width}x${res1.height}, ${res1.size} bytes`);
|
||||
if (res1.width !== 100 || res1.height !== 100) {
|
||||
throw new Error(`Expected 100x100, got ${res1.width}x${res1.height}`);
|
||||
if (res1.width !== 110 || res1.height !== 110) {
|
||||
throw new Error(`Expected 110x110, got ${res1.width}x${res1.height}`);
|
||||
}
|
||||
|
||||
// Synthetic test 2: Transparent border
|
||||
const transImg = await sharp({
|
||||
create: { width: 300, height: 300, channels: 4, background: { r: 0, g: 0, b: 0, alpha: 0 } },
|
||||
})
|
||||
.composite([
|
||||
{
|
||||
input: Buffer.from('<svg width="120" height="80"><rect width="120" height="80" fill="green"/></svg>'),
|
||||
top: 110,
|
||||
left: 90,
|
||||
},
|
||||
])
|
||||
.png()
|
||||
.toBuffer();
|
||||
const transSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="300" height="300">
|
||||
<rect x="90" y="110" width="120" height="80" fill="green"/>
|
||||
</svg>`;
|
||||
const transImg = Buffer.from((await optimizeImage({ image: transSvg, format: 'png' })).data);
|
||||
|
||||
const res2 = await cropAndConvertToAvif(transImg);
|
||||
console.log(`Transparent border: 300x300 -> ${res2.width}x${res2.height}, ${res2.size} bytes`);
|
||||
if (res2.width !== 120 || res2.height !== 80) {
|
||||
throw new Error(`Expected 120x80, got ${res2.width}x${res2.height}`);
|
||||
if (res2.width !== 130 || res2.height !== 90) {
|
||||
throw new Error(`Expected 130x90, got ${res2.width}x${res2.height}`);
|
||||
}
|
||||
|
||||
// Synthetic test 3: Outer transparent, inner white border
|
||||
const mixedImg = await sharp({
|
||||
create: { width: 400, height: 400, channels: 4, background: { r: 0, g: 0, b: 0, alpha: 0 } },
|
||||
})
|
||||
.composite([
|
||||
{
|
||||
input: Buffer.from('<svg width="200" height="200"><rect width="200" height="200" fill="white"/></svg>'),
|
||||
top: 100,
|
||||
left: 100,
|
||||
},
|
||||
{
|
||||
input: Buffer.from('<svg width="100" height="60"><rect width="100" height="60" fill="blue"/></svg>'),
|
||||
top: 170,
|
||||
left: 150,
|
||||
},
|
||||
])
|
||||
.png()
|
||||
.toBuffer();
|
||||
const mixedSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="400" height="400">
|
||||
<rect x="100" y="100" width="200" height="200" fill="white"/>
|
||||
<rect x="150" y="170" width="100" height="60" fill="blue"/>
|
||||
</svg>`;
|
||||
const mixedImg = Buffer.from((await optimizeImage({ image: mixedSvg, format: 'png' })).data);
|
||||
|
||||
const res3 = await cropAndConvertToAvif(mixedImg);
|
||||
console.log(`Mixed border: 400x400 -> ${res3.width}x${res3.height}, ${res3.size} bytes`);
|
||||
if (res3.width !== 100 || res3.height !== 60) {
|
||||
throw new Error(`Expected 100x60, got ${res3.width}x${res3.height}`);
|
||||
if (res3.width !== 110 || res3.height !== 70) {
|
||||
throw new Error(`Expected 110x70, got ${res3.width}x${res3.height}`);
|
||||
}
|
||||
|
||||
console.log('\nAll synthetic tests PASSED!');
|
||||
|
||||
@@ -144,7 +144,6 @@ async function wipeCompany(companyIdentifier, autoConfirm = false) {
|
||||
await tx.query('DELETE FROM companysetting WHERE company_id = @companyId', { companyId });
|
||||
await tx.query('DELETE FROM companyhistory WHERE company_id = @companyId', { companyId });
|
||||
await tx.query('DELETE FROM numbers WHERE company_id = @companyId', { companyId });
|
||||
await tx.query('DELETE FROM articletombstone WHERE company_id = @companyId', { companyId });
|
||||
await tx.query('DELETE FROM modelvfs WHERE company_id = @companyId', { companyId });
|
||||
await tx.query(`DELETE FROM modelconversation WHERE companyuser_id IN (SELECT id FROM companyuser WHERE company_id = @companyId)`, { companyId });
|
||||
|
||||
|
||||
8
sea-config.json
Normal file
8
sea-config.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"main": "src/sea-entry.cjs",
|
||||
"output": "dist/dashback",
|
||||
"assets": {
|
||||
"app-payload.bin": "dist/app-payload.bin"
|
||||
},
|
||||
"disableExperimentalSEAWarning": true
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user