This commit is contained in:
seb
2026-10-09 18:10:49 +02:00
parent 848ca0aff5
commit daf2d0525f
10 changed files with 112 additions and 66 deletions

View File

@@ -10,7 +10,7 @@ Params: path values first, then `query:` and `body:` (`body?` = optional body).
### Reusable types ### Reusable types
- `T1` = `{ article: T2 }` - `T1` = `{ article: T2 }`
- `T2` = `{ id: int, sku: str, name: str, slug: str, desc: str|null, seo: str|null, track_stock: bool, unitamount: num|null, weight: num|null, unit: T32, brand: T28|null, categoryIds: int[], photos: T26[], eans: str[], prices: T36[], suppliers: T12[] }` - `T2` = `{ id: int, sku: str, name: str, slug: str, desc: str|null, seo: str|null, track_stock: bool, unitamount: num|null, weight: num|null, unit: T31, brand: T28|null, categoryIds: int[], photos: T26[], eans: str[], prices: T35[], suppliers: T12[] }`
- `T3` = `{ delivery: T4 }` - `T3` = `{ delivery: T4 }`
- `T4` = `{ id: int, number: str, type: str, supplierId: int|null, date: str, lines: T20[], files: T9[], externalNumber?: str|null, createdAt?: str, ledger?: T40 }` - `T4` = `{ id: int, number: str, type: str, supplierId: int|null, date: str, lines: T20[], files: T9[], externalNumber?: str|null, createdAt?: str, ledger?: T40 }`
- `T5` = `{ labeltemplate: T6 }` - `T5` = `{ labeltemplate: T6 }`
@@ -38,13 +38,13 @@ Params: path values first, then `query:` and `body:` (`body?` = optional body).
- `T27` = `{ id: int, customergroupId: int, firstName: str|null, name: str, number: str|null, createdAt: str, updatedAt: str }` - `T27` = `{ id: int, customergroupId: int, firstName: str|null, name: str, number: str|null, createdAt: str, updatedAt: str }`
- `T28` = `{ name: str, id?: int|null, fullHash?: str|null, thumbW?: int|null, thumbH?: int|null, thumbHash?: str|null }` - `T28` = `{ name: str, id?: int|null, fullHash?: str|null, thumbW?: int|null, thumbH?: int|null, thumbHash?: str|null }`
- `T29` = `{ id: int, companyuser_id: int, provider: str, model: str, created_at: str, updated_at: str, state: str }` - `T29` = `{ id: int, companyuser_id: int, provider: str, model: str, created_at: str, updated_at: str, state: str }`
- `T30` = `{ id: int, sort: int, fullHash: str, thumbW: int, thumbH: int, thumbHash: str }` - `T30` = `{ article: T33 }`
- `T31` = `{ article: T34 }` - `T31` = `{ si: str, basesi: str, basesifactor: num, symbol?: str|null, name?: str|null }`
- `T32` = `{ si: str, basesi: str, basesifactor: num, symbol?: str|null, name?: str|null }` - `T32` = `{ id: int, iso639: str, name: str, taxrate: num, reducedtaxrate: num }`
- `T33` = `{ id: int, iso639: str, name: str, taxrate: num, reducedtaxrate: num }` - `T33` = `{ id: int, categoryId: int, name: str, sku: str, track_stock: bool }`
- `T34` = `{ id: int, categoryId: int, name: str, sku: str, track_stock: bool }` - `T34` = `{ id: int, email: str, selectedCompanyId: int|null, picture?: str }`
- `T35` = `{ id: int, email: str, selectedCompanyId: int|null, picture?: str }` - `T35` = `{ minmultiplier: num, net: num, taxRate: num, customergroupId: int }`
- `T36` = `{ minmultiplier: num, net: num, taxRate: num, customergroupId: int }` - `T36` = `{ fullHash: str, thumbW: int, thumbH: int, thumbHash: str }`
- `T37` = `{ id: int, entityId: int, contactType: str, contact: str }` - `T37` = `{ id: int, entityId: int, contactType: str, contact: str }`
- `T38` = `{ id: int, attributeId: int, value: str, sort: int }` - `T38` = `{ id: int, attributeId: int, value: str, sort: int }`
- `T39` = `{ id: int, name: str, createdAt: str, updatedAt: str }` - `T39` = `{ id: int, name: str, createdAt: str, updatedAt: str }`
@@ -68,7 +68,7 @@ _none_
- Returns: `204 void` - Returns: `204 void`
#### Create article in category — `POST /article` #### Create article in category — `POST /article`
- Params: `body: { categoryId: int, name: str, desc?: str, seo?: str, track_stock?: bool }` - Params: `body: { categoryId: int, name: str, desc?: str, seo?: str, track_stock?: bool }`
- Returns: `201 T31` - Returns: `201 T30`
#### Export articles as ZIP — `GET /article/export.zip` #### Export articles as ZIP — `GET /article/export.zip`
- Params: `query: categoryId?: int` - Params: `query: categoryId?: int`
- Returns: `200 zip` - Returns: `200 zip`
@@ -104,10 +104,10 @@ _none_
- Returns: `200 { 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 }[] }`
#### Create and attach a new child article to a parent article — `POST /article/{sku}/children` #### 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 }` - Params: `sku: str, body: { attributeValueId?: int, value?: str, name?: str }`
- Returns: `201 T31` - Returns: `201 T30`
#### Attach an existing article as a child to a parent article — `PUT /article/{sku}/children` #### 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 }` - Params: `sku: str, body: { sku: str, attributeValueId?: int, value?: str, reparent?: bool }`
- Returns: `200 { article: T34, children: { id: int, sku: str, name: str, parentsort: int, attributeValueId: int, attributeValue: str }[] }` - Returns: `200 { article: T33, 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}` #### Remove a child article from a parent article — `DELETE /article/{sku}/children/{childSku}`
- Params: `sku: str, childSku: str, query: deleteArticle?: bool` - Params: `sku: str, childSku: str, query: deleteArticle?: bool`
- Returns: `200 { success: bool, deleted: bool }` - Returns: `200 { success: bool, deleted: bool }`
@@ -134,7 +134,7 @@ _none_
- Returns: `200 { options: { id: int, articleId: int, sku: str, name: str, count: int, sort: int, mandated: bool }[] }` - 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` #### Toggle parent mode for an article — `POST /article/{sku}/parent`
- Params: `sku: str, body: { isParent: bool, attributeNameId?: int }` - Params: `sku: str, body: { isParent: bool, attributeNameId?: int }`
- Returns: `200 T31` - Returns: `200 T30`
#### Replace POS prices by SKU (net > gross; price=net, tax=taxRate %) — `PUT /article/{sku}/prices` #### 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 }[] }` - Params: `sku: str, body: { prices: { net?: num, gross?: num, price?: num, taxRate?: num, tax?: num, minmultiplier?: num }[] }`
- Returns: `200 T1` - Returns: `200 T1`
@@ -203,22 +203,22 @@ _none_
- Returns: `200 { attributevalue: T38 }` - Returns: `200 { attributevalue: T38 }`
#### Login with Google ID token — `POST /auth/login` #### Login with Google ID token — `POST /auth/login`
- Params: `body: { idToken: str }` - Params: `body: { idToken: str }`
- Returns: `200 { message: str, user: T35 }` - Returns: `200 { message: str, user: T34 }`
#### Logout — `POST /auth/logout` #### Logout — `POST /auth/logout`
_none_ _none_
- Returns: `200 { message: str }` - Returns: `200 { message: str }`
#### Current user — `GET /auth/me` #### Current user — `GET /auth/me`
_none_ _none_
- Returns: `200 { user: T35, googleClientId: str }` - Returns: `200 { user: T34, googleClientId: str }`
#### Set selected company — `PUT /auth/selected-company` #### Set selected company — `PUT /auth/selected-company`
- Params: `body: { companyId: int }` - Params: `body: { companyId: int }`
- Returns: `200 { user: T35 }` - Returns: `200 { user: T34 }`
#### List brands — `GET /brand` #### List brands — `GET /brand`
_none_ - Params: `query: offset?: int, limit?: int`
- Returns: `200 { brands: { id: int, name: str, pics: T30[], gsprpinfo?: str|null }[] }` - Returns: `200 { brands: { id: int, name: str, pics: T36[], gsprpinfo?: str|null }[], total: int, offset: int, limit: int }`
#### Create brand — `POST /brand` #### Create brand — `POST /brand`
- Params: `body: { name: str, gsprpinfo?: str }` - Params: `body: { name: str, gsprpinfo?: str }`
- Returns: `201 { brand: { id: int, name: str, pics: T30[], gsprpinfo?: str|null } }` - Returns: `201 { brand: { id: int, name: str, pics: T36[], gsprpinfo?: str|null } }`
#### Delete brand — `DELETE /brand/{id}` #### Delete brand — `DELETE /brand/{id}`
- Params: `id: int` - Params: `id: int`
- Returns: `204 void` - Returns: `204 void`
@@ -227,10 +227,10 @@ _none_
- Returns: `200 { brand: { id: int, name: str, touchedArticleCount: int, gsprpinfo?: str|null } }` - Returns: `200 { brand: { id: int, name: str, touchedArticleCount: int, gsprpinfo?: str|null } }`
#### Delete brand image — `DELETE /brand/{id}/image` #### Delete brand image — `DELETE /brand/{id}/image`
- Params: `id: int` - Params: `id: int`
- Returns: `200 { brand: { id: int, thumbW: int|null, thumbH: int|null, thumbHash: str|null, pics: T30[] } }` - Returns: `200 { brand: { id: int, thumbW: int|null, thumbH: int|null, thumbHash: str|null, pics: T36[] } }`
#### Add or replace brand image — `POST /brand/{id}/image` #### Add or replace brand image — `POST /brand/{id}/image`
- Params: `id: int, image/avif` - Params: `id: int, image/avif`
- Returns: `201 { brand: { id: int, fullHash: str, thumbW: int, thumbH: int, thumbHash: str, pics: T30[] } }` - Returns: `201 { brand: { id: int, fullHash: str, thumbW: int, thumbH: int, thumbHash: str, pics: T36[] } }`
#### Create category — `POST /category` #### Create category — `POST /category`
- Params: `body: { parentId: int, name: str }` - Params: `body: { parentId: int, name: str }`
- Returns: `201 { category: { id: int, parentId: int|null, sort: int, name: str } }` - Returns: `201 { category: { id: int, parentId: int|null, sort: int, name: str } }`
@@ -275,10 +275,10 @@ _none_
- Returns: `200 { ok: bool }` - Returns: `200 { ok: bool }`
#### List companies — `GET /company` #### List companies — `GET /company`
_none_ _none_
- Returns: `200 { companies: T33[] }` - Returns: `200 { companies: T32[] }`
#### Create company — `POST /company` #### Create company — `POST /company`
- Params: `body: { iso639: str, name: str, taxrate: num, reducedtaxrate: num }` - Params: `body: { iso639: str, name: str, taxrate: num, reducedtaxrate: num }`
- Returns: `201 { company: T33, user: T35 }` - Returns: `201 { company: T32, user: T34 }`
#### Get company history — `GET /company/history` #### Get company history — `GET /company/history`
- Params: `query: limit?: int` - Params: `query: limit?: int`
- Returns: `200 { history: { id: int, date: str, text: str, companyuserId?: int|null }[], truncated: bool }` - Returns: `200 { history: { id: int, date: str, text: str, companyuserId?: int|null }[], truncated: bool }`
@@ -302,7 +302,7 @@ _none_
- Returns: `204 void` - Returns: `204 void`
#### Update company — `PUT /company/{id}` #### Update company — `PUT /company/{id}`
- Params: `id: int, body: { iso639: str, name: str, taxrate: num, reducedtaxrate: num }` - Params: `id: int, body: { iso639: str, name: str, taxrate: num, reducedtaxrate: num }`
- Returns: `200 { company: T33 }` - Returns: `200 { company: T32 }`
#### List customer groups — `GET /customergroup` #### List customer groups — `GET /customergroup`
_none_ _none_
- Returns: `200 { customergroups: { id: int, name: str, sort: int, editable: bool }[] }` - Returns: `200 { customergroups: { id: int, name: str, sort: int, editable: bool }[] }`
@@ -611,10 +611,10 @@ _none_
- Returns: `204 void` - Returns: `204 void`
#### List units — `GET /unit` #### List units — `GET /unit`
_none_ _none_
- Returns: `200 { units: T32[] }` - Returns: `200 { units: T31[] }`
#### Upsert unit — `PUT /unit` #### Upsert unit — `PUT /unit`
- Params: `body: { si: str, basesi: str, basesifactor: num, symbol: str, name: str }` - Params: `body: { si: str, basesi: str, basesifactor: num, symbol: str, name: str }`
- Returns: `200 { unit: T32 }` - Returns: `200 { unit: T31 }`
#### JTL-POS category synchronization — `GET /v1/category` #### JTL-POS category synchronization — `GET /v1/category`
- Params: `query: lastChangedCategory?: str, limit?: int` - Params: `query: lastChangedCategory?: str, limit?: int`
- Returns: `200 {}[]` - Returns: `200 {}[]`

