Compare commits
179 Commits
6c821d381e
...
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 | ||
|
|
ee0eb2820e | ||
|
|
e4e4d2dcf0 | ||
|
|
63f4c3a0e4 | ||
|
|
b7058df5d2 | ||
|
|
5a5981dc07 | ||
|
|
fde381937c | ||
|
|
de3e74c928 | ||
|
|
a04094a7be | ||
|
|
3f540de768 | ||
|
|
3450552f7c | ||
|
|
6fbdeaa070 | ||
|
|
1bf99deeb9 | ||
|
|
e14a8ee8f0 | ||
|
|
c958ecf604 | ||
|
|
f571328e0c | ||
|
|
a717a05e8d | ||
|
|
c06a5e3413 | ||
|
|
5e4cb5a3f8 | ||
|
|
0ec993a0b6 | ||
|
|
69a9781cb6 | ||
|
|
7445a573ab | ||
|
|
9c50d9efc3 | ||
|
|
36d62138d4 | ||
|
|
0463003681 | ||
|
|
d0a2ede749 | ||
|
|
badce6819c | ||
|
|
832cfaca41 | ||
|
|
a01b42b24b | ||
|
|
04943fb7a6 | ||
|
|
e085e064ee | ||
|
|
df846f4f06 | ||
|
|
4bd977ed12 | ||
|
|
1778815a1e | ||
|
|
856692b66c | ||
|
|
5e9b168e0d | ||
|
|
bee21d2c20 | ||
|
|
7197a6ddb7 | ||
|
|
988b4848cf | ||
|
|
c61df92d63 | ||
|
|
fd21cb7319 | ||
|
|
da1254b0b1 | ||
|
|
8e841d2c23 | ||
|
|
0fe672a054 | ||
|
|
d7f7d669f9 | ||
|
|
188cd71f63 | ||
|
|
de6c4987b9 | ||
|
|
d05ba9276f | ||
|
|
75925ab35c | ||
|
|
52f49fb651 | ||
|
|
2f0c4aced1 | ||
|
|
99ac40e6fa | ||
|
|
7f28a05ed3 | ||
|
|
3b875c9f9a | ||
|
|
f506dd35be | ||
|
|
5ed634990e | ||
|
|
bed19f8b10 | ||
|
|
e083d66a75 | ||
|
|
a560a78f4d | ||
|
|
144bf0ca43 | ||
|
|
50f41bca8c | ||
|
|
2165afcc02 | ||
|
|
084b1b285e | ||
|
|
9a4e2e30df | ||
|
|
0039b80d31 | ||
|
|
78ad8f12e4 | ||
|
|
29a07d132c | ||
|
|
8af63d6bf8 | ||
|
|
508e1b6d7a | ||
|
|
e462a3d250 | ||
|
|
529b142341 | ||
|
|
f331625d63 | ||
|
|
8c55f899b5 | ||
|
|
bdd7ebf5b8 | ||
|
|
507dffa567 | ||
|
|
0ea7da4f3a | ||
|
|
d880273629 | ||
|
|
9c54a8a1d3 | ||
|
|
04e10cffdb | ||
|
|
90b782e500 | ||
|
|
37c58648db | ||
|
|
5fb8df6f6a | ||
|
|
80450e8748 | ||
|
|
e230c4cf12 |
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
|
||||
|
||||
16
.env.example
16
.env.example
@@ -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)
|
||||
@@ -51,4 +54,17 @@ OPENROUTER_PAID_MODEL=openai/gpt-6-luna:floor
|
||||
# BACKUP_HOURLY_RETENTION=50
|
||||
# BACKUP_DAILY_RETENTION=50
|
||||
|
||||
# Redis (Healthcheck Latency Metric)
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PORT=6379
|
||||
REDIS_PASSWORD=
|
||||
REDIS_DB=0
|
||||
REDIS_KEY=healthcheck:latency_ms
|
||||
# REDIS_URL=redis://127.0.0.1:6379
|
||||
|
||||
# Health Monitor Service
|
||||
# HEALTH_MONITOR_ENABLED=true
|
||||
# HEALTH_MONITOR_INTERVAL_MS=60000
|
||||
|
||||
|
||||
|
||||
|
||||
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"]
|
||||
@@ -240,7 +240,7 @@ export function createBashTool(googleAuthId) {
|
||||
|
||||
| Consideration | Ephemeral (`docker run --rm`) | Persistent Container (`docker exec`) |
|
||||
| :--- | :--- | :--- |
|
||||
| **Startup Overhead** | ~200–400ms per command | ~20–50ms per command |
|
||||
| **Startup Overhead** | ~200-400ms per command | ~20-50ms per command |
|
||||
| **State Cleanliness** | Completely fresh OS environment every call | Processes/background jobs remain running |
|
||||
| **Lifecycle Complexity** | None. Docker handles lifecycle and cleanup | Requires container pool management and reaper |
|
||||
| **Failure Recovery** | Automatic | If container crashes, must be recreated |
|
||||
|
||||
File diff suppressed because one or more lines are too long
3930
api-graph.svg
3930
api-graph.svg
File diff suppressed because it is too large
Load Diff
|
Before Width: | Height: | Size: 289 KiB After Width: | Height: | Size: 330 KiB |
@@ -37,8 +37,18 @@ 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` |
|
||||
| [`routes/article/delete.md`](routes/article/delete.md) | `DELETE /article/{sku}` |
|
||||
| [`routes/article/get.md`](routes/article/get.md) | `GET /article/{sku}` |
|
||||
| [`routes/article/update.md`](routes/article/update.md) | `PATCH /article/{sku}` |
|
||||
@@ -88,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` |
|
||||
@@ -97,6 +110,12 @@ Generated from `@openapi` annotations in [`src/api/routes/`](../../src/api/route
|
||||
| [`routes/brand/update.md`](routes/brand/update.md) | `PATCH /brand/{id}` |
|
||||
| [`routes/brand/_id/image.delete.md`](routes/brand/_id/image.delete.md) | `DELETE /brand/{id}/image` |
|
||||
| [`routes/brand/_id/image.post.md`](routes/brand/_id/image.post.md) | `POST /brand/{id}/image` |
|
||||
| [`routes/carrier.get.md`](routes/carrier.get.md) | `GET /carrier` |
|
||||
| [`routes/carrier.post.md`](routes/carrier.post.md) | `POST /carrier` |
|
||||
| [`routes/carrier/order.md`](routes/carrier/order.md) | `PUT /carrier/order` |
|
||||
| [`routes/carrier/_id.delete.md`](routes/carrier/_id.delete.md) | `DELETE /carrier/{id}` |
|
||||
| [`routes/carrier/_id.get.md`](routes/carrier/_id.get.md) | `GET /carrier/{id}` |
|
||||
| [`routes/carrier/_id.patch.md`](routes/carrier/_id.patch.md) | `PATCH /carrier/{id}` |
|
||||
| [`routes/category/create.md`](routes/category/create.md) | `POST /category` |
|
||||
| [`routes/category/export.zip.md`](routes/category/export.zip.md) | `GET /category/export.zip` |
|
||||
| [`routes/category/order.md`](routes/category/order.md) | `PUT /category/order` |
|
||||
@@ -108,11 +127,14 @@ 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}` |
|
||||
| [`routes/company/list.md`](routes/company/list.md) | `GET /company` |
|
||||
| [`routes/company/create.md`](routes/company/create.md) | `POST /company` |
|
||||
| [`routes/company/export.md`](routes/company/export.md) | `GET /company/export` |
|
||||
| [`routes/company/export.post.md`](routes/company/export.post.md) | `POST /company/export` |
|
||||
| [`routes/company/history.md`](routes/company/history.md) | `GET /company/history` |
|
||||
| [`routes/company/addHistory.md`](routes/company/addHistory.md) | `POST /company/history` |
|
||||
| [`routes/company/import.md`](routes/company/import.md) | `POST /company/import` |
|
||||
@@ -121,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` |
|
||||
@@ -128,11 +154,12 @@ Generated from `@openapi` annotations in [`src/api/routes/`](../../src/api/route
|
||||
| [`routes/customergroup/update.md`](routes/customergroup/update.md) | `PATCH /customergroup/{id}` |
|
||||
| [`routes/delivery/list.md`](routes/delivery/list.md) | `GET /delivery` |
|
||||
| [`routes/delivery/create.md`](routes/delivery/create.md) | `POST /delivery` |
|
||||
| [`routes/delivery/parse.md`](routes/delivery/parse.md) | `POST /delivery/parse` |
|
||||
| [`routes/delivery/delete.md`](routes/delivery/delete.md) | `DELETE /delivery/{id}` |
|
||||
| [`routes/delivery/get.md`](routes/delivery/get.md) | `GET /delivery/{id}` |
|
||||
| [`routes/delivery/update.md`](routes/delivery/update.md) | `PATCH /delivery/{id}` |
|
||||
| [`routes/delivery/_id/file/_fileId.delete.md`](routes/delivery/_id/file/_fileId.delete.md) | `DELETE /delivery/{id}/file/{fileId}` |
|
||||
| [`routes/delivery/file.md`](routes/delivery/file.md) | `GET /delivery/{id}/file/{fileId}` |
|
||||
| [`routes/delivery/_id/pdf.md`](routes/delivery/_id/pdf.md) | `POST /delivery/{id}/pdf` |
|
||||
| [`routes/entity/list.md`](routes/entity/list.md) | `GET /entity` |
|
||||
| [`routes/entity/create.md`](routes/entity/create.md) | `POST /entity` |
|
||||
| [`routes/entity/next-number.md`](routes/entity/next-number.md) | `GET /entity/next-number` |
|
||||
@@ -149,15 +176,17 @@ Generated from `@openapi` annotations in [`src/api/routes/`](../../src/api/route
|
||||
| [`routes/entity/update.md`](routes/entity/update.md) | `PATCH /entity/{id}` |
|
||||
| [`routes/events.md`](routes/events.md) | `GET /events` |
|
||||
| [`routes/health.md`](routes/health.md) | `GET /health` |
|
||||
| [`routes/health/latency.md`](routes/health/latency.md) | `GET /health/latency` |
|
||||
| [`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}` |
|
||||
| [`routes/labeltemplate/update.md`](routes/labeltemplate/update.md) | `PUT /labeltemplate/{id}` |
|
||||
| [`routes/ledger.get.md`](routes/ledger.get.md) | `GET /ledger` |
|
||||
| [`routes/ledger.post.md`](routes/ledger.post.md) | `POST /ledger` |
|
||||
| [`routes/ledger.md`](routes/ledger.md) | `GET /ledger` |
|
||||
| [`routes/ledger/history.md`](routes/ledger/history.md) | `GET /ledger/history` |
|
||||
| [`routes/ledger/manifestarticle/_manifestarticleId.md`](routes/ledger/manifestarticle/_manifestarticleId.md) | `GET /ledger/manifestarticle/{manifestarticleId}` |
|
||||
| [`routes/ledger/sku/_sku.md`](routes/ledger/sku/_sku.md) | `GET /ledger/sku/{sku}` |
|
||||
| [`routes/mcp.md`](routes/mcp.md) | `POST /mcp` |
|
||||
@@ -185,8 +214,11 @@ Generated from `@openapi` annotations in [`src/api/routes/`](../../src/api/route
|
||||
| [`routes/order/delete.md`](routes/order/delete.md) | `DELETE /order/{id}` |
|
||||
| [`routes/order/get.md`](routes/order/get.md) | `GET /order/{id}` |
|
||||
| [`routes/order/update.md`](routes/order/update.md) | `PATCH /order/{id}` |
|
||||
| [`routes/order/_id/file/_fileId.delete.md`](routes/order/_id/file/_fileId.delete.md) | `DELETE /order/{id}/file/{fileId}` |
|
||||
| [`routes/order/_id/file/_fileId.get.md`](routes/order/_id/file/_fileId.get.md) | `GET /order/{id}/file/{fileId}` |
|
||||
| [`routes/order/_id/payment.get.md`](routes/order/_id/payment.get.md) | `GET /order/{id}/payment` |
|
||||
| [`routes/order/_id/payment.post.md`](routes/order/_id/payment.post.md) | `POST /order/{id}/payment` |
|
||||
| [`routes/order/_id/pdf.md`](routes/order/_id/pdf.md) | `POST /order/{id}/pdf` |
|
||||
| [`routes/order/_id/shipment.get.md`](routes/order/_id/shipment.get.md) | `GET /order/{id}/shipment` |
|
||||
| [`routes/order/_id/shipment.post.md`](routes/order/_id/shipment.post.md) | `POST /order/{id}/shipment` |
|
||||
| [`routes/order/_id/shipping.get.md`](routes/order/_id/shipping.get.md) | `GET /order/{id}/shipping` |
|
||||
@@ -204,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` |
|
||||
@@ -222,10 +266,33 @@ Generated from `@openapi` annotations in [`src/api/routes/`](../../src/api/route
|
||||
| [`routes/quote/delete.md`](routes/quote/delete.md) | `DELETE /quote/{id}` |
|
||||
| [`routes/quote/get.md`](routes/quote/get.md) | `GET /quote/{id}` |
|
||||
| [`routes/quote/update.md`](routes/quote/update.md) | `PATCH /quote/{id}` |
|
||||
| [`routes/quote/_id/file/_fileId.delete.md`](routes/quote/_id/file/_fileId.delete.md) | `DELETE /quote/{id}/file/{fileId}` |
|
||||
| [`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` |
|
||||
| [`routes/shipment/_id.delete.md`](routes/shipment/_id.delete.md) | `DELETE /shipment/{id}` |
|
||||
| [`routes/shipment/_id.get.md`](routes/shipment/_id.get.md) | `GET /shipment/{id}` |
|
||||
| [`routes/shipment/_id.patch.md`](routes/shipment/_id.patch.md) | `PATCH /shipment/{id}` |
|
||||
| [`routes/shipment/_id/file/_fileId.delete.md`](routes/shipment/_id/file/_fileId.delete.md) | `DELETE /shipment/{id}/file/{fileId}` |
|
||||
| [`routes/shipment/_id/file/_fileId.get.md`](routes/shipment/_id/file/_fileId.get.md) | `GET /shipment/{id}/file/{fileId}` |
|
||||
| [`routes/shipment/_id/pdf.md`](routes/shipment/_id/pdf.md) | `POST /shipment/{id}/pdf` |
|
||||
| [`routes/shipment/_id/shipping.get.md`](routes/shipment/_id/shipping.get.md) | `GET /shipment/{id}/shipping` |
|
||||
| [`routes/shipment/_id/shipping.post.md`](routes/shipment/_id/shipping.post.md) | `POST /shipment/{id}/shipping` |
|
||||
| [`routes/shipping/_id.delete.md`](routes/shipping/_id.delete.md) | `DELETE /shipping/{id}` |
|
||||
@@ -233,7 +300,14 @@ Generated from `@openapi` annotations in [`src/api/routes/`](../../src/api/route
|
||||
| [`routes/shipping/_id/package.get.md`](routes/shipping/_id/package.get.md) | `GET /shipping/{id}/package` |
|
||||
| [`routes/shipping/_id/package.post.md`](routes/shipping/_id/package.post.md) | `POST /shipping/{id}/package` |
|
||||
| [`routes/smallthumb/get.md`](routes/smallthumb/get.md) | `GET /smallthumb/{fullHash}` |
|
||||
| [`routes/stock/accept.md`](routes/stock/accept.md) | `POST /stock/accept` |
|
||||
| [`routes/stock/adjust.md`](routes/stock/adjust.md) | `POST /stock/adjust` |
|
||||
| [`routes/stock/ship.md`](routes/stock/ship.md) | `POST /stock/ship` |
|
||||
| [`routes/subagentschedule.get.md`](routes/subagentschedule.get.md) | `GET /subagentschedule` |
|
||||
| [`routes/subagentschedule.post.md`](routes/subagentschedule.post.md) | `POST /subagentschedule` |
|
||||
| [`routes/subagentschedule/_id.delete.md`](routes/subagentschedule/_id.delete.md) | `DELETE /subagentschedule/{id}` |
|
||||
| [`routes/subagentschedule/_id.get.md`](routes/subagentschedule/_id.get.md) | `GET /subagentschedule/{id}` |
|
||||
| [`routes/subagentschedule/_id.put.md`](routes/subagentschedule/_id.put.md) | `PUT /subagentschedule/{id}` |
|
||||
| [`routes/supplier/list.md`](routes/supplier/list.md) | `GET /supplier` |
|
||||
| [`routes/supplier/create.md`](routes/supplier/create.md) | `POST /supplier` |
|
||||
| [`routes/supplier/delete.md`](routes/supplier/delete.md) | `DELETE /supplier/{id}` |
|
||||
@@ -245,14 +319,20 @@ 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` |
|
||||
| [`routes/vfs/drafts/response.md`](routes/vfs/drafts/response.md) | `POST /vfs/drafts/response` |
|
||||
| [`routes/vfs/applets-restore.md`](routes/vfs/applets-restore.md) | `POST /vfs/applets/restore` |
|
||||
| [`routes/vfs/mkdir.md`](routes/vfs/mkdir.md) | `POST /vfs/mkdir` |
|
||||
| [`routes/vfs/rename.md`](routes/vfs/rename.md) | `POST /vfs/rename` |
|
||||
| [`routes/vfs/skills-restore.md`](routes/vfs/skills-restore.md) | `POST /vfs/skills/restore` |
|
||||
| [`routes/vfs/upload.md`](routes/vfs/upload.md) | `POST /vfs/upload` |
|
||||
| [`routes/vfs/delete.md`](routes/vfs/delete.md) | `DELETE /vfs/{*path}` |
|
||||
| [`routes/vfs/_*path.md`](routes/vfs/_*path.md) | `GET /vfs/{*path}` |
|
||||
@@ -265,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).
|
||||
|
||||
@@ -274,19 +355,32 @@ 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}`, `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` |
|
||||
| `category` | `POST /category`, `PUT /category/order`, `DELETE /category/{id}`, `PATCH /category/{id}`, `DELETE /category/{id}/image`, `POST /category/{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`, `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` | `POST /stock/adjust` |
|
||||
| `ledger` | `DELETE /shipment/{id}`, `POST /stock/accept`, `POST /stock/adjust`, `POST /stock/ship` |
|
||||
| `modelconversation` | `POST /modelconversation`, `DELETE /modelconversation/{id}` |
|
||||
| `modelconversation-<id>` | `POST /modelconversation/{id}/message` |
|
||||
| `order` | `DELETE /order/{id}/file/{fileId}`, `POST /order/{id}/pdf`, `DELETE /shipment/{id}`, `PATCH /shipment/{id}`, `DELETE /shipment/{id}/file/{fileId}` |
|
||||
| `printer` | `POST /printer`, `PUT /printer/order`, `DELETE /printer/{id}`, `PATCH /printer/{id}`, `PUT /printer/{id}` |
|
||||
| `propertyname` | `POST /propertyname`, `PUT /propertyname/order`, `DELETE /propertyname/{id}`, `PATCH /propertyname/{id}` |
|
||||
| `stock` | `POST /stock/adjust` |
|
||||
| `vfs` | `POST /vfs/mkdir`, `POST /vfs/rename`, `POST /vfs/upload`, `DELETE /vfs/{*path}`, `POST /vfs/{*path}`, `PUT /vfs/{*path}` |
|
||||
| `quote` | `DELETE /quote/{id}/file/{fileId}`, `POST /quote/{id}/pdf` |
|
||||
| `shipment` | `DELETE /shipment/{id}`, `PATCH /shipment/{id}`, `DELETE /shipment/{id}/file/{fileId}`, `POST /shipment/{id}/pdf` |
|
||||
| `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}` |
|
||||
|
||||
## DESIGN
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
# Dash API Routes Overview
|
||||
|
||||
Overview of all 164 API endpoints across all modules.
|
||||
Overview of all 196 API endpoints across all modules.
|
||||
|
||||
### Notation
|
||||
|
||||
@@ -9,51 +9,33 @@ Params: path values first, then `query:` and `body:` (`body?` = optional body).
|
||||
|
||||
### Reusable types
|
||||
|
||||
- `T1` = `{ order: T2 }`
|
||||
- `T2` = `{ id: int, number: str, type: str, entityId: int|null, date: str, lines: T22[], createdAt?: str, shipping?: T30|null, shippings?: T30[], payment?: T36|null, payments?: T36[], paid?: bool, shipped?: bool, delivered?: bool, orderTotal?: num, paidTotal?: num, orderedQuantity?: num, shippedQuantity?: num, shipments?: T7[] }`
|
||||
- `T3` = `{ article: T4 }`
|
||||
- `T4` = `{ id: int, sku: str, name: str, slug: str, desc: str|null, seo: str|null, track_stock: bool, unitamount: num|null, weight: num|null, unit: T33, brand: T31|null, categoryIds: int[], photos: T28[], eans: str[], prices: T38[], suppliers: T13[] }`
|
||||
- `T5` = `{ delivery: T6 }`
|
||||
- `T6` = `{ id: int, number: str, type: str, supplierId: int|null, date: str, lines: T22[], files: T11[], externalNumber?: str|null, createdAt?: str, ledger?: T42 }`
|
||||
- `T7` = `{ id: int, number: str, type: str, date: str, lines: T22[], shippings: T30[], entityId?: int|null, externalNumber?: str|null, createdAt?: str|null, lineCount?: int, packageCount?: int }`
|
||||
- `T8` = `{ labeltemplate: T9 }`
|
||||
- `T9` = `{ id: int, name: str, width: num, height: num, dpi: int, type: str, content: T18, thumb?: str|null }`
|
||||
- `T10` = `{ quote: T12 }`
|
||||
- `T11` = `{ id: int, manifestId: int, fileId: int, sort: int, hash: str, mimetype: str, name: str, size: int, created?: str, modified?: str, thumbavif?: str|null, thumbx?: int|null, thumby?: int|null, meta?: { [k]: str }|null }`
|
||||
- `T12` = `{ id: int, number: str, type: str, entityId: int|null, date: str, lines: T22[], createdAt?: str }`
|
||||
- `T13` = `{ id: int, articleId: int, entityId: int, pu: num, sort: int, supplierName?: str|null, sku?: str|null, stock?: num|null, priceId?: int|null, price?: T44|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` = `{ ledger: T16[] }`
|
||||
- `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: T34[], articleCount?: int }`
|
||||
- `T18` = `{ objects: T23[] }`
|
||||
- `T19` = `{ objects: T24[] }`
|
||||
- `T20` = `{ printer: T26 }`
|
||||
- `T21` = `{ entity: T29 }`
|
||||
- `T22` = `{ id: int, sku: str|null, name: str|null, pu: num, amount: num, net: num, rebate: num, taxrate: num, comment: str|null }`
|
||||
- `T23` = `{ id: str, type: str, x: num, y: num, w?: num, h?: num, text?: str, font?: str, fontSize?: num, barcodeFormat?: str }`
|
||||
- `T24` = `{ id: str, type: str, x: num, y: num, w?: num, h?: num, text?: str, font?: str, fontSize?: num, barcodeFormat?: str }`
|
||||
- `T25` = `{ shipping: T30 }`
|
||||
- `T26` = `{ id: int, company_id: int, address: str, type: str, sort: int, model?: str|null, serial?: str|null, desc?: str|null }`
|
||||
- `T27` = `{ amount: num, net: num, taxrate: num, sku?: str|null, name?: str|null, pu?: num, rebate?: num, comment?: str|null }`
|
||||
- `T28` = `{ sort: int, fullHash: str, fullW: int, fullH: int, fullSize: int, thumbW: int, thumbH: int, thumbHash: str }`
|
||||
- `T29` = `{ id: int, customergroupId: int, firstName: str|null, name: str, number: str|null, createdAt: str, updatedAt: str }`
|
||||
- `T30` = `{ id: int, manifestId: int, number: str, type: str, state: str, trackingCode?: str|null, carrier?: str|null }`
|
||||
- `T31` = `{ name: str, id?: int|null, fullHash?: str|null, thumbW?: int|null, thumbH?: int|null, thumbHash?: str|null }`
|
||||
- `T32` = `{ article: T37 }`
|
||||
- `T33` = `{ si: str, basesi: str, basesifactor: num, symbol?: str|null, name?: str|null }`
|
||||
- `T34` = `{ id: int, attributeId: int, value: str, sort: int, articleCount?: int }`
|
||||
- `T35` = `{ id: int, name: str, sort: int, exclusive: bool, articleCount?: int }`
|
||||
- `T36` = `{ id: int, accountId: int, manifestId: int, type: str, amount: num }`
|
||||
- `T37` = `{ id: int, categoryId: int, name: str, sku: str, track_stock: bool }`
|
||||
- `T38` = `{ minmultiplier: num, net: num, taxRate: num, customergroupId: int }`
|
||||
- `T39` = `{ fullHash: str, thumbW: int, thumbH: int, thumbHash: str }`
|
||||
- `T40` = `{ id: int, entityId: int, contactType: str, contact: str }`
|
||||
- `T41` = `{ id: int, name: str, createdAt: str, updatedAt: str }`
|
||||
- `T42` = `{ totalPositions: int, completelyOnLedgerPositions: int }`
|
||||
- `T43` = `{ warehouse: T45 }`
|
||||
- `T44` = `{ net: num, taxId: int, taxRate?: num|null }`
|
||||
- `T45` = `{ id: int, name: str, sort: int }`
|
||||
- `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, 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
|
||||
|
||||
@@ -62,16 +44,19 @@ Params: path values first, then `query:` and `body:` (`body?` = optional body).
|
||||
|
||||
#### Create article in category — `POST /article`
|
||||
- Params: `body: { categoryId: int, name: str, desc?: str, seo?: str, track_stock?: bool }`
|
||||
- Returns: `201 T32`
|
||||
- Returns: `201 { sku: str }`
|
||||
#### Query company-wide article history — `GET /article/history`
|
||||
- Params: `query: offset?: int, limit?: int, search?: str, seekMonths?: int`
|
||||
- Returns: `200 { history: { id: int, date: str, sku: str, historytext: str, name?: str|null }[], total: int, unfilteredTotal: int, offset: int, limit: int }`
|
||||
#### Delete article by SKU — `DELETE /article/{sku}`
|
||||
- Params: `sku: str, query: cascade?: bool`
|
||||
- Returns: `204 void`
|
||||
#### Get article by SKU — `GET /article/{sku}`
|
||||
- Params: `sku: str`
|
||||
- Returns: `200 T3`
|
||||
- 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: `200 T3`
|
||||
- Returns: `204 void`
|
||||
#### Get Stückliste (bundle items) for an article — `GET /article/{sku}/articlelist`
|
||||
- Params: `sku: str`
|
||||
- Returns: `200 { items: { id: int, articleId: int, sku: str, name: str, count: int, sort: int }[] }`
|
||||
@@ -86,28 +71,28 @@ Params: path values first, then `query:` and `body:` (`body?` = optional body).
|
||||
- Returns: `200 { attributevalues: { id: int, attributeId: int, attributeName: str, attributeValueId: int, value: str, sort: int, articleId?: int, exclusive?: bool }[] }`
|
||||
#### Set or clear article brand by SKU (null to clear) — `PUT /article/{sku}/brand`
|
||||
- Params: `sku: str, body: { brandId: int|null }`
|
||||
- Returns: `200 T3`
|
||||
- Returns: `204 void`
|
||||
#### Replace article categories by SKU — `PUT /article/{sku}/categories`
|
||||
- Params: `sku: str, body: { categoryIds: int[] }`
|
||||
- Returns: `200 T3`
|
||||
- Returns: `204 void`
|
||||
#### List child articles of a parent article — `GET /article/{sku}/children`
|
||||
- Params: `sku: str`
|
||||
- Returns: `200 { children: { id: int, sku: str, name: str, parentsort: int, attributeValueId: int, attributeValue: str }[] }`
|
||||
#### Create and attach a new child article to a parent article — `POST /article/{sku}/children`
|
||||
- Params: `sku: str, body: { attributeValueId?: int, value?: str, name?: str }`
|
||||
- Returns: `201 T32`
|
||||
- Returns: `201 { sku: str }`
|
||||
#### Attach an existing article as a child to a parent article — `PUT /article/{sku}/children`
|
||||
- Params: `sku: str, body: { sku: str, attributeValueId?: int, value?: str, reparent?: bool }`
|
||||
- Returns: `200 { article: T37, children: { id: int, sku: str, name: str, parentsort: int, attributeValueId: int, attributeValue: str }[] }`
|
||||
- Returns: `200 { children: { id: int, sku: str, name: str, parentsort: int, attributeValueId: int, attributeValue: str }[] }`
|
||||
#### Remove a child article from a parent article — `DELETE /article/{sku}/children/{childSku}`
|
||||
- Params: `sku: str, childSku: str, query: deleteArticle?: bool`
|
||||
- Returns: `200 { success: bool, deleted: bool }`
|
||||
#### Replace article EANs by SKU — `PUT /article/{sku}/eans`
|
||||
- Params: `sku: str, body: { eans: str[] }`
|
||||
- Returns: `200 T3`
|
||||
- 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`
|
||||
@@ -122,12 +107,12 @@ Params: path values first, then `query:` and `body:` (`body?` = optional body).
|
||||
- Returns: `200 { options: { id: int, articleId: int, sku: str, name: str, count: int, sort: int, mandated: bool }[] }`
|
||||
#### Toggle parent mode for an article — `POST /article/{sku}/parent`
|
||||
- Params: `sku: str, body: { isParent: bool, attributeNameId?: int }`
|
||||
- Returns: `200 T32`
|
||||
#### 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 }[] }`
|
||||
- Returns: `200 T3`
|
||||
- Returns: `204 void`
|
||||
#### 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`
|
||||
@@ -140,10 +125,10 @@ Params: path values first, then `query:` and `body:` (`body?` = optional body).
|
||||
- Returns: `200 { ok: bool }`
|
||||
#### List article suppliers — `GET /article/{sku}/supplier`
|
||||
- Params: `sku: str`
|
||||
- Returns: `200 { suppliers: T13[] }`
|
||||
- Returns: `200 { suppliers: T5[] }`
|
||||
#### 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: T13 }`
|
||||
- Returns: `201 { supplier: T5 }`
|
||||
#### Reorder article suppliers — `PUT /article/{sku}/supplier/order`
|
||||
- Params: `sku: str, body: { ids: int[] }`
|
||||
- Returns: `200 { ids: int[] }`
|
||||
@@ -152,31 +137,31 @@ Params: path values first, then `query:` and `body:` (`body?` = optional body).
|
||||
- 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: T13 }`
|
||||
- Returns: `200 { supplier: T5 }`
|
||||
#### Set article track_stock flag by SKU — `PUT /article/{sku}/track_stock`
|
||||
- Params: `sku: str, body: { track_stock: bool }`
|
||||
- Returns: `200 T3`
|
||||
- Returns: `204 void`
|
||||
#### Set article weight by SKU — `PUT /article/{sku}/weight`
|
||||
- Params: `sku: str, body: { weight: num }`
|
||||
- Returns: `200 T3`
|
||||
- Returns: `204 void`
|
||||
|
||||
### Section: /attributename
|
||||
|
||||
#### List attribute names — `GET /attributename`
|
||||
_none_
|
||||
- Returns: `200 { attributenames: T17[] }`
|
||||
- Returns: `200 { attributenames: T10[] }`
|
||||
#### Create attribute name — `POST /attributename`
|
||||
- Params: `body: { name: str, sort?: int, exclusive?: bool }`
|
||||
- Returns: `201 { attributename: T17 }`
|
||||
- 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: T34[] }`
|
||||
- Returns: `200 { values: T18[] }`
|
||||
#### Create value for an attribute — `POST /attributename/{attributeId}/value`
|
||||
- Params: `attributeId: int, body: { value: str, sort?: int }`
|
||||
- Returns: `201 { attributevalue: T34 }`
|
||||
- Returns: `201 { attributevalue: T18 }`
|
||||
#### Reorder values of an attribute — `PUT /attributename/{attributeId}/value/order`
|
||||
- Params: `attributeId: int, body: { attributevalueIds: int[] }`
|
||||
- Returns: `200 { ok: bool }`
|
||||
@@ -185,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: T17 }`
|
||||
- Returns: `200 { attributename: T10 }`
|
||||
|
||||
### Section: /attributevalue
|
||||
|
||||
@@ -194,13 +179,22 @@ _none_
|
||||
- Returns: `200 { ok: bool }`
|
||||
#### Update attribute value — `PATCH /attributevalue/{id}`
|
||||
- Params: `id: int, body: { value?: str, sort?: int }`
|
||||
- Returns: `200 { attributevalue: T34 }`
|
||||
- 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: T39[] } }`
|
||||
#### 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: T39[] } }`
|
||||
- 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
|
||||
|
||||
@@ -209,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: T39[], 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`
|
||||
@@ -218,10 +212,28 @@ _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: T39[] } }`
|
||||
#### 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: T39[] } }`
|
||||
- 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: T22[] }`
|
||||
#### Create carrier — `POST /carrier`
|
||||
- Params: `body: { name: str, sort?: int, hasPackages?: bool, isReverse?: bool }`
|
||||
- Returns: `201 { carrier: T22 }`
|
||||
#### Reorder carriers — `PUT /carrier/order`
|
||||
- Params: `body: { carrierIds: int[] }`
|
||||
- Returns: `200 { carrierIds: int[] }`
|
||||
#### Delete carrier — `DELETE /carrier/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
#### Get carrier by ID — `GET /carrier/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { carrier: T22 }`
|
||||
#### Update carrier — `PATCH /carrier/{id}`
|
||||
- Params: `id: int, body: { name?: str, sort?: int, hasPackages?: bool, isReverse?: bool }`
|
||||
- Returns: `200 { carrier: T22 }`
|
||||
|
||||
### Section: /category
|
||||
|
||||
@@ -241,8 +253,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, brand?: T31|null }[] }`
|
||||
- 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`
|
||||
- Returns: `200 { attributevalues: { id: int, attributeId: int, attributeName: str, attributeValueId: int, value: str, sort: int, categoryId?: int, exclusive?: bool }[] }`
|
||||
@@ -252,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 }[] }`
|
||||
@@ -266,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 }`
|
||||
@@ -287,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
|
||||
|
||||
@@ -296,7 +326,7 @@ _none_
|
||||
- Returns: `200 { customergroups: { id: int, name: str, sort: int, editable: bool }[] }`
|
||||
#### Create customer group — `POST /customergroup`
|
||||
- Params: `body: { name: str }`
|
||||
- Returns: `201 { customergroup: T45 }`
|
||||
- Returns: `201 { customergroup: { id: int, name: str, sort: int } }`
|
||||
#### Reorder customer groups — `PUT /customergroup/order`
|
||||
- Params: `body: { customergroupIds: int[] }`
|
||||
- Returns: `200 { customergroupIds: int[] }`
|
||||
@@ -305,73 +335,76 @@ _none_
|
||||
- Returns: `204 void`
|
||||
#### Update customer group — `PATCH /customergroup/{id}`
|
||||
- Params: `id: int, body: { name: str }`
|
||||
- Returns: `200 { customergroup: T45 }`
|
||||
- Returns: `200 { customergroup: { id: int, name: str, sort: int } }`
|
||||
|
||||
### Section: /delivery
|
||||
|
||||
#### List deliveries — `GET /delivery`
|
||||
_none_
|
||||
- Returns: `200 { deliveries: { id: int, number: str, type: str, supplierId: int|null, date: str, externalNumber?: str|null, createdAt?: str, ledger?: T42 }[] }`
|
||||
- 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?: T26 }[], total: int, unfilteredTotal: int, offset: int, limit: int }`
|
||||
#### Create delivery — `POST /delivery`
|
||||
- Params: `body: { externalNumber: str, date: str, lines: T27[], supplierId?: int|null, files?: { mimetype: str, name: str, content: str, sort?: int, size?: int, hash?: str, created?: str, modified?: str, meta?: { [k]: str } }[] }`
|
||||
- Returns: `201 T5`
|
||||
- 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 }`
|
||||
#### Delete delivery — `DELETE /delivery/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
#### Get delivery — `GET /delivery/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 T5`
|
||||
- Returns: `200 { delivery: T4 }`
|
||||
#### Update delivery — `PATCH /delivery/{id}`
|
||||
- Params: `id: int, body: { externalNumber?: str|null, date?: str, supplierId?: int|null, lines?: T27[], files?: { mimetype: str, name: str, content: str, sort?: int, size?: int, hash?: str, created?: str, modified?: str, meta?: { [k]: str } }[] }`
|
||||
- Returns: `200 T5`
|
||||
#### Get delivery attachment file content — `GET /delivery/{id}/file/{fileId}`
|
||||
- Params: `id: int, fileId: int, query: download?: bool`
|
||||
- Returns: `200 str`
|
||||
- Params: `id: int, body: { externalNumber?: str|null, date?: str, supplierId?: int|null, 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: `200 { delivery: T4 }`
|
||||
#### Delete delivery file attachment — `DELETE /delivery/{id}/file/{fileId}`
|
||||
- Params: `id: int, fileId: int`
|
||||
- Returns: `204 void`
|
||||
#### Generate and attach delivery note PDF (goods receipt) — `POST /delivery/{id}/pdf`
|
||||
- Params: `id: int`
|
||||
- Returns: `201 { attachment: T7, fileUrl: str }`
|
||||
|
||||
### Section: /entity
|
||||
|
||||
#### List entities — `GET /entity`
|
||||
- Params: `query: customergroupId?: int, role?: str`
|
||||
- Returns: `200 { entities: T29[] }`
|
||||
- Returns: `200 { entities: T16[] }`
|
||||
#### Create entity — `POST /entity`
|
||||
- Params: `body: { customergroupId: int, name: str, firstName?: str|null, number?: str }`
|
||||
- Returns: `201 T21`
|
||||
- Returns: `201 { entity: T16 }`
|
||||
#### 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: T14[] }`
|
||||
- Returns: `200 { addresses: T8[] }`
|
||||
#### 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: T14 }`
|
||||
- Returns: `201 { address: T8 }`
|
||||
#### 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: T14 }`
|
||||
- Returns: `200 { address: T8 }`
|
||||
#### List entity contacts — `GET /entity/{entityId}/contact`
|
||||
- Params: `entityId: int`
|
||||
- Returns: `200 { contacts: T40[] }`
|
||||
- Returns: `200 { contacts: T24[] }`
|
||||
#### Create entity contact — `POST /entity/{entityId}/contact`
|
||||
- Params: `entityId: int, body: { contactType: str, contact: str }`
|
||||
- Returns: `201 { contact: T40 }`
|
||||
- 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: T40 }`
|
||||
- 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 T21`
|
||||
- Returns: `200 { entity: T16 }`
|
||||
#### Update entity — `PATCH /entity/{id}`
|
||||
- Params: `id: int, body: { name?: str, firstName?: str|null, number?: str|null }`
|
||||
- Returns: `200 T21`
|
||||
- Returns: `200 { entity: T16 }`
|
||||
|
||||
### Section: /labeltemplate
|
||||
|
||||
@@ -379,35 +412,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: T19 }`
|
||||
- Returns: `201 T8`
|
||||
- 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`
|
||||
#### Get label template by ID — `GET /labeltemplate/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 T8`
|
||||
- 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?: T19 }`
|
||||
- Returns: `200 T8`
|
||||
- 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?: T19 }`
|
||||
- Returns: `200 T8`
|
||||
- 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 T15`
|
||||
#### Add ledger entry — `POST /ledger`
|
||||
- Params: `body: { manifestarticle_id: int, transaction_type: str, amount: num, transaction_text: str }`
|
||||
- Returns: `201 { ledger: T16 }`
|
||||
- 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 T15`
|
||||
- Returns: `200 { ledger: T9[] }`
|
||||
#### Query ledger by article SKU — `GET /ledger/sku/{sku}`
|
||||
- Params: `sku: str, query: transaction_type?: str`
|
||||
- Returns: `200 T15`
|
||||
- Returns: `200 { ledger: T9[] }`
|
||||
|
||||
### Section: /number
|
||||
|
||||
@@ -422,37 +458,43 @@ _none_
|
||||
|
||||
#### List orders — `GET /order`
|
||||
- Params: `query: offset?: int, limit?: int, search?: str, onlyUnpaid?: bool, onlyUndelivered?: bool, seekMonths?: int`
|
||||
- Returns: `200 { orders: T2[], total: int, unfilteredTotal: int, offset: int, limit: int }`
|
||||
- Returns: `200 { orders: T1[], total: int, unfilteredTotal: int, offset: int, limit: int }`
|
||||
#### Create order — `POST /order`
|
||||
- Params: `body: { number: str, date: str, lines: T27[], entityId?: int|null }`
|
||||
- Returns: `201 T1`
|
||||
- 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`
|
||||
- Returns: `204 void`
|
||||
#### Get order — `GET /order/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 T1`
|
||||
- Returns: `200 { order: T1 }`
|
||||
#### Update order — `PATCH /order/{id}`
|
||||
- Params: `id: int, body: { number?: str, date?: str, entityId?: int|null, lines?: T27[] }`
|
||||
- Returns: `200 T1`
|
||||
- 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: T36[] }`
|
||||
- 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: T36 }`
|
||||
- Returns: `201 { payment: T21 }`
|
||||
#### Generate and attach order PDF — `POST /order/{id}/pdf`
|
||||
- Params: `id: int`
|
||||
- Returns: `201 { attachment: T7, fileUrl: str }`
|
||||
#### List shipments of an order — `GET /order/{id}/shipment`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { shipments: T7[] }`
|
||||
- Returns: `200 { shipments: T2[] }`
|
||||
#### Create shipment for an order — `POST /order/{id}/shipment`
|
||||
- Params: `id: int, body: { lines: { sku: str, amount: num, name?: str, pu?: num, net?: num, rebate?: num, taxrate?: num, comment?: str }[], date?: str, externalNumber?: str }`
|
||||
- Returns: `201 { shipment: T7 }`
|
||||
- Params: `id: int, body: { lines: { sku?: str, orderLineId?: int, amount?: num, name?: str, pu?: num, net?: num, rebate?: num, taxrate?: num, comment?: str }[], date?: str, warehouseId?: int, externalNumber?: str }`
|
||||
- Returns: `201 { shipment: T2 }`
|
||||
#### List shippings of an order — `GET /order/{id}/shipping`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { shippings: T30[] }`
|
||||
- Returns: `200 { shippings: T13[] }`
|
||||
#### Create shipping for an order — `POST /order/{id}/shipping`
|
||||
- Params: `id: int, body: { type: str, state: str, warehouseId?: int }`
|
||||
- Returns: `201 T25`
|
||||
- Params: `id: int, body: { carrierId: int, type: str, state: str, trackingCode?: str, warehouseId?: int }`
|
||||
- Returns: `201 { shipping: T13 }`
|
||||
|
||||
### Section: /package
|
||||
|
||||
@@ -466,38 +508,14 @@ _none_
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
|
||||
### Section: /printer
|
||||
|
||||
#### List printers — `GET /printer`
|
||||
_none_
|
||||
- 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 T20`
|
||||
#### 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 T20`
|
||||
#### 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 T20`
|
||||
#### 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 T20`
|
||||
|
||||
### Section: /propertyname
|
||||
|
||||
#### List property names — `GET /propertyname`
|
||||
_none_
|
||||
- Returns: `200 { propertynames: T35[] }`
|
||||
- Returns: `200 { propertynames: T20[] }`
|
||||
#### Create property name — `POST /propertyname`
|
||||
- Params: `body: { name: str, sort?: int, exclusive?: bool }`
|
||||
- Returns: `201 { propertyname: T35 }`
|
||||
- Returns: `201 { propertyname: T20 }`
|
||||
#### Reorder property names — `PUT /propertyname/order`
|
||||
- Params: `body: { propertynameIds: int[] }`
|
||||
- Returns: `200 { ok: bool }`
|
||||
@@ -506,40 +524,109 @@ _none_
|
||||
- Returns: `200 { ok: bool }`
|
||||
#### Update property name — `PATCH /propertyname/{id}`
|
||||
- Params: `id: int, body: { name?: str, sort?: int, exclusive?: bool }`
|
||||
- Returns: `200 { propertyname: T35 }`
|
||||
- Returns: `200 { propertyname: T20 }`
|
||||
|
||||
### Section: /quote
|
||||
|
||||
#### List quotes — `GET /quote`
|
||||
_none_
|
||||
- Returns: `200 { quotes: { id: int, number: str, type: str, entityId: int|null, date: str, createdAt?: str }[] }`
|
||||
- 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: T27[], entityId?: int|null }`
|
||||
- Returns: `201 T10`
|
||||
- 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`
|
||||
- Returns: `204 void`
|
||||
#### Get quote — `GET /quote/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 T10`
|
||||
- Returns: `200 { quote: T3 }`
|
||||
#### Update quote — `PATCH /quote/{id}`
|
||||
- Params: `id: int, body: { number?: str, date?: str, entityId?: int|null, lines?: T27[] }`
|
||||
- Returns: `200 T10`
|
||||
- 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?: 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`
|
||||
- Params: `query: offset?: int, limit?: int, search?: str, state?: str, seekMonths?: int`
|
||||
- Returns: `200 { shipments: { id: int, number: str, type: str, date: str, positions: int, totalQuantity: num, packageCount: int, state: str, entityId?: int|null, externalNumber?: str|null, createdAt?: str|null, orderId?: int|null, orderNumber?: str|null, customerName?: str|null, carrier?: str|null, trackingCode?: str|null }[], total: int, unfilteredTotal: int, offset: int, limit: int }`
|
||||
#### Delete shipment — `DELETE /shipment/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
#### Get shipment by ID — `GET /shipment/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { shipment: T7 }`
|
||||
- Returns: `200 { shipment: T2 }`
|
||||
#### Update shipment state or metadata — `PATCH /shipment/{id}`
|
||||
- Params: `id: int, body: { state?: str }`
|
||||
- Returns: `200 { shipment: T2 }`
|
||||
#### Delete shipment file attachment — `DELETE /shipment/{id}/file/{fileId}`
|
||||
- Params: `id: int, fileId: int`
|
||||
- Returns: `204 void`
|
||||
#### Generate and attach shipment PDF (delivery note) — `POST /shipment/{id}/pdf`
|
||||
- Params: `id: int`
|
||||
- Returns: `201 { attachment: T7, fileUrl: str }`
|
||||
#### List packages of a shipment — `GET /shipment/{id}/shipping`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { shippings: T30[] }`
|
||||
- Returns: `200 { shippings: T13[] }`
|
||||
#### Create package for a shipment — `POST /shipment/{id}/shipping`
|
||||
- Params: `id: int, body: { type: str, state: str, trackingCode?: str, carrier?: str, warehouseId?: int }`
|
||||
- Returns: `201 T25`
|
||||
- Params: `id: int, body: { carrierId: int, type: str, state: str, trackingCode?: str, warehouseId?: int }`
|
||||
- Returns: `201 { shipping: T13 }`
|
||||
|
||||
### Section: /shipping
|
||||
|
||||
@@ -547,8 +634,8 @@ _none_
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
#### Update shipping — `PATCH /shipping/{id}`
|
||||
- Params: `id: int, body: { type?: str, state?: str, trackingCode?: str, carrier?: str, warehouseId?: int }`
|
||||
- Returns: `200 T25`
|
||||
- Params: `id: int, body: { type?: str, state?: str, trackingCode?: str, carrierId?: int, warehouseId?: int }`
|
||||
- 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 }[] }`
|
||||
@@ -556,38 +643,38 @@ _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`
|
||||
- Params: `body: { manifestarticleId?: int, warehouseId?: int, items?: { manifestarticleId: int, warehouseId?: int }[] }`
|
||||
- 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: T16[] }`
|
||||
- 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: /supplier
|
||||
|
||||
#### List suppliers — `GET /supplier`
|
||||
_none_
|
||||
- Returns: `200 { suppliers: T41[] }`
|
||||
- Returns: `200 { suppliers: T25[] }`
|
||||
#### Create supplier — `POST /supplier`
|
||||
- Params: `body: { name: str }`
|
||||
- Returns: `201 { supplier: T41 }`
|
||||
- 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: T41 }`
|
||||
- Returns: `200 { supplier: T25 }`
|
||||
#### List supplier articles by SKUs — `GET /supplier/{id}/articles`
|
||||
- Params: `id: int, query: skus?: string`
|
||||
- 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?: T44|null }[] }`
|
||||
- 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?: 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?: T44|null }[] }`
|
||||
- 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
|
||||
|
||||
@@ -596,19 +683,19 @@ _none_
|
||||
- Returns: `204 void`
|
||||
#### List units — `GET /unit`
|
||||
_none_
|
||||
- Returns: `200 { units: T33[] }`
|
||||
- Returns: `200 { units: T17[] }`
|
||||
#### Upsert unit — `PUT /unit`
|
||||
- Params: `body: { si: str, basesi: str, basesifactor: num, symbol: str, name: str }`
|
||||
- Returns: `200 { unit: T33 }`
|
||||
- Returns: `200 { unit: T17 }`
|
||||
|
||||
### Section: /warehouse
|
||||
|
||||
#### List warehouses — `GET /warehouse`
|
||||
_none_
|
||||
- Returns: `200 { warehouses: T45[] }`
|
||||
- Returns: `200 { warehouses: { id: int, name: str, sort: int }[] }`
|
||||
#### Create warehouse — `POST /warehouse`
|
||||
- Params: `body: { name: str, sort?: int }`
|
||||
- Returns: `201 T43`
|
||||
- Returns: `201 { warehouse: { id: int, name: str, sort: int } }`
|
||||
#### Reorder warehouses — `PUT /warehouse/order`
|
||||
- Params: `body: { warehouseIds: int[] }`
|
||||
- Returns: `200 { warehouseIds: int[] }`
|
||||
@@ -617,24 +704,28 @@ _none_
|
||||
- Returns: `204 void`
|
||||
#### Get warehouse by ID — `GET /warehouse/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 T43`
|
||||
- Returns: `200 { warehouse: { id: int, name: str, sort: int } }`
|
||||
#### Update warehouse (partial) — `PATCH /warehouse/{id}`
|
||||
- Params: `id: int, body: { name?: str, sort?: int }`
|
||||
- Returns: `200 T43`
|
||||
- Returns: `200 { warehouse: { id: int, name: str, sort: int } }`
|
||||
#### Update warehouse — `PUT /warehouse/{id}`
|
||||
- Params: `id: int, body: { name?: str, sort?: int }`
|
||||
- Returns: `200 T43`
|
||||
- Returns: `200 { warehouse: { id: int, name: str, sort: int } }`
|
||||
### Binary & streaming routes (reachable only via `fetch()` in javascript_execute)
|
||||
|
||||
These routes are NOT in the table above because their responses are binary or long-lived streams, which the `dashback_request` tool cannot return usefully. They ARE reachable from inside `javascript_execute` with `fetch("/route")`, where you can decode the bytes, write them to the VFS and embed them in your reply:
|
||||
These routes are NOT in the table above because their payloads (binary request body or binary response) or long-lived streams cannot be handled usefully by the `dashback_request` tool. They ARE reachable from inside `javascript_execute` with `fetch("/route")`:
|
||||
|
||||
| Method | Route | Returns | Notes |
|
||||
|:---|:---|:---|:---|
|
||||
| `GET` | `/image/{fullHash}` | `image/avif` | Full-size article/brand/category image by SHA-256 hash. Use for inspecting or re-encoding an existing image.
|
||||
| `GET` | `/thumb/{fullHash}` | `image/avif` | Thumb AVIF by SHA-256 hash — cheaper than the full image. Takes the same `fullHash` as `/image/{fullHash}`.
|
||||
| `POST` | `/serper/image` | `image/avif` | Crawl an image from a URL, auto-crop transparent/white borders. Body: `{ url }`.
|
||||
| `POST` | `/article/{sku}/image` | `201 { image: { picId, sort, full, thumb, hash, thumbHash } }` | Upload full-size AVIF or WebP image for article SKU. WebP is auto-converted to AVIF. Body: raw binary (`image/avif` or `image/webp`).
|
||||
| `POST` | `/attributevalue/{id}/image` | `201 { attributevalue: { id, fullHash, thumbW, thumbH, thumbHash, pics } }` | Upload or replace AVIF/WebP image for attribute value ID. Body: raw binary (`image/avif` or `image/webp`).
|
||||
| `POST` | `/brand/{id}/image` | `201 { brand: { id, fullHash, thumbW, thumbH, thumbHash, pics } }` | Upload or replace AVIF/WebP image for brand ID. Body: raw binary (`image/avif` or `image/webp`).
|
||||
| `POST` | `/category/{id}/image` | `201 { category: { id, thumbW, thumbH, thumbHash } }` | Upload or replace AVIF/WebP image for category ID. Body: raw binary (`image/avif` or `image/webp`).
|
||||
|
||||
Save the bytes to the VFS, then embed them in your reply as ``:
|
||||
Save downloaded bytes to the VFS, then embed them in your reply as ``:
|
||||
|
||||
```js
|
||||
module.exports = (async () => {
|
||||
@@ -646,4 +737,18 @@ module.exports = (async () => {
|
||||
})();
|
||||
```
|
||||
|
||||
Upload an image from the VFS:
|
||||
|
||||
```js
|
||||
module.exports = (async () => {
|
||||
const buf = fs.readFileSync("images/product.avif");
|
||||
const res = await fetch("/article/SKU123/image", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "image/avif" },
|
||||
body: buf,
|
||||
});
|
||||
return await res.json();
|
||||
})();
|
||||
```
|
||||
|
||||
`fullHash` appears on articles, brands and categories. `thumbHash` is a base64 blur-up placeholder, not a content hash, and is not accepted here.
|
||||
|
||||
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`._
|
||||
@@ -34,13 +34,7 @@ Created child article
|
||||
|
||||
```json
|
||||
{
|
||||
"article": {
|
||||
"id": 1,
|
||||
"categoryId": 1,
|
||||
"name": "…",
|
||||
"sku": "…",
|
||||
"track_stock": true
|
||||
}
|
||||
"sku": "…"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -32,17 +32,10 @@ Attaches an existing article to this parent article. Idempotent if already a chi
|
||||
|
||||
## Response `200`
|
||||
|
||||
Attached child article and list of children
|
||||
List of children after attaching
|
||||
|
||||
```json
|
||||
{
|
||||
"article": {
|
||||
"id": 1,
|
||||
"categoryId": 1,
|
||||
"name": "…",
|
||||
"sku": "…",
|
||||
"track_stock": true
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": 1,
|
||||
|
||||
@@ -34,21 +34,11 @@ when `isParent` is `false`.
|
||||
}
|
||||
```
|
||||
|
||||
## Response `200`
|
||||
## Response `204`
|
||||
|
||||
Updated article
|
||||
Updated
|
||||
|
||||
```json
|
||||
{
|
||||
"article": {
|
||||
"id": 1,
|
||||
"categoryId": 1,
|
||||
"name": "…",
|
||||
"sku": "…",
|
||||
"track_stock": true
|
||||
}
|
||||
}
|
||||
```
|
||||
_No content_
|
||||
|
||||
## Errors
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
```
|
||||
|
||||
@@ -29,84 +29,11 @@ Enables or disables inventory stock tracking for this article.
|
||||
|
||||
On success, emits SSE signal: `article-<sku>` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
## Response `204`
|
||||
|
||||
Updated article detail
|
||||
Updated
|
||||
|
||||
```json
|
||||
{
|
||||
"article": {
|
||||
"id": 1,
|
||||
"sku": "…",
|
||||
"name": "…",
|
||||
"slug": "…",
|
||||
"desc": "…",
|
||||
"seo": "…",
|
||||
"track_stock": true,
|
||||
"unitamount": 1,
|
||||
"weight": 1,
|
||||
"unit": {
|
||||
"si": "…",
|
||||
"basesi": "…",
|
||||
"basesifactor": 1,
|
||||
"symbol": "…",
|
||||
"name": "…"
|
||||
},
|
||||
"brand": {
|
||||
"id": 1,
|
||||
"name": "…",
|
||||
"fullHash": "…",
|
||||
"thumbW": 1,
|
||||
"thumbH": 1,
|
||||
"thumbHash": "…"
|
||||
},
|
||||
"categoryIds": [
|
||||
1
|
||||
],
|
||||
"photos": [
|
||||
{
|
||||
"sort": 1,
|
||||
"fullHash": "…",
|
||||
"fullW": 1,
|
||||
"fullH": 1,
|
||||
"fullSize": 1,
|
||||
"thumbW": 1,
|
||||
"thumbH": 1,
|
||||
"thumbHash": "…"
|
||||
}
|
||||
],
|
||||
"eans": [
|
||||
"…"
|
||||
],
|
||||
"prices": [
|
||||
{
|
||||
"minmultiplier": 1,
|
||||
"net": 1,
|
||||
"taxRate": 1,
|
||||
"customergroupId": 1
|
||||
}
|
||||
],
|
||||
"suppliers": [
|
||||
{
|
||||
"id": 1,
|
||||
"articleId": 1,
|
||||
"entityId": 1,
|
||||
"supplierName": "…",
|
||||
"sku": "…",
|
||||
"pu": 1,
|
||||
"stock": 1,
|
||||
"sort": 1,
|
||||
"priceId": 1,
|
||||
"price": {
|
||||
"net": 1,
|
||||
"taxId": 1,
|
||||
"taxRate": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
_No content_
|
||||
|
||||
## Errors
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ Creates an article under an authorized category (`parentId`).
|
||||
| `name` | yes | string | |
|
||||
| `desc` | no | string | Article description text/HTML |
|
||||
| `seo` | no | string | SEO text |
|
||||
| `track_stock` | no | boolean | Whether to track inventory stock (defaults to true) |
|
||||
| `track_stock` | no | boolean | Whether to track inventory stock (defaults to false) |
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -33,13 +33,7 @@ Created
|
||||
|
||||
```json
|
||||
{
|
||||
"article": {
|
||||
"id": 1,
|
||||
"categoryId": 1,
|
||||
"name": "…",
|
||||
"sku": "…",
|
||||
"track_stock": true
|
||||
}
|
||||
"sku": "…"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -84,7 +84,22 @@ Article detail
|
||||
"net": 1,
|
||||
"taxId": 1,
|
||||
"taxRate": 1
|
||||
}
|
||||
},
|
||||
"incoming": [
|
||||
{
|
||||
"date": "2026-08-10T00:00:00.000Z",
|
||||
"amount": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"undeliveredOrders": [
|
||||
{
|
||||
"orderId": 1,
|
||||
"orderNumber": "…",
|
||||
"date": "2026-08-10T00:00:00.000Z",
|
||||
"customerName": "…",
|
||||
"amount": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
52
docs/api/routes/article/history-list.md
Normal file
52
docs/api/routes/article/history-list.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# `GET /article/history`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Query company-wide article history
|
||||
|
||||
Queries article change history across all articles for the authenticated user's selected company.
|
||||
Supports pagination, search filter, and date cutoff via `seekMonths`.
|
||||
|
||||
|
||||
## Query parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `offset` | no | integer | Paging offset |
|
||||
| `limit` | no | integer | Page size |
|
||||
| `search` | no | string | Optional search filter across SKU, article name, and history text |
|
||||
| `seekMonths` | no | integer | Negative integer cutoff months ago (e.g. -13) |
|
||||
|
||||
## Response `200`
|
||||
|
||||
Paged article history list
|
||||
|
||||
```json
|
||||
{
|
||||
"history": [
|
||||
{
|
||||
"id": 1,
|
||||
"date": "2026-08-10T00:00:00.000Z",
|
||||
"sku": "…",
|
||||
"name": "…",
|
||||
"historytext": "…"
|
||||
}
|
||||
],
|
||||
"total": 1,
|
||||
"unfilteredTotal": 1,
|
||||
"offset": 1,
|
||||
"limit": 1
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Validation error or no company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
@@ -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":"…"}` |
|
||||
|
||||
@@ -30,84 +30,11 @@ Pass `null` to clear the brand. Returns the same shape as GET by SKU.
|
||||
|
||||
On success, emits SSE signal: `article-<sku>` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
## Response `204`
|
||||
|
||||
Updated article detail
|
||||
Updated
|
||||
|
||||
```json
|
||||
{
|
||||
"article": {
|
||||
"id": 1,
|
||||
"sku": "…",
|
||||
"name": "…",
|
||||
"slug": "…",
|
||||
"desc": "…",
|
||||
"seo": "…",
|
||||
"track_stock": true,
|
||||
"unitamount": 1,
|
||||
"weight": 1,
|
||||
"unit": {
|
||||
"si": "…",
|
||||
"basesi": "…",
|
||||
"basesifactor": 1,
|
||||
"symbol": "…",
|
||||
"name": "…"
|
||||
},
|
||||
"brand": {
|
||||
"id": 1,
|
||||
"name": "…",
|
||||
"fullHash": "…",
|
||||
"thumbW": 1,
|
||||
"thumbH": 1,
|
||||
"thumbHash": "…"
|
||||
},
|
||||
"categoryIds": [
|
||||
1
|
||||
],
|
||||
"photos": [
|
||||
{
|
||||
"sort": 1,
|
||||
"fullHash": "…",
|
||||
"fullW": 1,
|
||||
"fullH": 1,
|
||||
"fullSize": 1,
|
||||
"thumbW": 1,
|
||||
"thumbH": 1,
|
||||
"thumbHash": "…"
|
||||
}
|
||||
],
|
||||
"eans": [
|
||||
"…"
|
||||
],
|
||||
"prices": [
|
||||
{
|
||||
"minmultiplier": 1,
|
||||
"net": 1,
|
||||
"taxRate": 1,
|
||||
"customergroupId": 1
|
||||
}
|
||||
],
|
||||
"suppliers": [
|
||||
{
|
||||
"id": 1,
|
||||
"articleId": 1,
|
||||
"entityId": 1,
|
||||
"supplierName": "…",
|
||||
"sku": "…",
|
||||
"pu": 1,
|
||||
"stock": 1,
|
||||
"sort": 1,
|
||||
"priceId": 1,
|
||||
"price": {
|
||||
"net": 1,
|
||||
"taxId": 1,
|
||||
"taxRate": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
_No content_
|
||||
|
||||
## Errors
|
||||
|
||||
|
||||
@@ -34,84 +34,11 @@ at least one category (empty array is rejected). Returns the same shape as GET b
|
||||
|
||||
On success, emits SSE signal: `article-<sku>` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
## Response `204`
|
||||
|
||||
Updated article detail
|
||||
Updated
|
||||
|
||||
```json
|
||||
{
|
||||
"article": {
|
||||
"id": 1,
|
||||
"sku": "…",
|
||||
"name": "…",
|
||||
"slug": "…",
|
||||
"desc": "…",
|
||||
"seo": "…",
|
||||
"track_stock": true,
|
||||
"unitamount": 1,
|
||||
"weight": 1,
|
||||
"unit": {
|
||||
"si": "…",
|
||||
"basesi": "…",
|
||||
"basesifactor": 1,
|
||||
"symbol": "…",
|
||||
"name": "…"
|
||||
},
|
||||
"brand": {
|
||||
"id": 1,
|
||||
"name": "…",
|
||||
"fullHash": "…",
|
||||
"thumbW": 1,
|
||||
"thumbH": 1,
|
||||
"thumbHash": "…"
|
||||
},
|
||||
"categoryIds": [
|
||||
1
|
||||
],
|
||||
"photos": [
|
||||
{
|
||||
"sort": 1,
|
||||
"fullHash": "…",
|
||||
"fullW": 1,
|
||||
"fullH": 1,
|
||||
"fullSize": 1,
|
||||
"thumbW": 1,
|
||||
"thumbH": 1,
|
||||
"thumbHash": "…"
|
||||
}
|
||||
],
|
||||
"eans": [
|
||||
"…"
|
||||
],
|
||||
"prices": [
|
||||
{
|
||||
"minmultiplier": 1,
|
||||
"net": 1,
|
||||
"taxRate": 1,
|
||||
"customergroupId": 1
|
||||
}
|
||||
],
|
||||
"suppliers": [
|
||||
{
|
||||
"id": 1,
|
||||
"articleId": 1,
|
||||
"entityId": 1,
|
||||
"supplierName": "…",
|
||||
"sku": "…",
|
||||
"pu": 1,
|
||||
"stock": 1,
|
||||
"sort": 1,
|
||||
"priceId": 1,
|
||||
"price": {
|
||||
"net": 1,
|
||||
"taxId": 1,
|
||||
"taxRate": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
_No content_
|
||||
|
||||
## Errors
|
||||
|
||||
|
||||
@@ -32,84 +32,11 @@ empty array clears all EANs. Returns the same shape as GET by SKU.
|
||||
|
||||
On success, emits SSE signal: `article-<sku>` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
## Response `204`
|
||||
|
||||
Updated article detail
|
||||
Updated
|
||||
|
||||
```json
|
||||
{
|
||||
"article": {
|
||||
"id": 1,
|
||||
"sku": "…",
|
||||
"name": "…",
|
||||
"slug": "…",
|
||||
"desc": "…",
|
||||
"seo": "…",
|
||||
"track_stock": true,
|
||||
"unitamount": 1,
|
||||
"weight": 1,
|
||||
"unit": {
|
||||
"si": "…",
|
||||
"basesi": "…",
|
||||
"basesifactor": 1,
|
||||
"symbol": "…",
|
||||
"name": "…"
|
||||
},
|
||||
"brand": {
|
||||
"id": 1,
|
||||
"name": "…",
|
||||
"fullHash": "…",
|
||||
"thumbW": 1,
|
||||
"thumbH": 1,
|
||||
"thumbHash": "…"
|
||||
},
|
||||
"categoryIds": [
|
||||
1
|
||||
],
|
||||
"photos": [
|
||||
{
|
||||
"sort": 1,
|
||||
"fullHash": "…",
|
||||
"fullW": 1,
|
||||
"fullH": 1,
|
||||
"fullSize": 1,
|
||||
"thumbW": 1,
|
||||
"thumbH": 1,
|
||||
"thumbHash": "…"
|
||||
}
|
||||
],
|
||||
"eans": [
|
||||
"…"
|
||||
],
|
||||
"prices": [
|
||||
{
|
||||
"minmultiplier": 1,
|
||||
"net": 1,
|
||||
"taxRate": 1,
|
||||
"customergroupId": 1
|
||||
}
|
||||
],
|
||||
"suppliers": [
|
||||
{
|
||||
"id": 1,
|
||||
"articleId": 1,
|
||||
"entityId": 1,
|
||||
"supplierName": "…",
|
||||
"sku": "…",
|
||||
"pu": 1,
|
||||
"stock": 1,
|
||||
"sort": 1,
|
||||
"priceId": 1,
|
||||
"price": {
|
||||
"net": 1,
|
||||
"taxId": 1,
|
||||
"taxRate": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
_No content_
|
||||
|
||||
## Errors
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -50,84 +48,11 @@ Empty `prices` clears all POS prices. Returns the same shape as GET by SKU.
|
||||
|
||||
On success, emits SSE signal: `article-<sku>` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
## Response `204`
|
||||
|
||||
Updated article detail
|
||||
Updated
|
||||
|
||||
```json
|
||||
{
|
||||
"article": {
|
||||
"id": 1,
|
||||
"sku": "…",
|
||||
"name": "…",
|
||||
"slug": "…",
|
||||
"desc": "…",
|
||||
"seo": "…",
|
||||
"track_stock": true,
|
||||
"unitamount": 1,
|
||||
"weight": 1,
|
||||
"unit": {
|
||||
"si": "…",
|
||||
"basesi": "…",
|
||||
"basesifactor": 1,
|
||||
"symbol": "…",
|
||||
"name": "…"
|
||||
},
|
||||
"brand": {
|
||||
"id": 1,
|
||||
"name": "…",
|
||||
"fullHash": "…",
|
||||
"thumbW": 1,
|
||||
"thumbH": 1,
|
||||
"thumbHash": "…"
|
||||
},
|
||||
"categoryIds": [
|
||||
1
|
||||
],
|
||||
"photos": [
|
||||
{
|
||||
"sort": 1,
|
||||
"fullHash": "…",
|
||||
"fullW": 1,
|
||||
"fullH": 1,
|
||||
"fullSize": 1,
|
||||
"thumbW": 1,
|
||||
"thumbH": 1,
|
||||
"thumbHash": "…"
|
||||
}
|
||||
],
|
||||
"eans": [
|
||||
"…"
|
||||
],
|
||||
"prices": [
|
||||
{
|
||||
"minmultiplier": 1,
|
||||
"net": 1,
|
||||
"taxRate": 1,
|
||||
"customergroupId": 1
|
||||
}
|
||||
],
|
||||
"suppliers": [
|
||||
{
|
||||
"id": 1,
|
||||
"articleId": 1,
|
||||
"entityId": 1,
|
||||
"supplierName": "…",
|
||||
"sku": "…",
|
||||
"pu": 1,
|
||||
"stock": 1,
|
||||
"sort": 1,
|
||||
"priceId": 1,
|
||||
"price": {
|
||||
"net": 1,
|
||||
"taxId": 1,
|
||||
"taxRate": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
_No content_
|
||||
|
||||
## Errors
|
||||
|
||||
|
||||
@@ -30,84 +30,11 @@ Returns the same shape as GET by SKU.
|
||||
|
||||
On success, emits SSE signal: `article-<sku>` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
## Response `204`
|
||||
|
||||
Updated article detail
|
||||
Updated
|
||||
|
||||
```json
|
||||
{
|
||||
"article": {
|
||||
"id": 1,
|
||||
"sku": "…",
|
||||
"name": "…",
|
||||
"slug": "…",
|
||||
"desc": "…",
|
||||
"seo": "…",
|
||||
"track_stock": true,
|
||||
"unitamount": 1,
|
||||
"weight": 1,
|
||||
"unit": {
|
||||
"si": "…",
|
||||
"basesi": "…",
|
||||
"basesifactor": 1,
|
||||
"symbol": "…",
|
||||
"name": "…"
|
||||
},
|
||||
"brand": {
|
||||
"id": 1,
|
||||
"name": "…",
|
||||
"fullHash": "…",
|
||||
"thumbW": 1,
|
||||
"thumbH": 1,
|
||||
"thumbHash": "…"
|
||||
},
|
||||
"categoryIds": [
|
||||
1
|
||||
],
|
||||
"photos": [
|
||||
{
|
||||
"sort": 1,
|
||||
"fullHash": "…",
|
||||
"fullW": 1,
|
||||
"fullH": 1,
|
||||
"fullSize": 1,
|
||||
"thumbW": 1,
|
||||
"thumbH": 1,
|
||||
"thumbHash": "…"
|
||||
}
|
||||
],
|
||||
"eans": [
|
||||
"…"
|
||||
],
|
||||
"prices": [
|
||||
{
|
||||
"minmultiplier": 1,
|
||||
"net": 1,
|
||||
"taxRate": 1,
|
||||
"customergroupId": 1
|
||||
}
|
||||
],
|
||||
"suppliers": [
|
||||
{
|
||||
"id": 1,
|
||||
"articleId": 1,
|
||||
"entityId": 1,
|
||||
"supplierName": "…",
|
||||
"sku": "…",
|
||||
"pu": 1,
|
||||
"stock": 1,
|
||||
"sort": 1,
|
||||
"priceId": 1,
|
||||
"price": {
|
||||
"net": 1,
|
||||
"taxId": 1,
|
||||
"taxRate": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
_No content_
|
||||
|
||||
## Errors
|
||||
|
||||
|
||||
@@ -62,7 +62,13 @@ Created supplier assignment
|
||||
"net": 1,
|
||||
"taxId": 1,
|
||||
"taxRate": 1
|
||||
}
|
||||
},
|
||||
"incoming": [
|
||||
{
|
||||
"date": "2026-08-10T00:00:00.000Z",
|
||||
"amount": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -33,7 +33,13 @@ List of suppliers linked to the article
|
||||
"net": 1,
|
||||
"taxId": 1,
|
||||
"taxRate": 1
|
||||
}
|
||||
},
|
||||
"incoming": [
|
||||
{
|
||||
"date": "2026-08-10T00:00:00.000Z",
|
||||
"amount": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -59,7 +59,13 @@ Updated supplier assignment
|
||||
"net": 1,
|
||||
"taxId": 1,
|
||||
"taxRate": 1
|
||||
}
|
||||
},
|
||||
"incoming": [
|
||||
{
|
||||
"date": "2026-08-10T00:00:00.000Z",
|
||||
"amount": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -36,84 +36,11 @@ Patches article fields. At least one of `name`, `unitamount`, `unitSi` required.
|
||||
|
||||
On success, emits SSE signal: `articles` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
## Response `204`
|
||||
|
||||
Updated article detail
|
||||
Updated
|
||||
|
||||
```json
|
||||
{
|
||||
"article": {
|
||||
"id": 1,
|
||||
"sku": "…",
|
||||
"name": "…",
|
||||
"slug": "…",
|
||||
"desc": "…",
|
||||
"seo": "…",
|
||||
"track_stock": true,
|
||||
"unitamount": 1,
|
||||
"weight": 1,
|
||||
"unit": {
|
||||
"si": "…",
|
||||
"basesi": "…",
|
||||
"basesifactor": 1,
|
||||
"symbol": "…",
|
||||
"name": "…"
|
||||
},
|
||||
"brand": {
|
||||
"id": 1,
|
||||
"name": "…",
|
||||
"fullHash": "…",
|
||||
"thumbW": 1,
|
||||
"thumbH": 1,
|
||||
"thumbHash": "…"
|
||||
},
|
||||
"categoryIds": [
|
||||
1
|
||||
],
|
||||
"photos": [
|
||||
{
|
||||
"sort": 1,
|
||||
"fullHash": "…",
|
||||
"fullW": 1,
|
||||
"fullH": 1,
|
||||
"fullSize": 1,
|
||||
"thumbW": 1,
|
||||
"thumbH": 1,
|
||||
"thumbHash": "…"
|
||||
}
|
||||
],
|
||||
"eans": [
|
||||
"…"
|
||||
],
|
||||
"prices": [
|
||||
{
|
||||
"minmultiplier": 1,
|
||||
"net": 1,
|
||||
"taxRate": 1,
|
||||
"customergroupId": 1
|
||||
}
|
||||
],
|
||||
"suppliers": [
|
||||
{
|
||||
"id": 1,
|
||||
"articleId": 1,
|
||||
"entityId": 1,
|
||||
"supplierName": "…",
|
||||
"sku": "…",
|
||||
"pu": 1,
|
||||
"stock": 1,
|
||||
"sort": 1,
|
||||
"priceId": 1,
|
||||
"price": {
|
||||
"net": 1,
|
||||
"taxId": 1,
|
||||
"taxRate": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
_No content_
|
||||
|
||||
## Errors
|
||||
|
||||
|
||||
@@ -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`._
|
||||
37
docs/api/routes/carrier.get.md
Normal file
37
docs/api/routes/carrier.get.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# `GET /carrier`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
List carriers
|
||||
|
||||
Lists carriers for the selected company, ordered by sort and name.
|
||||
|
||||
## Response `200`
|
||||
|
||||
List of carriers
|
||||
|
||||
```json
|
||||
{
|
||||
"carriers": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "…",
|
||||
"sort": 1,
|
||||
"hasPackages": true,
|
||||
"isReverse": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | No company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
60
docs/api/routes/carrier.post.md
Normal file
60
docs/api/routes/carrier.post.md
Normal file
@@ -0,0 +1,60 @@
|
||||
# `POST /carrier`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Create carrier
|
||||
|
||||
Creates a new carrier for the selected company.
|
||||
Sort order will be automatically appended if omitted.
|
||||
|
||||
|
||||
## Body (JSON)
|
||||
|
||||
| Field | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `name` | yes | string | |
|
||||
| `sort` | no | integer | Optional sort order |
|
||||
| `hasPackages` | no | boolean | |
|
||||
| `isReverse` | no | boolean | |
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "…",
|
||||
"sort": 1,
|
||||
"hasPackages": true,
|
||||
"isReverse": true
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `carrier` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `201`
|
||||
|
||||
Created carrier
|
||||
|
||||
```json
|
||||
{
|
||||
"carrier": {
|
||||
"id": 1,
|
||||
"name": "…",
|
||||
"sort": 1,
|
||||
"hasPackages": true,
|
||||
"isReverse": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Invalid input or missing fields — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized — `{"error":"…"}` |
|
||||
| 409 | Carrier already exists — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
37
docs/api/routes/carrier/_id.delete.md
Normal file
37
docs/api/routes/carrier/_id.delete.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# `DELETE /carrier/{id}`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Delete carrier
|
||||
|
||||
Deletes a carrier for the selected company, unless referenced in shipping.
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | Carrier ID |
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `carrier` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `204`
|
||||
|
||||
Carrier deleted
|
||||
|
||||
_No content_
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Invalid ID or no company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized — `{"error":"…"}` |
|
||||
| 404 | Carrier not found — `{"error":"…"}` |
|
||||
| 409 | Carrier in use in shipping — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
42
docs/api/routes/carrier/_id.get.md
Normal file
42
docs/api/routes/carrier/_id.get.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# `GET /carrier/{id}`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Get carrier by ID
|
||||
|
||||
Retrieves a single carrier for the authenticated user's selected company.
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | Carrier ID |
|
||||
|
||||
## Response `200`
|
||||
|
||||
Carrier details
|
||||
|
||||
```json
|
||||
{
|
||||
"carrier": {
|
||||
"id": 1,
|
||||
"name": "…",
|
||||
"sort": 1,
|
||||
"hasPackages": true,
|
||||
"isReverse": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Invalid ID or no company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized — `{"error":"…"}` |
|
||||
| 404 | Carrier not found — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
65
docs/api/routes/carrier/_id.patch.md
Normal file
65
docs/api/routes/carrier/_id.patch.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# `PATCH /carrier/{id}`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Update carrier
|
||||
|
||||
Updates carrier name, sort order, hasPackages, and/or isReverse for the selected company.
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | Carrier ID |
|
||||
|
||||
## Body (JSON)
|
||||
|
||||
| Field | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `name` | no | string | |
|
||||
| `sort` | no | integer | |
|
||||
| `hasPackages` | no | boolean | |
|
||||
| `isReverse` | no | boolean | |
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "…",
|
||||
"sort": 1,
|
||||
"hasPackages": true,
|
||||
"isReverse": true
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `carrier` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
|
||||
Updated carrier
|
||||
|
||||
```json
|
||||
{
|
||||
"carrier": {
|
||||
"id": 1,
|
||||
"name": "…",
|
||||
"sort": 1,
|
||||
"hasPackages": true,
|
||||
"isReverse": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Invalid input or missing fields — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized — `{"error":"…"}` |
|
||||
| 404 | Carrier not found — `{"error":"…"}` |
|
||||
| 409 | Carrier already exists — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
51
docs/api/routes/carrier/order.md
Normal file
51
docs/api/routes/carrier/order.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# `PUT /carrier/order`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Reorder carriers
|
||||
|
||||
Reorders carriers for the selected company.
|
||||
`carrierIds` must include all existing carrier IDs exactly once.
|
||||
|
||||
|
||||
## Body (JSON)
|
||||
|
||||
| Field | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `carrierIds` | yes | integer[] | |
|
||||
|
||||
```json
|
||||
{
|
||||
"carrierIds": [
|
||||
1
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `carrier` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
|
||||
Applied carrier order
|
||||
|
||||
```json
|
||||
{
|
||||
"carrierIds": [
|
||||
1
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Invalid carrier order or no company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized — `{"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).
|
||||
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
|
||||
@@ -36,6 +42,9 @@ Articles list
|
||||
"thumbW": 1,
|
||||
"thumbH": 1,
|
||||
"thumbHash": "…",
|
||||
"smallThumbW": 1,
|
||||
"smallThumbH": 1,
|
||||
"smallThumbBinary": "…",
|
||||
"brand": {
|
||||
"id": 1,
|
||||
"name": "…",
|
||||
@@ -43,7 +52,25 @@ Articles list
|
||||
"thumbW": 1,
|
||||
"thumbH": 1,
|
||||
"thumbHash": "…"
|
||||
}
|
||||
},
|
||||
"articlewarehousesummary": [
|
||||
{
|
||||
"id": 1,
|
||||
"articleId": 1,
|
||||
"article_id": 1,
|
||||
"warehouseId": 1,
|
||||
"warehouse_id": 1,
|
||||
"warehouseName": "…",
|
||||
"stock": 1
|
||||
}
|
||||
],
|
||||
"warehouses": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "…",
|
||||
"stock": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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,7 +60,7 @@ Created; selected company updated
|
||||
|--------|-------------|
|
||||
| 400 | Validation error — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 409 | Company name not available — `{"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
|
||||
|
||||
33
docs/api/routes/company/export.md
Normal file
33
docs/api/routes/company/export.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# `GET /company/export`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Export company catalog as zip archive (SSE)
|
||||
|
||||
Exports full company catalog data (categories hierarchy, articles, variants, brands, pictures)
|
||||
into a round-trip compatible .zip archive matching the format of `/company/import`.
|
||||
Streams progress events via Server-Sent Events (`text/event-stream`), followed by base64-encoded
|
||||
binary chunks in `chunk` events and a final `done` event.
|
||||
|
||||
|
||||
## Query parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `stream` | no | string | Force SSE stream mode (`1`) or direct binary download (`0`) |
|
||||
|
||||
## Response `200`
|
||||
|
||||
Export progress stream (`text/event-stream`) with binary chunks, or raw ZIP file
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Bad request (no company selected) — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 500 | Server error — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
23
docs/api/routes/company/export.post.md
Normal file
23
docs/api/routes/company/export.post.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# `POST /company/export`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Export company catalog as zip archive (SSE)
|
||||
|
||||
POST variant of `/company/export` with identical SSE streaming semantics.
|
||||
|
||||
## Response `200`
|
||||
|
||||
Export progress stream (`text/event-stream`) with binary chunks, or raw ZIP file
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Bad request (no company selected) — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 500 | Server error — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -56,7 +61,6 @@ Updated
|
||||
| 400 | Validation error — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 404 | Company not found — `{"error":"…"}` |
|
||||
| 409 | Company name not available — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
|
||||
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`._
|
||||
38
docs/api/routes/delivery/_id/file/_fileId.delete.md
Normal file
38
docs/api/routes/delivery/_id/file/_fileId.delete.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# `DELETE /delivery/{id}/file/{fileId}`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Delete delivery file attachment
|
||||
|
||||
Removes a file attachment from the delivery and deletes the underlying file.
|
||||
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | Delivery ID |
|
||||
| `fileId` | yes | integer | File ID or attachment ID |
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `delivery` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `204`
|
||||
|
||||
Attachment deleted
|
||||
|
||||
_No content_
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Invalid parameters or no company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized — `{"error":"…"}` |
|
||||
| 404 | Delivery or attachment not found — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
58
docs/api/routes/delivery/_id/pdf.md
Normal file
58
docs/api/routes/delivery/_id/pdf.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# `POST /delivery/{id}/pdf`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Generate and attach delivery note PDF (goods receipt)
|
||||
|
||||
Generates an A4 PDF document for the goods receipt / delivery note with line items and quantities.
|
||||
Attaches the PDF as a `manifestattachment` to the delivery.
|
||||
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | Delivery ID |
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `delivery` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `201`
|
||||
|
||||
PDF generated and attached to delivery
|
||||
|
||||
```json
|
||||
{
|
||||
"attachment": {
|
||||
"id": 1,
|
||||
"manifestId": 1,
|
||||
"fileId": 1,
|
||||
"sort": 1,
|
||||
"hash": "…",
|
||||
"mimetype": "…",
|
||||
"name": "…",
|
||||
"size": 1,
|
||||
"created": "2026-08-10T00:00:00.000Z",
|
||||
"modified": "2026-08-10T00:00:00.000Z",
|
||||
"skeledash": "…",
|
||||
"thumbx": 1,
|
||||
"thumby": 1,
|
||||
"meta": {}
|
||||
},
|
||||
"fileUrl": "/delivery/1/file/5"
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Invalid ID or no company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized — `{"error":"…"}` |
|
||||
| 404 | Delivery not found — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
@@ -17,7 +17,7 @@ The manifest `number` is allocated automatically via
|
||||
|-------|----------|------|-------------|
|
||||
| `externalNumber` | yes | string | User-supplied reference number |
|
||||
| `date` | yes | string | |
|
||||
| `supplierId` | no | integer | |
|
||||
| `supplierId` | yes | integer | |
|
||||
| `lines` | yes | DeliveryLineInput[] | |
|
||||
| `files` | no | DeliveryFileInput[] | Attached documents (pdf or txt) stored with the delivery and returned in `files` on every delivery response. Thumbnails (AVIF) are generated server-side. |
|
||||
|
||||
@@ -97,7 +97,7 @@ Created delivery
|
||||
"size": 1,
|
||||
"created": "2026-08-10T00:00:00.000Z",
|
||||
"modified": "2026-08-10T00:00:00.000Z",
|
||||
"thumbavif": "…",
|
||||
"skeledash": "…",
|
||||
"thumbx": 1,
|
||||
"thumby": 1,
|
||||
"meta": {}
|
||||
|
||||
@@ -55,7 +55,7 @@ Delivery
|
||||
"size": 1,
|
||||
"created": "2026-08-10T00:00:00.000Z",
|
||||
"modified": "2026-08-10T00:00:00.000Z",
|
||||
"thumbavif": "…",
|
||||
"skeledash": "…",
|
||||
"thumbx": 1,
|
||||
"thumby": 1,
|
||||
"meta": {}
|
||||
|
||||
@@ -5,12 +5,23 @@ Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
List deliveries
|
||||
|
||||
Lists goods receipts (`manifest` rows with `type = 'delivery'`)
|
||||
for the authenticated user's selected company.
|
||||
for the authenticated user's selected company. Supports pagination and filtering.
|
||||
|
||||
|
||||
## Query parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `offset` | no | integer | Number of records to skip |
|
||||
| `limit` | no | integer | Number of records to return (1-1000) |
|
||||
| `search` | no | string | Substring match for delivery number, external number, or supplier name |
|
||||
| `onlyUnbooked` | no | boolean | When true, returns only deliveries with unbooked stock items |
|
||||
| `supplierId` | no | integer | Filter by supplier entity id |
|
||||
| `seekMonths` | no | integer | Negative integer cutoff months ago (e.g. -1) |
|
||||
|
||||
## Response `200`
|
||||
|
||||
Delivery list
|
||||
Delivery list (windowed when pagination/filters are used)
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -28,7 +39,11 @@ Delivery list
|
||||
"completelyOnLedgerPositions": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
],
|
||||
"total": 1,
|
||||
"unfilteredTotal": 1,
|
||||
"offset": 1,
|
||||
"limit": 1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
# `POST /delivery/parse`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Parse document (SSE)
|
||||
|
||||
Accepts an invoice or delivery note as PDF or text file
|
||||
(`multipart/form-data`, field `file`) and streams extraction results as
|
||||
Server-Sent Events until parsing is complete.
|
||||
|
||||
PDFs are read via `pdftotext -layout`; text files are decoded as UTF-8.
|
||||
Pages are separated by the form feed character (`\f`). If no form feed
|
||||
is present, the input is treated as a single page.
|
||||
|
||||
The extracted pages are fed to an LLM (OpenRouter) which fills a structured
|
||||
manifest of header data and line items. The OpenRouter API key is read from
|
||||
the authenticated user's company setting `keys.openrouter` (or the server's
|
||||
`OPENROUTER_FREE_KEY` if not configured); the endpoint
|
||||
returns `400` if the key is not configured.
|
||||
|
||||
The stream ends after the final `result` event (or an `error` event on failure).
|
||||
|
||||
|
||||
## Body (`multipart/form-data`)
|
||||
|
||||
| Field | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `file` | yes | file | Document to parse (max 50 MB, application/pdf or text file) |
|
||||
|
||||
## SSE Events
|
||||
|
||||
The response is a `text/event-stream`. Events are emitted in order until the stream closes.
|
||||
|
||||
| Event | Description | Payload |
|
||||
|-------|-------------|---------|
|
||||
| `status` | Document parse confirmation and LLM status messages | `{ "message": "…" }` |
|
||||
| `llm_call` | Fired before each LLM request | `{ "model": "…", "promptSize": 0, "messages": 0 }` |
|
||||
| `tool_call` | Fired when the output_manifest tool is invoked | `{ "name": "output_manifest" }` |
|
||||
| `usage` | Token usage after each LLM response | `{ "input": 0, "cached": 0, "output": 0, "cost": 0 }` |
|
||||
| `progress` | Intermediate accumulated extraction state (basedata / notes / items) | `ManifestResult` |
|
||||
| `result` | Final accumulated extraction — emitted just before the stream closes | `ManifestResult` |
|
||||
| `error` | Emitted on document parse or LLM failure; stream closes immediately after | `{ "message": "…" }` |
|
||||
|
||||
## Response `200`
|
||||
|
||||
`text/event-stream` — emits `status`, `llm_call`, `tool_call`, `usage`,
|
||||
`progress`, `result` (and `error` on failure). See SSE Events table below.
|
||||
|
||||
**ManifestResult shape** (used by `progress` and `result`):
|
||||
|
||||
```json
|
||||
{
|
||||
"basedata": {
|
||||
"date": "2026-01-15",
|
||||
"lieferant_id": 42,
|
||||
"lieferantName": "Muster GmbH",
|
||||
"manifestNr": "LS-2026-001",
|
||||
"manifestType": "lieferschein"
|
||||
},
|
||||
"notes": ["Pos. 3: VPE-Angabe fehlte, Standardwert 1 angenommen."],
|
||||
"items": {
|
||||
"pagesFrom": 1,
|
||||
"pagesTo": 2,
|
||||
"items": [
|
||||
{
|
||||
"position": 1,
|
||||
"count": 10,
|
||||
"vpe": 1,
|
||||
"unit": "Stk.",
|
||||
"articleName": "Einhängesieb Stahl",
|
||||
"liefArtNr": "ES-100",
|
||||
"mwst": "19",
|
||||
"eknetto": 450,
|
||||
"page": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | No file uploaded, unsupported file type, or OpenRouter key not configured — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
@@ -84,7 +84,7 @@ Updated delivery
|
||||
"size": 1,
|
||||
"created": "2026-08-10T00:00:00.000Z",
|
||||
"modified": "2026-08-10T00:00:00.000Z",
|
||||
"thumbavif": "…",
|
||||
"skeledash": "…",
|
||||
"thumbx": 1,
|
||||
"thumby": 1,
|
||||
"meta": {}
|
||||
|
||||
@@ -4,48 +4,58 @@ 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 |
|
||||
| `brand` | `{ sender, brandId }` | `POST /brand`, `PATCH /brand/{id}`, `DELETE /brand/{id}`, `POST /brand/{id}/image`, `DELETE /brand/{id}/image` |
|
||||
| `draft` | `{ sender, action, name, content }` | Draft update on `drafts/quote`, `drafts/order`, `drafts/delivery` (`sender` echoes the caller's `x-client-id`) |
|
||||
| `draft:request` | `{ requestId, action, name, target, sender }` | Server request to frontend to read a draft or list drafts |
|
||||
|
||||
The `brand` payload is `{ sender, brandId }`: `sender` echoes the
|
||||
caller's `x-client-id` header (empty string if absent) so the sender
|
||||
@@ -62,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":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
@@ -4,11 +4,11 @@ Public. No cookie required.
|
||||
|
||||
Database health check
|
||||
|
||||
Verifies the database client can establish a connection.
|
||||
Verifies database connectivity and transaction execution by updating a healthcheck sequence.
|
||||
|
||||
## Response `200`
|
||||
|
||||
Database reachable
|
||||
Database reachable and healthy
|
||||
|
||||
```json
|
||||
{
|
||||
|
||||
51
docs/api/routes/health/latency.md
Normal file
51
docs/api/routes/health/latency.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# `GET /health/latency`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Health latency history
|
||||
|
||||
Returns the database healthcheck latency (ms), each series oldest first with unix-ms timestamps. By default (`range=3h`) only `raw` is returned, the per-minute samples of the last 3 hours. With `range=all` the 30-day `avg` and `max` series (30-minute aggregates over the last 4 hours of samples) are included as well. Requires a valid JWT; no company selection needed.
|
||||
|
||||
## Query parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `range` | no | string | `3h` (default) returns only the per-minute samples of the last 3 hours; `all` also includes the 30-day avg and max series. |
|
||||
|
||||
## Response `200`
|
||||
|
||||
Latency series
|
||||
|
||||
```json
|
||||
{
|
||||
"raw": [
|
||||
{
|
||||
"timestamp": 1,
|
||||
"value": 1
|
||||
}
|
||||
],
|
||||
"avg": [
|
||||
{
|
||||
"timestamp": 1,
|
||||
"value": 1
|
||||
}
|
||||
],
|
||||
"max": [
|
||||
{
|
||||
"timestamp": 1,
|
||||
"value": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 401 | Unauthorized |
|
||||
| 500 | Redis read failed |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
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`._
|
||||
@@ -1,63 +0,0 @@
|
||||
# `POST /ledger`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Add ledger entry
|
||||
|
||||
Appends a new entry to the append-only ledger table.
|
||||
`hash_version` is fixed to 1. `prev_hash` is cryptographically chained:
|
||||
for the genesis row it defaults to `TODO_TSE_BASED_INITHASH`, and for subsequent rows
|
||||
it is the SHA-512 hex hash of the canonical JSON representation of the previous highest-id entry.
|
||||
Requires authentication and membership in the company owning the referenced manifest article.
|
||||
|
||||
|
||||
## Body (JSON)
|
||||
|
||||
| Field | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `manifestarticle_id` | yes | integer | References manifestarticle.id |
|
||||
| `transaction_type` | yes | string | Transaction identifier / type (max 100 chars) |
|
||||
| `amount` | yes | number | Movement amount |
|
||||
| `transaction_text` | yes | string | Transaction memo / details |
|
||||
|
||||
```json
|
||||
{
|
||||
"manifestarticle_id": 1,
|
||||
"transaction_type": "…",
|
||||
"amount": 1,
|
||||
"transaction_text": "…"
|
||||
}
|
||||
```
|
||||
|
||||
## Response `201`
|
||||
|
||||
Ledger entry added successfully
|
||||
|
||||
```json
|
||||
{
|
||||
"ledger": {
|
||||
"id": 1,
|
||||
"manifestarticle_id": 1,
|
||||
"transaction_type": "…",
|
||||
"amount": 1,
|
||||
"transaction_text": "…",
|
||||
"hash_version": 1,
|
||||
"prev_hash": "…",
|
||||
"sku": "…",
|
||||
"created_at": "2026-08-10T00:00:00.000Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Invalid ledger entry or no company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized — `{"error":"…"}` |
|
||||
| 404 | Manifest article or company not found — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
54
docs/api/routes/ledger/history.md
Normal file
54
docs/api/routes/ledger/history.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# `GET /ledger/history`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Query company-wide ledger history
|
||||
|
||||
Queries ledger entries across all articles for the authenticated user's selected company.
|
||||
Supports pagination, search filter, and date cutoff via `seekMonths`.
|
||||
|
||||
|
||||
## Query parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `offset` | no | integer | Paging offset |
|
||||
| `limit` | no | integer | Page size |
|
||||
| `search` | no | string | Optional search filter across SKU, article name, manifest number, external number, transaction type, and transaction text |
|
||||
| `seekMonths` | no | integer | Negative integer cutoff months ago (e.g. -1) |
|
||||
|
||||
## Response `200`
|
||||
|
||||
Paged ledger history list
|
||||
|
||||
```json
|
||||
{
|
||||
"ledger": [
|
||||
{
|
||||
"id": 1,
|
||||
"date": "2026-08-10T00:00:00.000Z",
|
||||
"sku": "…",
|
||||
"name": "…",
|
||||
"transaction_type": "…",
|
||||
"transaction_text": "…",
|
||||
"amount": 1
|
||||
}
|
||||
],
|
||||
"total": 1,
|
||||
"unfilteredTotal": 1,
|
||||
"offset": 1,
|
||||
"limit": 1
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Validation error or no company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
@@ -21,7 +21,7 @@ List of conversations
|
||||
"created_at": "…",
|
||||
"updated_at": "…",
|
||||
"state": "idle",
|
||||
"started_by": "…",
|
||||
"started_by": 1,
|
||||
"first_message": "…"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -38,7 +38,7 @@ Created conversation
|
||||
"created_at": "…",
|
||||
"updated_at": "…",
|
||||
"state": "idle",
|
||||
"started_by": "…",
|
||||
"started_by": 1,
|
||||
"first_message": "…"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ Conversation details
|
||||
"created_at": "…",
|
||||
"updated_at": "…",
|
||||
"state": "idle",
|
||||
"started_by": "…",
|
||||
"started_by": 1,
|
||||
"first_message": "…"
|
||||
}
|
||||
}
|
||||
|
||||
38
docs/api/routes/order/_id/file/_fileId.delete.md
Normal file
38
docs/api/routes/order/_id/file/_fileId.delete.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# `DELETE /order/{id}/file/{fileId}`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Delete order file attachment
|
||||
|
||||
Removes a file attachment from the order and deletes the underlying file.
|
||||
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | Order ID |
|
||||
| `fileId` | yes | integer | File ID or attachment ID |
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `order` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `204`
|
||||
|
||||
Attachment deleted
|
||||
|
||||
_No content_
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Invalid parameters or no company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized — `{"error":"…"}` |
|
||||
| 404 | Order or attachment not found — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
38
docs/api/routes/order/_id/file/_fileId.get.md
Normal file
38
docs/api/routes/order/_id/file/_fileId.get.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# `GET /order/{id}/file/{fileId}`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Get order attachment file content
|
||||
|
||||
Returns the full binary content of an attached file (e.g. order PDF)
|
||||
for the specified order. Supports HTTP caching via ETag (SHA-256 hash) and 304 Not Modified.
|
||||
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | Order ID |
|
||||
| `fileId` | yes | integer | File ID or attachment ID |
|
||||
|
||||
## Query parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `download` | no | boolean | When true, sets Content-Disposition to attachment instead of inline |
|
||||
|
||||
## Response `200`
|
||||
|
||||
Binary file content
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 304 | Not modified |
|
||||
| 400 | Invalid ID or no company selected — `{"error":"…"}` |
|
||||
| 404 | Order or file not found — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
58
docs/api/routes/order/_id/pdf.md
Normal file
58
docs/api/routes/order/_id/pdf.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# `POST /order/{id}/pdf`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Generate and attach order PDF
|
||||
|
||||
Generates an A4 PDF document for the sales order with line items, prices, and tax breakdown.
|
||||
Attaches the PDF as a `manifestattachment` to the order so it can be printed or archived.
|
||||
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | Order ID |
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `order` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `201`
|
||||
|
||||
PDF generated and attached to order
|
||||
|
||||
```json
|
||||
{
|
||||
"attachment": {
|
||||
"id": 1,
|
||||
"manifestId": 1,
|
||||
"fileId": 1,
|
||||
"sort": 1,
|
||||
"hash": "…",
|
||||
"mimetype": "…",
|
||||
"name": "…",
|
||||
"size": 1,
|
||||
"created": "2026-08-10T00:00:00.000Z",
|
||||
"modified": "2026-08-10T00:00:00.000Z",
|
||||
"skeledash": "…",
|
||||
"thumbx": 1,
|
||||
"thumby": 1,
|
||||
"meta": {}
|
||||
},
|
||||
"fileUrl": "/order/1/file/5"
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Invalid ID or no company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized — `{"error":"…"}` |
|
||||
| 404 | Order not found — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
@@ -39,7 +39,8 @@ List of shipments
|
||||
"net": 1,
|
||||
"rebate": 1,
|
||||
"taxrate": 1,
|
||||
"comment": "…"
|
||||
"comment": "…",
|
||||
"shippable": true
|
||||
}
|
||||
],
|
||||
"shippings": [
|
||||
@@ -48,11 +49,31 @@ List of shipments
|
||||
"manifestId": 1,
|
||||
"number": "…",
|
||||
"trackingCode": "…",
|
||||
"carrierId": 1,
|
||||
"carrier": "…",
|
||||
"type": "…",
|
||||
"state": "…"
|
||||
}
|
||||
]
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"id": 1,
|
||||
"manifestId": 1,
|
||||
"fileId": 1,
|
||||
"sort": 1,
|
||||
"hash": "…",
|
||||
"mimetype": "…",
|
||||
"name": "…",
|
||||
"size": 1,
|
||||
"created": "2026-08-10T00:00:00.000Z",
|
||||
"modified": "2026-08-10T00:00:00.000Z",
|
||||
"skeledash": "…",
|
||||
"thumbx": 1,
|
||||
"thumby": 1,
|
||||
"meta": {}
|
||||
}
|
||||
],
|
||||
"state": "new"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -4,9 +4,13 @@ Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Create shipment for an order
|
||||
|
||||
Creates a new partial or full shipment manifest for the order.
|
||||
Validates that article positions belong to the order and cumulative shipped quantities
|
||||
do not exceed ordered quantities.
|
||||
Creates a new shipment manifest (Lieferschein) for an order containing one, some, or all items from the order.
|
||||
If `lines` is omitted or empty, all remaining unshipped items from the order are included automatically.
|
||||
On individual line items, `amount` is optional and defaults to the remaining unshipped quantity for that article.
|
||||
Auto-assigns the shipment number formatted as `<order_number><shipment_prefix><index>`, e.g. `AUF-000001-L-1`.
|
||||
Automatically books shipment lines out on the ledger and deducts warehouse stock for stock-tracked articles.
|
||||
Updates the materialized `ordersummary` table (`shipped_quantity`, `is_shipped`) and emits SSE events
|
||||
(`order`, `shipment`, `stock`, `ledger`, `articles`) so that inventory and summaries are rerendered in real time.
|
||||
|
||||
|
||||
## Path parameters
|
||||
@@ -19,11 +23,13 @@ do not exceed ordered quantities.
|
||||
|
||||
| Field | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `date` | no | string | |
|
||||
| `externalNumber` | no | string | |
|
||||
| `lines` | yes | object[] | |
|
||||
| `lines[].sku` | yes | string | |
|
||||
| `lines[].amount` | yes | number | |
|
||||
| `date` | no | string | Optional shipment date (defaults to current date) |
|
||||
| `warehouseId` | no | integer | Optional target warehouse ID to deduct stock from (defaults to company default warehouse) |
|
||||
| `externalNumber` | no | string | Optional external delivery note reference (defaults to order.externalNumber or order.number) |
|
||||
| `lines` | yes | object[] | Positions to ship |
|
||||
| `lines[].sku` | no | string | Article SKU (omit for SKU-less order lines) |
|
||||
| `lines[].orderLineId` | no | integer | Order line id (`lines[].id` of the order); required for SKU-less lines, ignored when `sku` is given |
|
||||
| `lines[].amount` | no | number | Quantity to ship. Defaults to remaining unshipped quantity for this SKU. |
|
||||
| `lines[].name` | no | string | |
|
||||
| `lines[].pu` | no | number | |
|
||||
| `lines[].net` | no | number | |
|
||||
@@ -34,10 +40,12 @@ do not exceed ordered quantities.
|
||||
```json
|
||||
{
|
||||
"date": "2026-08-10",
|
||||
"warehouseId": 1,
|
||||
"externalNumber": "…",
|
||||
"lines": [
|
||||
{
|
||||
"sku": "…",
|
||||
"orderLineId": 1,
|
||||
"amount": 1,
|
||||
"name": "…",
|
||||
"pu": 1,
|
||||
@@ -76,7 +84,8 @@ Created shipment
|
||||
"net": 1,
|
||||
"rebate": 1,
|
||||
"taxrate": 1,
|
||||
"comment": "…"
|
||||
"comment": "…",
|
||||
"shippable": true
|
||||
}
|
||||
],
|
||||
"shippings": [
|
||||
@@ -85,11 +94,31 @@ Created shipment
|
||||
"manifestId": 1,
|
||||
"number": "…",
|
||||
"trackingCode": "…",
|
||||
"carrierId": 1,
|
||||
"carrier": "…",
|
||||
"type": "…",
|
||||
"state": "…"
|
||||
}
|
||||
]
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"id": 1,
|
||||
"manifestId": 1,
|
||||
"fileId": 1,
|
||||
"sort": 1,
|
||||
"hash": "…",
|
||||
"mimetype": "…",
|
||||
"name": "…",
|
||||
"size": 1,
|
||||
"created": "2026-08-10T00:00:00.000Z",
|
||||
"modified": "2026-08-10T00:00:00.000Z",
|
||||
"skeledash": "…",
|
||||
"thumbx": 1,
|
||||
"thumby": 1,
|
||||
"meta": {}
|
||||
}
|
||||
],
|
||||
"state": "new"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -98,10 +127,10 @@ Created shipment
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Validation error or article not in order — `{"error":"…"}` |
|
||||
| 400 | Validation error, article not in order, or article not shippable — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 404 | Order not found — `{"error":"…"}` |
|
||||
| 409 | Cumulative shipment amount exceeds ordered amount — `{"error":"…"}` |
|
||||
| 409 | Cumulative shipment amount exceeds ordered amount, or insufficient stock — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ List of shippings
|
||||
"manifestId": 1,
|
||||
"number": "…",
|
||||
"trackingCode": "…",
|
||||
"carrierId": 1,
|
||||
"carrier": "…",
|
||||
"type": "…",
|
||||
"state": "…"
|
||||
|
||||
@@ -19,14 +19,18 @@ If `state` is `shipped`, stock is adjusted via the ledger and article history is
|
||||
|
||||
| Field | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `carrierId` | yes | integer | Carrier ID |
|
||||
| `type` | yes | string | |
|
||||
| `state` | yes | string | |
|
||||
| `trackingCode` | no | string | Carrier parcel tracking code |
|
||||
| `warehouseId` | no | integer | Optional warehouse ID for stock deduction when state is shipped |
|
||||
|
||||
```json
|
||||
{
|
||||
"carrierId": 1,
|
||||
"type": "…",
|
||||
"state": "…",
|
||||
"trackingCode": "…",
|
||||
"warehouseId": 1
|
||||
}
|
||||
```
|
||||
@@ -42,6 +46,7 @@ Created shipping
|
||||
"manifestId": 1,
|
||||
"number": "…",
|
||||
"trackingCode": "…",
|
||||
"carrierId": 1,
|
||||
"carrier": "…",
|
||||
"type": "…",
|
||||
"state": "…"
|
||||
|
||||
@@ -6,8 +6,8 @@ Create order
|
||||
|
||||
Creates a sales order with header and lines in one transaction.
|
||||
`date` is the document date (expected delivery).
|
||||
`entityId` must be a company customer (not Lieferanten), or null.
|
||||
Each line requires `sku` or `name`, `amount`, `net`, and `taxrate` (rate); `pu` defaults to `1`; `rebate` defaults to `0`.
|
||||
`entityId` must be a company customer (not Lieferanten).
|
||||
Each line requires `sku` or `name`, `amount`, `net`, and `taxrate` (rate); `pu` defaults to `1`; `rebate` defaults to `0`; `shippable` defaults to `true` (`false` = not shippable, excluded from order completeness).
|
||||
|
||||
|
||||
## Body (JSON)
|
||||
@@ -16,7 +16,8 @@ Each line requires `sku` or `name`, `amount`, `net`, and `taxrate` (rate); `pu`
|
||||
|-------|----------|------|-------------|
|
||||
| `number` | yes | string | |
|
||||
| `date` | yes | string | Document date / expected delivery |
|
||||
| `entityId` | no | integer | Customer entity (manifest.entity_id) |
|
||||
| `entityId` | yes | integer | Customer entity (manifest.entity_id) |
|
||||
| `externalNumber` | no | string | External customer reference number (manifest.external_number) |
|
||||
| `lines` | yes | ManifestLineInput[] | |
|
||||
|
||||
```json
|
||||
@@ -48,6 +49,7 @@ Created order
|
||||
"number": "…",
|
||||
"type": "order",
|
||||
"entityId": 1,
|
||||
"externalNumber": "…",
|
||||
"date": "2026-08-10T00:00:00.000Z",
|
||||
"createdAt": "2026-08-10T00:00:00.000Z",
|
||||
"lines": [
|
||||
@@ -60,7 +62,8 @@ Created order
|
||||
"net": 1,
|
||||
"rebate": 1,
|
||||
"taxrate": 1,
|
||||
"comment": "…"
|
||||
"comment": "…",
|
||||
"shippable": true
|
||||
}
|
||||
],
|
||||
"shipping": {
|
||||
@@ -68,6 +71,7 @@ Created order
|
||||
"manifestId": 1,
|
||||
"number": "…",
|
||||
"trackingCode": "…",
|
||||
"carrierId": 1,
|
||||
"carrier": "…",
|
||||
"type": "…",
|
||||
"state": "…"
|
||||
@@ -78,6 +82,7 @@ Created order
|
||||
"manifestId": 1,
|
||||
"number": "…",
|
||||
"trackingCode": "…",
|
||||
"carrierId": 1,
|
||||
"carrier": "…",
|
||||
"type": "…",
|
||||
"state": "…"
|
||||
@@ -127,7 +132,8 @@ Created order
|
||||
"net": 1,
|
||||
"rebate": 1,
|
||||
"taxrate": 1,
|
||||
"comment": "…"
|
||||
"comment": "…",
|
||||
"shippable": true
|
||||
}
|
||||
],
|
||||
"shippings": [
|
||||
@@ -136,11 +142,49 @@ Created order
|
||||
"manifestId": 1,
|
||||
"number": "…",
|
||||
"trackingCode": "…",
|
||||
"carrierId": 1,
|
||||
"carrier": "…",
|
||||
"type": "…",
|
||||
"state": "…"
|
||||
}
|
||||
]
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"id": 1,
|
||||
"manifestId": 1,
|
||||
"fileId": 1,
|
||||
"sort": 1,
|
||||
"hash": "…",
|
||||
"mimetype": "…",
|
||||
"name": "…",
|
||||
"size": 1,
|
||||
"created": "2026-08-10T00:00:00.000Z",
|
||||
"modified": "2026-08-10T00:00:00.000Z",
|
||||
"skeledash": "…",
|
||||
"thumbx": 1,
|
||||
"thumby": 1,
|
||||
"meta": {}
|
||||
}
|
||||
],
|
||||
"state": "new"
|
||||
}
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"id": 1,
|
||||
"manifestId": 1,
|
||||
"fileId": 1,
|
||||
"sort": 1,
|
||||
"hash": "…",
|
||||
"mimetype": "…",
|
||||
"name": "…",
|
||||
"size": 1,
|
||||
"created": "2026-08-10T00:00:00.000Z",
|
||||
"modified": "2026-08-10T00:00:00.000Z",
|
||||
"skeledash": "…",
|
||||
"thumbx": 1,
|
||||
"thumby": 1,
|
||||
"meta": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ Order
|
||||
"number": "…",
|
||||
"type": "order",
|
||||
"entityId": 1,
|
||||
"externalNumber": "…",
|
||||
"date": "2026-08-10T00:00:00.000Z",
|
||||
"createdAt": "2026-08-10T00:00:00.000Z",
|
||||
"lines": [
|
||||
@@ -35,7 +36,8 @@ Order
|
||||
"net": 1,
|
||||
"rebate": 1,
|
||||
"taxrate": 1,
|
||||
"comment": "…"
|
||||
"comment": "…",
|
||||
"shippable": true
|
||||
}
|
||||
],
|
||||
"shipping": {
|
||||
@@ -43,6 +45,7 @@ Order
|
||||
"manifestId": 1,
|
||||
"number": "…",
|
||||
"trackingCode": "…",
|
||||
"carrierId": 1,
|
||||
"carrier": "…",
|
||||
"type": "…",
|
||||
"state": "…"
|
||||
@@ -53,6 +56,7 @@ Order
|
||||
"manifestId": 1,
|
||||
"number": "…",
|
||||
"trackingCode": "…",
|
||||
"carrierId": 1,
|
||||
"carrier": "…",
|
||||
"type": "…",
|
||||
"state": "…"
|
||||
@@ -102,7 +106,8 @@ Order
|
||||
"net": 1,
|
||||
"rebate": 1,
|
||||
"taxrate": 1,
|
||||
"comment": "…"
|
||||
"comment": "…",
|
||||
"shippable": true
|
||||
}
|
||||
],
|
||||
"shippings": [
|
||||
@@ -111,11 +116,49 @@ Order
|
||||
"manifestId": 1,
|
||||
"number": "…",
|
||||
"trackingCode": "…",
|
||||
"carrierId": 1,
|
||||
"carrier": "…",
|
||||
"type": "…",
|
||||
"state": "…"
|
||||
}
|
||||
]
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"id": 1,
|
||||
"manifestId": 1,
|
||||
"fileId": 1,
|
||||
"sort": 1,
|
||||
"hash": "…",
|
||||
"mimetype": "…",
|
||||
"name": "…",
|
||||
"size": 1,
|
||||
"created": "2026-08-10T00:00:00.000Z",
|
||||
"modified": "2026-08-10T00:00:00.000Z",
|
||||
"skeledash": "…",
|
||||
"thumbx": 1,
|
||||
"thumby": 1,
|
||||
"meta": {}
|
||||
}
|
||||
],
|
||||
"state": "new"
|
||||
}
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"id": 1,
|
||||
"manifestId": 1,
|
||||
"fileId": 1,
|
||||
"sort": 1,
|
||||
"hash": "…",
|
||||
"mimetype": "…",
|
||||
"name": "…",
|
||||
"size": 1,
|
||||
"created": "2026-08-10T00:00:00.000Z",
|
||||
"modified": "2026-08-10T00:00:00.000Z",
|
||||
"skeledash": "…",
|
||||
"thumbx": 1,
|
||||
"thumby": 1,
|
||||
"meta": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ Order list
|
||||
"number": "…",
|
||||
"type": "order",
|
||||
"entityId": 1,
|
||||
"externalNumber": "…",
|
||||
"date": "2026-08-10T00:00:00.000Z",
|
||||
"createdAt": "2026-08-10T00:00:00.000Z",
|
||||
"lines": [
|
||||
@@ -44,7 +45,8 @@ Order list
|
||||
"net": 1,
|
||||
"rebate": 1,
|
||||
"taxrate": 1,
|
||||
"comment": "…"
|
||||
"comment": "…",
|
||||
"shippable": true
|
||||
}
|
||||
],
|
||||
"shipping": {
|
||||
@@ -52,6 +54,7 @@ Order list
|
||||
"manifestId": 1,
|
||||
"number": "…",
|
||||
"trackingCode": "…",
|
||||
"carrierId": 1,
|
||||
"carrier": "…",
|
||||
"type": "…",
|
||||
"state": "…"
|
||||
@@ -62,6 +65,7 @@ Order list
|
||||
"manifestId": 1,
|
||||
"number": "…",
|
||||
"trackingCode": "…",
|
||||
"carrierId": 1,
|
||||
"carrier": "…",
|
||||
"type": "…",
|
||||
"state": "…"
|
||||
@@ -111,7 +115,8 @@ Order list
|
||||
"net": 1,
|
||||
"rebate": 1,
|
||||
"taxrate": 1,
|
||||
"comment": "…"
|
||||
"comment": "…",
|
||||
"shippable": true
|
||||
}
|
||||
],
|
||||
"shippings": [
|
||||
@@ -120,11 +125,49 @@ Order list
|
||||
"manifestId": 1,
|
||||
"number": "…",
|
||||
"trackingCode": "…",
|
||||
"carrierId": 1,
|
||||
"carrier": "…",
|
||||
"type": "…",
|
||||
"state": "…"
|
||||
}
|
||||
]
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"id": 1,
|
||||
"manifestId": 1,
|
||||
"fileId": 1,
|
||||
"sort": 1,
|
||||
"hash": "…",
|
||||
"mimetype": "…",
|
||||
"name": "…",
|
||||
"size": 1,
|
||||
"created": "2026-08-10T00:00:00.000Z",
|
||||
"modified": "2026-08-10T00:00:00.000Z",
|
||||
"skeledash": "…",
|
||||
"thumbx": 1,
|
||||
"thumby": 1,
|
||||
"meta": {}
|
||||
}
|
||||
],
|
||||
"state": "new"
|
||||
}
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"id": 1,
|
||||
"manifestId": 1,
|
||||
"fileId": 1,
|
||||
"sort": 1,
|
||||
"hash": "…",
|
||||
"mimetype": "…",
|
||||
"name": "…",
|
||||
"size": 1,
|
||||
"created": "2026-08-10T00:00:00.000Z",
|
||||
"modified": "2026-08-10T00:00:00.000Z",
|
||||
"skeledash": "…",
|
||||
"thumbx": 1,
|
||||
"thumby": 1,
|
||||
"meta": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ all lines; if omitted, leaves lines unchanged. Returns the full order.
|
||||
| `number` | no | string | |
|
||||
| `date` | no | string | Document date / expected delivery |
|
||||
| `entityId` | no | integer | |
|
||||
| `externalNumber` | no | string | External customer reference number (manifest.external_number) |
|
||||
| `lines` | no | ManifestLineInput[] | |
|
||||
|
||||
```json
|
||||
@@ -42,6 +43,7 @@ Updated order
|
||||
"number": "…",
|
||||
"type": "order",
|
||||
"entityId": 1,
|
||||
"externalNumber": "…",
|
||||
"date": "2026-08-10T00:00:00.000Z",
|
||||
"createdAt": "2026-08-10T00:00:00.000Z",
|
||||
"lines": [
|
||||
@@ -54,7 +56,8 @@ Updated order
|
||||
"net": 1,
|
||||
"rebate": 1,
|
||||
"taxrate": 1,
|
||||
"comment": "…"
|
||||
"comment": "…",
|
||||
"shippable": true
|
||||
}
|
||||
],
|
||||
"shipping": {
|
||||
@@ -62,6 +65,7 @@ Updated order
|
||||
"manifestId": 1,
|
||||
"number": "…",
|
||||
"trackingCode": "…",
|
||||
"carrierId": 1,
|
||||
"carrier": "…",
|
||||
"type": "…",
|
||||
"state": "…"
|
||||
@@ -72,6 +76,7 @@ Updated order
|
||||
"manifestId": 1,
|
||||
"number": "…",
|
||||
"trackingCode": "…",
|
||||
"carrierId": 1,
|
||||
"carrier": "…",
|
||||
"type": "…",
|
||||
"state": "…"
|
||||
@@ -121,7 +126,8 @@ Updated order
|
||||
"net": 1,
|
||||
"rebate": 1,
|
||||
"taxrate": 1,
|
||||
"comment": "…"
|
||||
"comment": "…",
|
||||
"shippable": true
|
||||
}
|
||||
],
|
||||
"shippings": [
|
||||
@@ -130,11 +136,49 @@ Updated order
|
||||
"manifestId": 1,
|
||||
"number": "…",
|
||||
"trackingCode": "…",
|
||||
"carrierId": 1,
|
||||
"carrier": "…",
|
||||
"type": "…",
|
||||
"state": "…"
|
||||
}
|
||||
]
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"id": 1,
|
||||
"manifestId": 1,
|
||||
"fileId": 1,
|
||||
"sort": 1,
|
||||
"hash": "…",
|
||||
"mimetype": "…",
|
||||
"name": "…",
|
||||
"size": 1,
|
||||
"created": "2026-08-10T00:00:00.000Z",
|
||||
"modified": "2026-08-10T00:00:00.000Z",
|
||||
"skeledash": "…",
|
||||
"thumbx": 1,
|
||||
"thumby": 1,
|
||||
"meta": {}
|
||||
}
|
||||
],
|
||||
"state": "new"
|
||||
}
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"id": 1,
|
||||
"manifestId": 1,
|
||||
"fileId": 1,
|
||||
"sort": 1,
|
||||
"hash": "…",
|
||||
"mimetype": "…",
|
||||
"name": "…",
|
||||
"size": 1,
|
||||
"created": "2026-08-10T00:00:00.000Z",
|
||||
"modified": "2026-08-10T00:00:00.000Z",
|
||||
"skeledash": "…",
|
||||
"thumbx": 1,
|
||||
"thumby": 1,
|
||||
"meta": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
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`._
|
||||
@@ -5,7 +5,7 @@ Public. No cookie required.
|
||||
POS discovery and pairing
|
||||
|
||||
Special API for POS bind and sync.
|
||||
- Step 1 (Discovery): `authCode` length 1–4. Returns certificate fingerprints, serial number, and mandantId.
|
||||
- Step 1 (Discovery): `authCode` length 1-4. Returns certificate fingerprints, serial number, and mandantId.
|
||||
- Step 2 (Pairing): `authCode` length 6 (pairingpin from posterminal). Verifies the pairingpin, sets token, paired_at, and clientserial, revokes the pairingpin, and returns device credentials and company metadata.
|
||||
|
||||
|
||||
@@ -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`._
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user