This commit is contained in:
seb
2026-10-01 10:19:16 +02:00
parent 956fadcc8d
commit 8a7500cb5a
11 changed files with 59 additions and 19 deletions

View File

@@ -88,6 +88,9 @@ function articleErrorStatus(error) {
if (error.message === 'Attribute value is required for child article' || error.message === 'Attribute value is required') return 400;
if (error.message === 'Attribute value not found or does not match father attribute') return 400;
if (error.message === 'Child article does not belong to this father') return 400;
if (error.message === 'Variant with this attribute value already exists') return 400;
if (error.message?.startsWith('Child article') && error.message?.includes('already exists')) return 400;
if (error.message?.toLowerCase().includes('duplicate variant')) return 400;
if (error.message === 'Father article not found') return 404;
if (
error.message?.includes('Stückliste') ||
@@ -553,6 +556,14 @@ export function register(app, basePath = '') {
* schema:
* type: string
* description: Article SKU
* - in: query
* name: limit
* required: false
* schema:
* type: integer
* minimum: 1
* maximum: 1000
* description: Maximum number of entries to return (newest first). Omit for all entries.
* responses:
* 200:
* description: Article history (newest first)
@@ -560,12 +571,15 @@ export function register(app, basePath = '') {
* application/json:
* schema:
* type: object
* required: [history]
* required: [history, truncated]
* properties:
* history:
* type: array
* items:
* $ref: '#/components/schemas/ArticleHistoryEntry'
* truncated:
* type: boolean
* description: True when a limit was applied and the result set was exactly that size (more entries may exist).
* example:
* history:
* - id: 42
@@ -605,9 +619,19 @@ export function register(app, basePath = '') {
return res.status(400).json({ error: 'sku is required' });
}
const rawLimit = req.query.limit;
let limit = null;
if (rawLimit !== undefined) {
limit = parseInt(rawLimit, 10);
if (!Number.isInteger(limit) || limit < 1 || limit > 1000) {
return res.status(400).json({ error: 'limit must be an integer between 1 and 1000' });
}
}
try {
const history = await db.getHistoryBySku(req.user.id, decodeURIComponent(sku));
res.status(200).json({ history });
const history = await db.getHistoryBySku(req.user.id, decodeURIComponent(sku), limit != null ? { limit } : undefined);
const truncated = limit != null && history.length === limit;
res.status(200).json({ history, truncated });
} catch (error) {
const status = articleErrorStatus(error);
if (status === 500) console.error('Get article history by sku failed:', error);
@@ -1868,7 +1892,7 @@ export function register(app, basePath = '') {
* /article/{sku}/children:
* post:
* summary: Add a child article to a father article
* description: Automatically generates SKU as fatherSku-attributeValueId and assigns the variant attribute.
* description: Automatically generates SKU as fatherSku-nextFreeIndex (or accepts custom sku) and assigns the variant attribute.
* tags:
* - Article
* security:
@@ -1896,6 +1920,9 @@ export function register(app, basePath = '') {
* name:
* type: string
* description: Optional custom variant name
* sku:
* type: string
* description: Optional custom SKU for the child article
* responses:
* 201:
* description: Created child article
@@ -1907,9 +1934,7 @@ export function register(app, basePath = '') {
* article:
* $ref: '#/components/schemas/Article'
* 400:
* description: Father not configured as father or missing value
* 409:
* description: Child SKU already exists
* description: Father not configured as father, missing value, duplicate variant, or child SKU already exists
*/
app.post(`${basePath}/article/:sku/children`, async (req, res) => {
const parsed = parseSku(req.params.sku);

View File

@@ -89,14 +89,19 @@ export function register(app, basePath = '') {
* properties:
* attributevalues:
* type: array
* description: Array of attribute value IDs (numbers) or objects with id or attributeValueId
* items:
* oneOf:
* - type: integer
* description: Attribute value ID
* - type: object
* required: [attributeValueId]
* properties:
* id:
* type: integer
* description: Attribute value ID
* attributeValueId:
* type: integer
* description: Attribute value ID
* sort:
* type: integer
* responses:
@@ -142,7 +147,7 @@ export function register(app, basePath = '') {
return res.status(400).json({ error: skuParsed.error });
}
const valuesInput = req.body?.attributevalues ?? req.body;
const valuesInput = req.body?.attributevalues ?? req.body?.attributeValues ?? req.body?.attribute_values ?? req.body?.values ?? req.body;
if (!Array.isArray(valuesInput)) {
return res.status(400).json({ error: 'attributevalues array required' });
}

View File

@@ -171,6 +171,7 @@ function deliveryErrorStatus(error) {
if (error.message === 'Invalid file') return 400;
if (error.message === 'Invalid JSON in "data" field') return 400;
if (error.message === 'Only PDF or text files are accepted as attachments') return 400;
if (error.message?.includes('father article') || error.message?.includes('A father article')) return 400;
return 500;
}

View File

@@ -18,6 +18,7 @@ function orderErrorStatus(error) {
if (error.message === 'Invalid entityId') return 400;
if (error.message === 'Invalid order') return 400;
if (error.message === 'Invalid lines') return 400;
if (error.message?.includes('father article') || error.message?.includes('A father article')) return 400;
return 500;
}

View File

@@ -18,6 +18,7 @@ function quoteErrorStatus(error) {
if (error.message === 'Invalid entityId') return 400;
if (error.message === 'Invalid quote') return 400;
if (error.message === 'Invalid lines') return 400;
if (error.message?.includes('father article') || error.message?.includes('A father article')) return 400;
return 500;
}

View File

@@ -20,7 +20,7 @@ function stockErrorStatus(error) {
if (error.message?.includes('Amount must be')) return 400;
if (error.message?.includes('Invalid amount')) return 400;
if (error.message === 'No items to adjust') return 400;
if (error.message?.includes('cannot have stock') || error.message?.includes('A father article cannot have') || error.message?.includes('father article')) return 400;
if (error.message?.includes('cannot have stock') || error.message?.includes('A father article cannot have') || error.message?.includes('father article') || error.message?.includes('Stückliste')) return 400;
return 500;
}