View File

@@ -10,7 +10,7 @@ Params: path values first, then `query:` and `body:` (`body?` = optional body).
### Reusable types ### Reusable types
- `T1` = `{ article: T2 }` - `T1` = `{ article: T2 }`
- `T2` = `{ id: int, sku: str, name: str, slug: str, desc: str|null, seo: str|null, track_stock: bool, unitamount: num|null, weight: num|null, unit: T30, brand: T27|null, categoryIds: int[], photos: T25[], eans: str[], prices: T32[], suppliers: T11[] }` - `T2` = `{ id: int, sku: str, name: str, slug: str, desc: str|null, seo: str|null, track_stock: bool, unitamount: num|null, weight: num|null, unit: T29, brand: T27|null, categoryIds: int[], photos: T25[], eans: str[], prices: T31[], suppliers: T11[] }`
- `T3` = `{ delivery: T4 }` - `T3` = `{ delivery: T4 }`
- `T4` = `{ id: int, number: str, type: str, supplierId: int|null, date: str, lines: T19[], files: T9[], externalNumber?: str|null, createdAt?: str, ledger?: T36 }` - `T4` = `{ id: int, number: str, type: str, supplierId: int|null, date: str, lines: T19[], files: T9[], externalNumber?: str|null, createdAt?: str, ledger?: T36 }`
- `T5` = `{ labeltemplate: T6 }` - `T5` = `{ labeltemplate: T6 }`
@@ -36,11 +36,11 @@ Params: path values first, then `query:` and `body:` (`body?` = optional body).
- `T25` = `{ sort: int, fullHash: str, fullW: int, fullH: int, fullSize: int, thumbW: int, thumbH: int, thumbHash: str }` - `T25` = `{ sort: int, fullHash: str, fullW: int, fullH: int, fullSize: int, thumbW: int, thumbH: int, thumbHash: str }`
- `T26` = `{ id: int, customergroupId: int, firstName: str|null, name: str, number: str|null, createdAt: str, updatedAt: str }` - `T26` = `{ id: int, customergroupId: int, firstName: str|null, name: str, number: str|null, createdAt: str, updatedAt: str }`
- `T27` = `{ name: str, id?: int|null, fullHash?: str|null, thumbW?: int|null, thumbH?: int|null, thumbHash?: str|null }` - `T27` = `{ name: str, id?: int|null, fullHash?: str|null, thumbW?: int|null, thumbH?: int|null, thumbHash?: str|null }`
- `T28` = `{ id: int, sort: int, fullHash: str, thumbW: int, thumbH: int, thumbHash: str }` - `T28` = `{ article: T30 }`
- `T29` = `{ article: T31 }` - `T29` = `{ si: str, basesi: str, basesifactor: num, symbol?: str|null, name?: str|null }`
- `T30` = `{ si: str, basesi: str, basesifactor: num, symbol?: str|null, name?: str|null }` - `T30` = `{ id: int, categoryId: int, name: str, sku: str, track_stock: bool }`
- `T31` = `{ id: int, categoryId: int, name: str, sku: str, track_stock: bool }` - `T31` = `{ minmultiplier: num, net: num, taxRate: num, customergroupId: int }`
- `T32` = `{ minmultiplier: num, net: num, taxRate: num, customergroupId: int }` - `T32` = `{ fullHash: str, thumbW: int, thumbH: int, thumbHash: str }`
- `T33` = `{ id: int, entityId: int, contactType: str, contact: str }` - `T33` = `{ id: int, entityId: int, contactType: str, contact: str }`
- `T34` = `{ id: int, attributeId: int, value: str, sort: int }` - `T34` = `{ id: int, attributeId: int, value: str, sort: int }`
- `T35` = `{ id: int, name: str, createdAt: str, updatedAt: str }` - `T35` = `{ id: int, name: str, createdAt: str, updatedAt: str }`
@@ -63,7 +63,7 @@ _none_
- Returns: `204 void` - Returns: `204 void`
#### Create article in category — `POST /article` #### Create article in category — `POST /article`
- Params: `body: { categoryId: int, name: str, desc?: str, seo?: str, track_stock?: bool }` - Params: `body: { categoryId: int, name: str, desc?: str, seo?: str, track_stock?: bool }`
- Returns: `201 T29` - Returns: `201 T28`
#### Delete article by SKU — `DELETE /article/{sku}` #### Delete article by SKU — `DELETE /article/{sku}`
- Params: `sku: str, query: cascade?: bool` - Params: `sku: str, query: cascade?: bool`
- Returns: `204 void` - Returns: `204 void`
@@ -96,10 +96,10 @@ _none_
- Returns: `200 { 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 }[] }`
#### Create and attach a new child article to a parent article — `POST /article/{sku}/children` #### 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 }` - Params: `sku: str, body: { attributeValueId?: int, value?: str, name?: str }`
- Returns: `201 T29` - Returns: `201 T28`
#### Attach an existing article as a child to a parent article — `PUT /article/{sku}/children` #### 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 }` - Params: `sku: str, body: { sku: str, attributeValueId?: int, value?: str, reparent?: bool }`
- Returns: `200 { article: T31, children: { id: int, sku: str, name: str, parentsort: int, attributeValueId: int, attributeValue: str }[] }` - Returns: `200 { article: T30, 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}` #### Remove a child article from a parent article — `DELETE /article/{sku}/children/{childSku}`
- Params: `sku: str, childSku: str, query: deleteArticle?: bool` - Params: `sku: str, childSku: str, query: deleteArticle?: bool`
- Returns: `200 { success: bool, deleted: bool }` - Returns: `200 { success: bool, deleted: bool }`
@@ -123,7 +123,7 @@ _none_
- Returns: `200 { options: { id: int, articleId: int, sku: str, name: str, count: int, sort: int, mandated: bool }[] }` - 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` #### Toggle parent mode for an article — `POST /article/{sku}/parent`
- Params: `sku: str, body: { isParent: bool, attributeNameId?: int }` - Params: `sku: str, body: { isParent: bool, attributeNameId?: int }`
- Returns: `200 T29` - Returns: `200 T28`
#### Replace POS prices by SKU (net > gross; price=net, tax=taxRate %) — `PUT /article/{sku}/prices` #### 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 }[] }` - Params: `sku: str, body: { prices: { net?: num, gross?: num, price?: num, taxRate?: num, tax?: num, minmultiplier?: num }[] }`
- Returns: `200 T1` - Returns: `200 T1`
@@ -197,11 +197,11 @@ _none_
_none_ _none_
- Returns: `200 { message: str }` - Returns: `200 { message: str }`
#### List brands — `GET /brand` #### List brands — `GET /brand`
_none_ - Params: `query: offset?: int, limit?: int`
- Returns: `200 { brands: { id: int, name: str, pics: T28[], gsprpinfo?: str|null }[] }` - Returns: `200 { brands: { id: int, name: str, pics: T32[], gsprpinfo?: str|null }[], total: int, offset: int, limit: int }`
#### Create brand — `POST /brand` #### Create brand — `POST /brand`
- Params: `body: { name: str, gsprpinfo?: str }` - Params: `body: { name: str, gsprpinfo?: str }`
- Returns: `201 { brand: { id: int, name: str, pics: T28[], gsprpinfo?: str|null } }` - Returns: `201 { brand: { id: int, name: str, pics: T32[], gsprpinfo?: str|null } }`
#### Delete brand — `DELETE /brand/{id}` #### Delete brand — `DELETE /brand/{id}`
- Params: `id: int` - Params: `id: int`
- Returns: `204 void` - Returns: `204 void`
@@ -210,10 +210,10 @@ _none_
- Returns: `200 { brand: { id: int, name: str, touchedArticleCount: int, gsprpinfo?: str|null } }` - Returns: `200 { brand: { id: int, name: str, touchedArticleCount: int, gsprpinfo?: str|null } }`
#### Delete brand image — `DELETE /brand/{id}/image` #### Delete brand image — `DELETE /brand/{id}/image`
- Params: `id: int` - Params: `id: int`
- Returns: `200 { brand: { id: int, thumbW: int|null, thumbH: int|null, thumbHash: str|null, pics: T28[] } }` - Returns: `200 { brand: { id: int, thumbW: int|null, thumbH: int|null, thumbHash: str|null, pics: T32[] } }`
#### Add or replace brand image — `POST /brand/{id}/image` #### Add or replace brand image — `POST /brand/{id}/image`
- Params: `id: int, image/avif` - Params: `id: int, image/avif`
- Returns: `201 { brand: { id: int, fullHash: str, thumbW: int, thumbH: int, thumbHash: str, pics: T28[] } }` - Returns: `201 { brand: { id: int, fullHash: str, thumbW: int, thumbH: int, thumbHash: str, pics: T32[] } }`
#### Create category — `POST /category` #### Create category — `POST /category`
- Params: `body: { parentId: int, name: str }` - Params: `body: { parentId: int, name: str }`
- Returns: `201 { category: { id: int, parentId: int|null, sort: int, name: str } }` - Returns: `201 { category: { id: int, parentId: int|null, sort: int, name: str } }`
@@ -504,10 +504,10 @@ _none_
- Returns: `204 void` - Returns: `204 void`
#### List units — `GET /unit` #### List units — `GET /unit`
_none_ _none_
- Returns: `200 { units: T30[] }` - Returns: `200 { units: T29[] }`
#### Upsert unit — `PUT /unit` #### Upsert unit — `PUT /unit`
- Params: `body: { si: str, basesi: str, basesifactor: num, symbol: str, name: str }` - Params: `body: { si: str, basesi: str, basesifactor: num, symbol: str, name: str }`
- Returns: `200 { unit: T30 }` - Returns: `200 { unit: T29 }`
#### List warehouses — `GET /warehouse` #### List warehouses — `GET /warehouse`
_none_ _none_
- Returns: `200 { warehouses: T40[] }` - Returns: `200 { warehouses: T40[] }`

