This commit is contained in:
seb
2026-10-02 00:15:22 +02:00
parent 20886e7c76
commit 3f84ff2be8
12 changed files with 238 additions and 31 deletions

View File

@@ -11955,7 +11955,7 @@
"Article"
],
"summary": "Replace POS prices by SKU",
"description": "Replace-all prices for the company POS customer group.\nEach entry: `price` (net), `tax` (rate, ensured via tax.ensure), optional `minmultiplier` (default 1).\nEmpty `prices` clears all POS prices. Returns the same shape as GET by SKU.\n",
"description": "Replace-all prices for the company POS customer group.\nEach entry: `price` (net), `tax` (rate, ensured via tax.ensure), optional `minmultiplier` (default 1).\nEmpty `prices` clears all POS prices. Returns the same shape as GET by SKU (article `prices` array contains `{ minmultiplier, net, taxRate, customergroupId }`).\n",
"security": [
{
"cookieAuth": []
@@ -14543,18 +14543,47 @@
},
"prices": {
"type": "array",
"description": "Selling prices by customer group and quantity tier (field is net, not price)",
"items": {
"type": "object"
"$ref": "#/components/schemas/ArticlePriceEntry"
}
},
"suppliers": {
"type": "array",
"items": {
"type": "object"
"$ref": "#/components/schemas/ArticleSupplier"
}
}
}
},
"ArticlePriceEntry": {
"type": "object",
"description": "Article selling price tier for a customer group (note price field is net, not price)",
"required": [
"minmultiplier",
"net",
"taxRate",
"customergroupId"
],
"properties": {
"minmultiplier": {
"type": "number",
"description": "Quantity threshold for volume pricing (defaults to 1)"
},
"net": {
"type": "number",
"description": "Net selling price"
},
"taxRate": {
"type": "number",
"description": "Tax rate in percent (e.g. 19 or 8.1)"
},
"customergroupId": {
"type": "integer",
"description": "Customer group ID (e.g. company POS customer group)"
}
}
},
"ArticleHistoryEntry": {
"type": "object",
"required": [

View File

@@ -14,25 +14,25 @@ Overview of all 141 API endpoints across all modules.
|:---|:---|:---|:---|:---|
| `POST` | `/article` | `body: { categoryId, name, track_stock? }` | `201 { article: { id, categoryId, name, sku, track_stock } }` | Create article in category |
| `DELETE` | `/article/{sku}` | `sku:string, query: cascade?:boolean` | `204 void` | Delete article by SKU |
| `GET` | `/article/{sku}` | `sku:string` | `200 { article: { id, sku, name, slug, track_stock, unitamount, weight, unit, brand, categoryIds: integer[], photos: object[], eans: string[], prices: object[], suppliers: object[] } }` | Get article by SKU |
| `PATCH` | `/article/{sku}` | `sku:string, body: { name?, unitamount?, unitSi?, track_stock? }` | `200 { article: { id, sku, name, slug, track_stock, unitamount, weight, unit, brand, categoryIds: integer[], photos: object[], eans: string[], prices: object[], suppliers: object[] } }` | Update article by SKU |
| `GET` | `/article/{sku}` | `sku:string` | `200 { article: { id, sku, name, slug, track_stock, unitamount, weight, unit, brand, categoryIds: integer[], photos: object[], eans: string[], prices: { minmultiplier, net, taxRate, customergroupId }[], suppliers: { id, articleId, entityId, supplierName, sku, pu, stock, sort, priceId, price }[] } }` | Get article by SKU |
| `PATCH` | `/article/{sku}` | `sku:string, body: { name?, unitamount?, unitSi?, track_stock? }` | `200 { article: { id, sku, name, slug, track_stock, unitamount, weight, unit, brand, categoryIds: integer[], photos: object[], eans: string[], prices: { minmultiplier, net, taxRate, customergroupId }[], suppliers: { id, articleId, entityId, supplierName, sku, pu, stock, sort, priceId, price }[] } }` | Update article by SKU |
| `GET` | `/article/{sku}/articlelist` | `sku:string` | `200 { items: { id, articleId, sku, name, count, sort }[] }` | Get Stückliste (bundle items) for an article |
| `PUT` | `/article/{sku}/articlelist` | `sku:string, body: { items: { articleId?, sku?: string, count?, sort? }[] }` | `200 { items: object[] }` | Set Stückliste (bundle items) for an article |
| `GET` | `/article/{sku}/attributevalue` | `sku:string` | `200 { attributevalues: { id, articleId, attributeId, attributeName, exclusive, attributeValueId, value, sort }[] }` | List article attribute values |
| `PUT` | `/article/{sku}/attributevalue` | `sku:string, body: { attributevalues: any[] }` | `200 { attributevalues: { id, articleId, attributeId, attributeName, exclusive, attributeValueId, value, sort }[] }` | Bulk set article attribute values |
| `PUT` | `/article/{sku}/brand` | `sku:string, body: { brandId: integer }` | `200 { article: { id, sku, name, slug, track_stock, unitamount, weight, unit, brand, categoryIds: integer[], photos: object[], eans: string[], prices: object[], suppliers: object[] } }` | Set or clear article brand by SKU |
| `PUT` | `/article/{sku}/categories` | `sku:string, body: { categoryIds: integer[] }` | `200 { article: { id, sku, name, slug, track_stock, unitamount, weight, unit, brand, categoryIds: integer[], photos: object[], eans: string[], prices: object[], suppliers: object[] } }` | Replace article categories by SKU |
| `PUT` | `/article/{sku}/brand` | `sku:string, body: { brandId: integer }` | `200 { article: { id, sku, name, slug, track_stock, unitamount, weight, unit, brand, categoryIds: integer[], photos: object[], eans: string[], prices: { minmultiplier, net, taxRate, customergroupId }[], suppliers: { id, articleId, entityId, supplierName, sku, pu, stock, sort, priceId, price }[] } }` | Set or clear article brand by SKU |
| `PUT` | `/article/{sku}/categories` | `sku:string, body: { categoryIds: integer[] }` | `200 { article: { id, sku, name, slug, track_stock, unitamount, weight, unit, brand, categoryIds: integer[], photos: object[], eans: string[], prices: { minmultiplier, net, taxRate, customergroupId }[], suppliers: { id, articleId, entityId, supplierName, sku, pu, stock, sort, priceId, price }[] } }` | Replace article categories by SKU |
| `GET` | `/article/{sku}/children` | `sku:string` | `200 { children: { id, sku, name, fathersort, attributeValueId, attributeValue }[] }` | List child articles of a father article |
| `POST` | `/article/{sku}/children` | `sku:string, body: { attributeValueId?, value?, name?, sku?: string }` | `201 { article: { id, categoryId, name, sku, track_stock } }` | Add a child article to a father article |
| `DELETE` | `/article/{sku}/children/{childSku}` | `sku:string, childSku:string, query: deleteArticle?:boolean` | `200 { success, deleted }` | Remove a child article from a father article |
| `PUT` | `/article/{sku}/eans` | `sku:string, body: { eans: string[] }` | `200 { article: { id, sku, name, slug, track_stock, unitamount, weight, unit, brand, categoryIds: integer[], photos: object[], eans: string[], prices: object[], suppliers: object[] } }` | Replace article EANs by SKU |
| `PUT` | `/article/{sku}/eans` | `sku:string, body: { eans: string[] }` | `200 { article: { id, sku, name, slug, track_stock, unitamount, weight, unit, brand, categoryIds: integer[], photos: object[], eans: string[], prices: { minmultiplier, net, taxRate, customergroupId }[], suppliers: { id, articleId, entityId, supplierName, sku, pu, stock, sort, priceId, price }[] } }` | Replace article EANs by SKU |
| `POST` | `/article/{sku}/father` | `sku:string, body: { isFather, attributeNameId? }` | `200 { article: { id, categoryId, name, sku, track_stock } }` | Toggle father mode for an article |
| `GET` | `/article/{sku}/history` | `sku:string, query: limit?:integer` | `200 { history: { id, date, text }[], truncated }` | Get article history by SKU |
| `DELETE` | `/article/{sku}/image/{fullHash}` | `sku:string, fullHash:string` | `204 void` | Delete article image |
| `PUT` | `/article/{sku}/images/order` | `sku:string, body: { fullHashes: string[] }` | `200 { fullHashes: string[] }` | Reorder article images |
| `GET` | `/article/{sku}/optionslist` | `sku:string` | `200 { options: { id, articleId, sku, name, count, sort, mandated }[] }` | Get options list for an article |
| `PUT` | `/article/{sku}/optionslist` | `sku:string, body: { options: { articleId?, sku?: string, count?, sort?, mandated? }[] }` | `200 { options: object[] }` | Set options list for an article |
| `PUT` | `/article/{sku}/prices` | `sku:string, body: { prices: { price, tax, minmultiplier? }[] }` | `200 { article: { id, sku, name, slug, track_stock, unitamount, weight, unit, brand, categoryIds: integer[], photos: object[], eans: string[], prices: object[], suppliers: object[] } }` | Replace POS prices by SKU |
| `PUT` | `/article/{sku}/prices` | `sku:string, body: { prices: { price, tax, minmultiplier? }[] }` | `200 { article: { id, sku, name, slug, track_stock, unitamount, weight, unit, brand, categoryIds: integer[], photos: object[], eans: string[], prices: { minmultiplier, net, taxRate, customergroupId }[], suppliers: { id, articleId, entityId, supplierName, sku, pu, stock, sort, priceId, price }[] } }` | Replace POS prices by SKU |
| `POST` | `/article/{sku}/print` | `sku:string, body: { templateId, printerId, quantity }` | `200` | Print article label |
| `GET` | `/article/{sku}/property` | `sku:string` | `200 { properties: { id, articleId, propertyId, name, exclusive, value, sort }[] }` | List article properties |
| `PUT` | `/article/{sku}/property` | `sku:string, body: { properties: { propertyId, value, sort? }[] }` | `200 { properties: { id, articleId, propertyId, name, exclusive, value, sort }[] }` | Bulk set article properties |
@@ -42,8 +42,8 @@ Overview of all 141 API endpoints across all modules.
| `PUT` | `/article/{sku}/supplier/order` | `sku:string, body: { ids: integer[] }` | `200 { ids: integer[] }` | Reorder article suppliers |
| `DELETE` | `/article/{sku}/supplier/{id}` | `sku:string, id:integer` | `204 void` | Remove supplier assignment from article |
| `PATCH` | `/article/{sku}/supplier/{id}` | `sku:string, id:integer, body: { sku?: string, pu?, stock?, sort?, netPrice?, taxId?, taxRate? }` | `200 { supplier: { id, articleId, entityId, supplierName, sku, pu, stock, sort, priceId, price } }` | Update article supplier assignment |
| `PUT` | `/article/{sku}/track_stock` | `sku:string, body: { track_stock: boolean }` | `200 { article: { id, sku, name, slug, track_stock, unitamount, weight, unit, brand, categoryIds: integer[], photos: object[], eans: string[], prices: object[], suppliers: object[] } }` | Set article track_stock flag by SKU |
| `PUT` | `/article/{sku}/weight` | `sku:string, body: { weight: number }` | `200 { article: { id, sku, name, slug, track_stock, unitamount, weight, unit, brand, categoryIds: integer[], photos: object[], eans: string[], prices: object[], suppliers: object[] } }` | Set article weight by SKU |
| `PUT` | `/article/{sku}/track_stock` | `sku:string, body: { track_stock: boolean }` | `200 { article: { id, sku, name, slug, track_stock, unitamount, weight, unit, brand, categoryIds: integer[], photos: object[], eans: string[], prices: { minmultiplier, net, taxRate, customergroupId }[], suppliers: { id, articleId, entityId, supplierName, sku, pu, stock, sort, priceId, price }[] } }` | Set article track_stock flag by SKU |
| `PUT` | `/article/{sku}/weight` | `sku:string, body: { weight: number }` | `200 { article: { id, sku, name, slug, track_stock, unitamount, weight, unit, brand, categoryIds: integer[], photos: object[], eans: string[], prices: { minmultiplier, net, taxRate, customergroupId }[], suppliers: { id, articleId, entityId, supplierName, sku, pu, stock, sort, priceId, price }[] } }` | Set article weight by SKU |
| `GET` | `/articleIndex` | — | `200 { articles: { id, sku, name, eans: string[], categoryIds: integer[] }[] }` | List article search index |
| `GET` | `/attributename` | — | `200 { attributenames: { id, name, sort, exclusive, values: { id, attributeId, value, sort }[] }[] }` | List attribute names |
| `POST` | `/attributename` | `body: { name, sort?, exclusive? }` | `201 { attributename: { id, name, sort, exclusive, values: { id, attributeId, value, sort }[] } }` | Create attribute name |

View File

@@ -55,10 +55,30 @@ Updated article detail
"…"
],
"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
}
}
]
}
}

