u
This commit is contained in:
@@ -246,11 +246,20 @@ Clients subscribe via [`GET /events`](routes/events.md) (`text/event-stream`). A
|
||||
|
||||
| Signal | Emitted by |
|
||||
|--------|------------|
|
||||
| `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` |
|
||||
| `articles` | `POST /article`, `DELETE /article/{sku}`, `PATCH /article/{sku}`, `DELETE /category/{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` |
|
||||
| `attributename` | `POST /attributename`, `PUT /attributename/order`, `DELETE /attributename/{id}`, `PATCH /attributename/{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` |
|
||||
| `labeltemplate` | `POST /labeltemplate`, `DELETE /labeltemplate/{id}`, `PATCH /labeltemplate/{id}`, `PUT /labeltemplate/{id}` |
|
||||
| `ledger` | `POST /stock/adjust` |
|
||||
| `modelconversation` | `POST /modelconversation`, `DELETE /modelconversation/{id}` |
|
||||
| `modelconversation-<id>` | `POST /modelconversation/{id}/message` |
|
||||
| `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}`, `PUT /vfs/{*path}` |
|
||||
| `warehouse` | `POST /warehouse`, `PUT /warehouse/order`, `DELETE /warehouse/{id}`, `PUT /warehouse/{id}` |
|
||||
|
||||
## DESIGN
|
||||
|
||||
|
||||
@@ -214,8 +214,8 @@ _none_
|
||||
- Params: `body: { companyId: int }`
|
||||
- Returns: `200 { user: T34 }`
|
||||
#### List brands — `GET /brand`
|
||||
- Params: `query: offset?: int, limit?: int`
|
||||
- Returns: `200 { brands: { id: int, name: str, pics: T36[], gsprpinfo?: str|null }[], total: int, offset: int, limit: int }`
|
||||
- Params: `query: offset?: int, limit?: int, includeSmallThumbs?: bool`
|
||||
- Returns: `200 { brands: { id: int, name: str, 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: T36[], gsprpinfo?: str|null } }`
|
||||
@@ -327,6 +327,15 @@ _none_
|
||||
#### Parse document (SSE) — `POST /delivery/parse`
|
||||
- Params: `form: { file: str }`
|
||||
- Returns: `200 SSE`
|
||||
|
||||
- Events:
|
||||
- `status`: `{ "message": "…" }`
|
||||
- `llm_call`: `{ "model": "…", "promptSize": 0, "messages": 0 }`
|
||||
- `tool_call`: `{ "name": "output_manifest" }`
|
||||
- `usage`: `{ "input": 0, "cached": 0, "output": 0, "cost": 0 }`
|
||||
- `progress`: `ManifestResult`
|
||||
- `result`: `ManifestResult`
|
||||
- `error`: `{ "message": "…" }`
|
||||
#### Delete delivery — `DELETE /delivery/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
@@ -384,6 +393,22 @@ _none_
|
||||
#### Subscribe to update signals (SSE) — `GET /events`
|
||||
_none_
|
||||
- Returns: `200 SSE`
|
||||
|
||||
- Events:
|
||||
- `category`: `{}`
|
||||
- `articles`: `{}`
|
||||
- `article-<sku>`: `{}`
|
||||
- `stock`: `{}`
|
||||
- `ledger`: `{}`
|
||||
- `attributename`: `{}`
|
||||
- `propertyname`: `{}`
|
||||
- `labeltemplate`: `{}`
|
||||
- `printer`: `{}`
|
||||
- `warehouse`: `{}`
|
||||
- `vfs`: `{}`
|
||||
- `modelconversation`: `{}`
|
||||
- `modelconversation-<id>`: `{}`
|
||||
- `brand`: `{ sender, brandId }`
|
||||
#### Database health check — `GET /health`
|
||||
_none_
|
||||
- Returns: `200 { ok: bool }`
|
||||
@@ -573,6 +598,12 @@ _none_
|
||||
#### Search images via Serper.dev and stream WebP thumbnails (SSE) — `POST /serper/images`
|
||||
- Params: `body: { q: str, gl?: str, hl?: str, num?: int, preferSource?: bool }`
|
||||
- Returns: `200 SSE`
|
||||
|
||||
- Events:
|
||||
- `images`: `{ "images": [ { "id": 0, "url": "…", "width": 1000, "height": 800 } ] }`
|
||||
- `thumb`: `{ "id": 0, "dataUrl": "data:image/webp;base64,…" }`
|
||||
- `done`: `{ "total": 100 }`
|
||||
- `error`: `{ "error": "…" }`
|
||||
#### Delete shipping — `DELETE /shipping/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `204 void`
|
||||
|
||||
@@ -197,8 +197,8 @@ _none_
|
||||
_none_
|
||||
- Returns: `200 { message: str }`
|
||||
#### List brands — `GET /brand`
|
||||
- Params: `query: offset?: int, limit?: int`
|
||||
- Returns: `200 { brands: { id: int, name: str, pics: T32[], gsprpinfo?: str|null }[], total: int, offset: int, limit: int }`
|
||||
- Params: `query: offset?: int, limit?: int, includeSmallThumbs?: bool`
|
||||
- Returns: `200 { brands: { id: int, name: str, 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: T32[], gsprpinfo?: str|null } }`
|
||||
|
||||
@@ -22,6 +22,10 @@ Creates an attribute name for the selected company.
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `attributename` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `201`
|
||||
|
||||
Created attribute name
|
||||
|
||||
@@ -12,6 +12,10 @@ Deletes an attribute name and cascades to attribute values and article assignmen
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | |
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `attributename` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
|
||||
Deleted successfully
|
||||
|
||||
@@ -28,6 +28,10 @@ Updates name, sort, and/or exclusive flag for an attribute name.
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `attributename` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
|
||||
Updated attribute name
|
||||
|
||||
@@ -20,6 +20,10 @@ Updates the display sort order of attribute names for the selected company.
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `attributename` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
|
||||
Reordered successfully
|
||||
|
||||
@@ -4,7 +4,7 @@ Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
List brands
|
||||
|
||||
Lists brands for the authenticated user's selected company, sorted by name. Paged; `total` is the unpaged count.
|
||||
Lists brands for the authenticated user's selected company, sorted by name. Paged; `total` is the unpaged count. Small-thumbnail fields are omitted by default. Set `includeSmallThumbs=true` to include each picture's `smallThumbW`, `smallThumbH`, and `smallThumbBinary` (base64-encoded AVIF bytes, resized with a 40px maximum edge).
|
||||
|
||||
## Query parameters
|
||||
|
||||
@@ -12,6 +12,7 @@ Lists brands for the authenticated user's selected company, sorted by name. Page
|
||||
|-------|----------|------|-------------|
|
||||
| `offset` | no | integer | Number of brands to skip |
|
||||
| `limit` | no | integer | Number of brands to return |
|
||||
| `includeSmallThumbs` | no | boolean | Include each picture's small thumbnail dimensions and base64 AVIF bytes. |
|
||||
|
||||
## Response `200`
|
||||
|
||||
@@ -29,7 +30,10 @@ Brand list
|
||||
"fullHash": "…",
|
||||
"thumbW": 1,
|
||||
"thumbH": 1,
|
||||
"thumbHash": "…"
|
||||
"thumbHash": "…",
|
||||
"smallThumbW": 1,
|
||||
"smallThumbH": 1,
|
||||
"smallThumbBinary": "…"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -44,7 +48,7 @@ Brand list
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Invalid offset, invalid limit, or no company selected — `{"error":"…"}` |
|
||||
| 400 | Invalid offset, invalid limit, invalid includeSmallThumbs, or no company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized — `{"error":"…"}` |
|
||||
| 404 | Company not found — `{"error":"…"}` |
|
||||
|
||||
@@ -24,21 +24,36 @@ to the company at connect time).
|
||||
|
||||
## Signals
|
||||
|
||||
| Signal | Emitted after successful |
|
||||
|--------|--------------------------|
|
||||
| `category` | `POST /category`, `PATCH /category/{id}`, `PUT /category/order`, `DELETE /category/{id}`, `POST /category/{id}/image`, `DELETE /category/{id}/image` |
|
||||
| `articles` | `POST /article`, `PATCH /article/{sku}`, `DELETE /article/{sku}` |
|
||||
| `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}` |
|
||||
| `brand` | `POST /brand`, `PATCH /brand/{id}`, `DELETE /brand/{id}`, `POST /brand/{id}/image`, `DELETE /brand/{id}/image` |
|
||||
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.
|
||||
|
||||
The `brand` signal carries a JSON payload `{ sender, brandId }`:
|
||||
`sender` echoes the caller's `x-client-id` header (empty string if
|
||||
absent) so the sender can ignore its own event; `brandId` is the
|
||||
affected brand id (`null` only if unknown). Other signals send `{}`.
|
||||
| Signal | Payload | Emitted after successful |
|
||||
|--------|---------|--------------------------|
|
||||
| `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` |
|
||||
| `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}` |
|
||||
| `warehouse` | `{}` | `POST /warehouse`, `PUT /warehouse/{id}`, `PATCH /warehouse/{id}`, `DELETE /warehouse/{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` |
|
||||
|
||||
The `brand` payload is `{ sender, brandId }`: `sender` echoes the
|
||||
caller's `x-client-id` header (empty string if absent) so the sender
|
||||
can ignore its own event; `brandId` is the affected brand id (`null`
|
||||
only if unknown). All other signals send `{}`.
|
||||
|
||||
Signals are only sent when the mutation actually succeeds (2xx).
|
||||
Failed or no-op validation errors do not emit. The `article-<sku>`
|
||||
event name uses the concrete SKU (e.g. `article-42000045`).
|
||||
and `modelconversation-<id>` event names use the concrete item id at
|
||||
runtime (for example `article-42000045` and `modelconversation-123`).
|
||||
|
||||
|
||||
## Response `200`
|
||||
|
||||
@@ -46,6 +46,10 @@ and stored with the template.
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `labeltemplate` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `201`
|
||||
|
||||
Created label template
|
||||
|
||||
@@ -12,6 +12,10 @@ Deletes a label template for the authenticated user's selected company.
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | Label template ID |
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `labeltemplate` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `204`
|
||||
|
||||
Label template deleted
|
||||
|
||||
@@ -51,6 +51,10 @@ When `content` (or `width`/`height`) is provided, the thumbnail is automatically
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `labeltemplate` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
|
||||
Updated label template
|
||||
|
||||
@@ -20,6 +20,10 @@ Creates a new conversation in state `idle`.
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `modelconversation` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `201`
|
||||
|
||||
Created conversation
|
||||
|
||||
@@ -12,6 +12,10 @@ Deletes one of the authenticated user's model conversations and all its messages
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | Conversation ID |
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `modelconversation` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `204`
|
||||
|
||||
Conversation deleted
|
||||
|
||||
@@ -34,6 +34,10 @@ Refused with 409 unless the conversation state is `idle`.
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `modelconversation-<id>` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `201`
|
||||
|
||||
Created message
|
||||
|
||||
@@ -34,6 +34,10 @@ Updates specified fields of an existing printer for the selected company.
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `printer` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
|
||||
Updated printer
|
||||
|
||||
@@ -30,6 +30,10 @@ Creates a new printer for the selected company.
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `printer` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `201`
|
||||
|
||||
Created printer
|
||||
|
||||
@@ -12,6 +12,10 @@ Deletes a printer for the authenticated user's selected company.
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | Printer ID |
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `printer` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `204`
|
||||
|
||||
Printer deleted
|
||||
|
||||
@@ -22,6 +22,10 @@ Reorders printers for the selected company.
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `printer` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
|
||||
Applied printer order
|
||||
|
||||
@@ -34,6 +34,10 @@ Updates specified fields of an existing printer for the selected company.
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `printer` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
|
||||
Updated printer
|
||||
|
||||
@@ -22,6 +22,10 @@ Creates a new property name for the selected company.
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `propertyname` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `201`
|
||||
|
||||
Created property name
|
||||
|
||||
@@ -12,6 +12,10 @@ Deletes a property name and cascades to article properties.
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | |
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `propertyname` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
|
||||
Deleted successfully
|
||||
|
||||
@@ -28,6 +28,10 @@ Updates name and/or sort for a property name.
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `propertyname` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
|
||||
Updated property name
|
||||
|
||||
@@ -20,6 +20,10 @@ Updates the display sort order of property names for the selected company.
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `propertyname` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
|
||||
Reordered successfully
|
||||
|
||||
@@ -41,6 +41,10 @@ of type "adjustment", allocating a number from the "adjustment" number scheme.
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signals: `stock`, `ledger`, `articles`, `article-<sku>` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `201`
|
||||
|
||||
Stock adjusted successfully
|
||||
|
||||
@@ -26,6 +26,10 @@ Updates specified fields of an existing warehouse for the selected company.
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `warehouse` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
|
||||
Updated warehouse
|
||||
|
||||
@@ -22,6 +22,10 @@ Sort order will be automatically appended if omitted.
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `warehouse` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `201`
|
||||
|
||||
Created warehouse
|
||||
|
||||
@@ -12,6 +12,10 @@ Deletes a warehouse if not in use in the ledger.
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | Warehouse ID |
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `warehouse` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `204`
|
||||
|
||||
Warehouse deleted
|
||||
|
||||
@@ -22,6 +22,10 @@ Reorders warehouses for the selected company.
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `warehouse` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
|
||||
Applied warehouse order
|
||||
|
||||
Reference in New Issue
Block a user