View File

@@ -29,8 +29,6 @@ Image removed
"thumbHash": "…", "thumbHash": "…",
"pics": [ "pics": [
{ {
"id": 1,
"sort": 1,
"fullHash": "…", "fullHash": "…",
"thumbW": 1, "thumbW": 1,
"thumbH": 1, "thumbH": 1,

View File

@@ -41,8 +41,6 @@ Image stored and linked
"thumbHash": "…", "thumbHash": "…",
"pics": [ "pics": [
{ {
"id": 1,
"sort": 1,
"fullHash": "…", "fullHash": "…",
"thumbW": 1, "thumbW": 1,
"thumbH": 1, "thumbH": 1,

View File

@@ -39,8 +39,6 @@ Created brand
"gsprpinfo": "…", "gsprpinfo": "…",
"pics": [ "pics": [
{ {
"id": 1,
"sort": 1,
"fullHash": "…", "fullHash": "…",
"thumbW": 1, "thumbW": 1,
"thumbH": 1, "thumbH": 1,

View File

@@ -4,7 +4,14 @@ Protected. Requires a valid session cookie (`credentials: 'include'`).
List brands List brands
Lists brands for the authenticated user's selected company, sorted by name. Lists brands for the authenticated user's selected company, sorted by name. Paged; `total` is the unpaged count.
## Query parameters
| Param | Required | Type | Description |
|-------|----------|------|-------------|
| `offset` | no | integer | Number of brands to skip |
| `limit` | no | integer | Number of brands to return |
## Response `200` ## Response `200`
@@ -19,8 +26,6 @@ Brand list
"gsprpinfo": "…", "gsprpinfo": "…",
"pics": [ "pics": [
{ {
"id": 1,
"sort": 1,
"fullHash": "…", "fullHash": "…",
"thumbW": 1, "thumbW": 1,
"thumbH": 1, "thumbH": 1,
@@ -28,7 +33,10 @@ Brand list
} }
] ]
} }
] ],
"total": 1,
"offset": 1,
"limit": 1
} }
``` ```
@@ -36,7 +44,7 @@ Brand list
| Status | Description | | Status | Description |
|--------|-------------| |--------|-------------|
| 400 | No company selected — `{"error":"…"}` | | 400 | Invalid offset, invalid limit, or no company selected — `{"error":"…"}` |
| 401 | Unauthorized — `{"error":"…"}` | | 401 | Unauthorized — `{"error":"…"}` |
| 403 | Not authorized — `{"error":"…"}` | | 403 | Not authorized — `{"error":"…"}` |
| 404 | Company not found — `{"error":"…"}` | | 404 | Company not found — `{"error":"…"}` |

View File

@@ -343,12 +343,8 @@
* $ref: '#/components/schemas/SupplierArticleInfo' * $ref: '#/components/schemas/SupplierArticleInfo'
* BrandPic: * BrandPic:
* type: object * type: object
* required: [id, sort, fullHash, thumbW, thumbH, thumbHash] * required: [fullHash, thumbW, thumbH, thumbHash]
* properties: * properties:
* id:
* type: integer
* sort:
* type: integer
* fullHash: * fullHash:
* type: string * type: string
* thumbW: * thumbW:

View File

@@ -19,6 +19,8 @@ function brandErrorStatus(error) {
if (error.message === 'Company not found') return 404; if (error.message === 'Company not found') return 404;
if (error.message === 'Brand not found') return 404; if (error.message === 'Brand not found') return 404;
if (error.message === 'Invalid brand') return 400; if (error.message === 'Invalid brand') return 400;
if (error.message === 'Invalid offset') return 400;
if (error.message === 'Invalid limit') return 400;
if (error.message === 'Brand already exists') return 409; if (error.message === 'Brand already exists') return 409;
if (error.message === 'Brand in use') return 409; if (error.message === 'Brand in use') return 409;
if (error.message === 'Image not found') return 404; if (error.message === 'Image not found') return 404;
@@ -45,9 +47,25 @@ export function register(app, basePath = '') {
* get: * get:
* tags: [Brand] * tags: [Brand]
* summary: List brands * summary: List brands
* description: Lists brands for the authenticated user's selected company, sorted by name. * description: Lists brands for the authenticated user's selected company, sorted by name. Paged; `total` is the unpaged count.
* security: * security:
* - cookieAuth: [] * - cookieAuth: []
* parameters:
* - in: query
* name: offset
* schema:
* type: integer
* default: 0
* minimum: 0
* description: Number of brands to skip
* - in: query
* name: limit
* schema:
* type: integer
* default: 10
* minimum: 1
* maximum: 100
* description: Number of brands to return
* x-markdown: brand/list.md * x-markdown: brand/list.md
* responses: * responses:
* 200: * 200:
@@ -56,13 +74,23 @@ export function register(app, basePath = '') {
* application/json: * application/json:
* schema: * schema:
* type: object * type: object
* required: [brands, total, offset, limit]
* properties: * properties:
* brands: * brands:
* type: array * type: array
* items: * items:
* $ref: '#/components/schemas/Brand' * $ref: '#/components/schemas/Brand'
* total:
* type: integer
* description: Total number of unpaged brands
* offset:
* type: integer
* description: Number of brands skipped
* limit:
* type: integer
* description: Number of brands returned
* 400: * 400:
* description: No company selected * description: Invalid offset, invalid limit, or no company selected
* content: * content:
* application/json: * application/json:
* schema: * schema:
@@ -92,9 +120,29 @@ export function register(app, basePath = '') {
return res.status(400).json({ error: selected.error }); return res.status(400).json({ error: selected.error });
} }
const rawOffset = req.query.offset;
const rawLimit = req.query.limit;
let offset = 0;
let limit = 10;
if (rawOffset !== undefined) {
offset = parseInt(rawOffset, 10);
if (!Number.isInteger(offset) || offset < 0) {
return res.status(400).json({ error: 'offset must be an integer >= 0' });
}
}
if (rawLimit !== undefined) {
limit = parseInt(rawLimit, 10);
if (!Number.isInteger(limit) || limit < 1 || limit > 100) {
return res.status(400).json({ error: 'limit must be an integer between 1 and 100' });
}
}
try { try {
const brands = await db.list(req.user.id); const result = await db.list(req.user.id, { offset, limit });
res.status(200).json({ brands }); res.status(200).json(result);
} catch (error) { } catch (error) {
const status = brandErrorStatus(error); const status = brandErrorStatus(error);
if (status === 500) console.error('List brands failed:', error); if (status === 500) console.error('List brands failed:', error);

View File

@@ -1,8 +1,8 @@
import { getStore } from './store.js'; import { getStore } from './store.js';
export async function list(googleAuthId) { export async function list(googleAuthId, opts) {
const store = await getStore(); const store = await getStore();
return store.brand.list(googleAuthId); return store.brand.list(googleAuthId, opts);
} }
export async function create(googleAuthId, data) { export async function create(googleAuthId, data) {

View File

@@ -360,9 +360,9 @@ export async function executeCompanyImport({
log.info(`Processing ${brandEntries.length} brands (Hersteller)...`); log.info(`Processing ${brandEntries.length} brands (Hersteller)...`);
// Fetch existing brands to accurately track new vs existing // Fetch existing brands to accurately track new vs existing
const existingBrands = await store.brand.list(googleAuthId); const { brands: existingBrandRows } = await store.brand.list(googleAuthId, { offset: 0, limit: 100 });
const existingBrandNames = new Set( const existingBrandNames = new Set(
existingBrands.map((b) => (b.name || '').trim().toLowerCase()).filter(Boolean) existingBrandRows.map((b) => (b.name || '').trim().toLowerCase()).filter(Boolean)
); );
for (let i = 0; i < brandEntries.length; i++) { for (let i = 0; i < brandEntries.length; i++) {