View File

@@ -38,10 +38,30 @@ Article detail
"…"
],
"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
}
}
]
}
}

View File

@@ -56,10 +56,30 @@ Updated article detail
"…"
],
"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
}
}
]
}
}

View File

@@ -60,10 +60,30 @@ Updated article detail
"…"
],
"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
}
}
]
}
}

View File

@@ -58,10 +58,30 @@ Updated article detail
"…"
],
"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
}
}
]
}
}

View File

@@ -6,7 +6,7 @@ Replace POS prices by SKU
Replace-all prices for the company POS customer group.
Each entry: `price` (net), `tax` (rate, ensured via tax.ensure), optional `minmultiplier` (default 1).
Empty `prices` clears all POS prices. Returns the same shape as GET by SKU.
Empty `prices` clears all POS prices. Returns the same shape as GET by SKU (article `prices` array contains `{ minmultiplier, net, taxRate, customergroupId }`).
## Path parameters
@@ -70,10 +70,30 @@ Updated article detail
"…"
],
"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
}
}
]
}
}

View File

@@ -56,10 +56,30 @@ Updated article detail
"…"
],
"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
}
}
]
}
}

View File

@@ -60,10 +60,30 @@ Updated article detail
"…"
],
"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
}
}
]
}
}

View File

@@ -152,12 +152,30 @@
* type: string
* prices:
* type: array
* description: Selling prices by customer group and quantity tier (field is net, not price)
* items:
* type: object
* $ref: '#/components/schemas/ArticlePriceEntry'
* suppliers:
* type: array
* items:
* type: object
* $ref: '#/components/schemas/ArticleSupplier'
* ArticlePriceEntry:
* type: object
* description: Article selling price tier for a customer group (note price field is net, not price)
* required: [minmultiplier, net, taxRate, customergroupId]
* properties:
* minmultiplier:
* type: number
* description: Quantity threshold for volume pricing (defaults to 1)
* net:
* type: number
* description: Net selling price
* taxRate:
* type: number
* description: Tax rate in percent (e.g. 19 or 8.1)
* customergroupId:
* type: integer
* description: Customer group ID (e.g. company POS customer group)
* ArticleHistoryEntry:
* type: object
* required: [id, date, text]

View File

@@ -707,7 +707,7 @@ export function register(app, basePath = '') {
* description: |
* Replace-all prices for the company POS customer group.
* Each entry: `price` (net), `tax` (rate, ensured via tax.ensure), optional `minmultiplier` (default 1).
* Empty `prices` clears all POS prices. Returns the same shape as GET by SKU.
* Empty `prices` clears all POS prices. Returns the same shape as GET by SKU (article `prices` array contains `{ minmultiplier, net, taxRate, customergroupId }`).
* security:
* - cookieAuth: []
* x-signals: [article-<sku>]