u
This commit is contained in:
@@ -41,7 +41,11 @@ Generated from `@openapi` annotations in [`src/api/routes/`](../../src/api/route
|
|||||||
| [`routes/article/_sku/attributevalue.put.md`](routes/article/_sku/attributevalue.put.md) | `PUT /article/{sku}/attributevalue` |
|
| [`routes/article/_sku/attributevalue.put.md`](routes/article/_sku/attributevalue.put.md) | `PUT /article/{sku}/attributevalue` |
|
||||||
| [`routes/article/set-brand.md`](routes/article/set-brand.md) | `PUT /article/{sku}/brand` |
|
| [`routes/article/set-brand.md`](routes/article/set-brand.md) | `PUT /article/{sku}/brand` |
|
||||||
| [`routes/article/set-categories.md`](routes/article/set-categories.md) | `PUT /article/{sku}/categories` |
|
| [`routes/article/set-categories.md`](routes/article/set-categories.md) | `PUT /article/{sku}/categories` |
|
||||||
|
| [`routes/article/_sku/children.get.md`](routes/article/_sku/children.get.md) | `GET /article/{sku}/children` |
|
||||||
|
| [`routes/article/_sku/children.post.md`](routes/article/_sku/children.post.md) | `POST /article/{sku}/children` |
|
||||||
|
| [`routes/article/_sku/children/_childSku.md`](routes/article/_sku/children/_childSku.md) | `DELETE /article/{sku}/children/{childSku}` |
|
||||||
| [`routes/article/set-eans.md`](routes/article/set-eans.md) | `PUT /article/{sku}/eans` |
|
| [`routes/article/set-eans.md`](routes/article/set-eans.md) | `PUT /article/{sku}/eans` |
|
||||||
|
| [`routes/article/_sku/father.md`](routes/article/_sku/father.md) | `POST /article/{sku}/father` |
|
||||||
| [`routes/article/history.md`](routes/article/history.md) | `GET /article/{sku}/history` |
|
| [`routes/article/history.md`](routes/article/history.md) | `GET /article/{sku}/history` |
|
||||||
| [`routes/article/add-image.md`](routes/article/add-image.md) | `POST /article/{sku}/image` |
|
| [`routes/article/add-image.md`](routes/article/add-image.md) | `POST /article/{sku}/image` |
|
||||||
| [`routes/article/delete-image.md`](routes/article/delete-image.md) | `DELETE /article/{sku}/image/{fullHash}` |
|
| [`routes/article/delete-image.md`](routes/article/delete-image.md) | `DELETE /article/{sku}/image/{fullHash}` |
|
||||||
|
|||||||
@@ -12676,6 +12676,277 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/article/{sku}/father": {
|
||||||
|
"post": {
|
||||||
|
"summary": "Toggle father mode for an article",
|
||||||
|
"description": "Enables or disables father article status. Enabling requires specifying an attributeNameId; disabling requires the article to have zero children.",
|
||||||
|
"tags": [
|
||||||
|
"Article"
|
||||||
|
],
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"cookieAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "sku",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"description": "Article SKU"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"required": true,
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"isFather"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"isFather": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "True to make article a father, false to revert to regular article"
|
||||||
|
},
|
||||||
|
"attributeNameId": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Required when isFather is true. The attributename id for variants."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Updated article",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"article": {
|
||||||
|
"$ref": "#/components/schemas/Article"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Invalid input or article still has children"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Article or attribute name not found"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/article/{sku}/children": {
|
||||||
|
"get": {
|
||||||
|
"summary": "List child articles of a father article",
|
||||||
|
"description": "Returns variants/children linked to this father article.",
|
||||||
|
"tags": [
|
||||||
|
"Article"
|
||||||
|
],
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"cookieAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "sku",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"description": "Father article SKU"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "List of children",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"children": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"sku": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"fathersort": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"attributeValueId": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"attributeValue": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Article not found"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"summary": "Add a child article to a father article",
|
||||||
|
"description": "Automatically generates SKU as fatherSku-attributeValueId and assigns the variant attribute.",
|
||||||
|
"tags": [
|
||||||
|
"Article"
|
||||||
|
],
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"cookieAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "sku",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"description": "Father article SKU"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"required": true,
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"attributeValueId": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "ID of existing attribute value for the father's attribute"
|
||||||
|
},
|
||||||
|
"value": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "String value to find or create under the father's attribute"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Optional custom variant name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"201": {
|
||||||
|
"description": "Created child article",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"article": {
|
||||||
|
"$ref": "#/components/schemas/Article"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Father not configured as father or missing value"
|
||||||
|
},
|
||||||
|
"409": {
|
||||||
|
"description": "Child SKU already exists"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/article/{sku}/children/{childSku}": {
|
||||||
|
"delete": {
|
||||||
|
"summary": "Remove a child article from a father article",
|
||||||
|
"description": "Unlinks the child from the father (or deletes if deleteArticle query/body is true).",
|
||||||
|
"tags": [
|
||||||
|
"Article"
|
||||||
|
],
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"cookieAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "sku",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"description": "Father article SKU"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "childSku",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"description": "Child article SKU"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"in": "query",
|
||||||
|
"name": "deleteArticle",
|
||||||
|
"schema": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"description": "If true, permanently deletes the child article instead of just unlinking"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Child removed",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"success": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"deleted": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/auth/selected-company": {
|
"/auth/selected-company": {
|
||||||
"put": {
|
"put": {
|
||||||
"tags": [
|
"tags": [
|
||||||
|
|||||||
42
docs/api/routes/article/_sku/children.get.md
Normal file
42
docs/api/routes/article/_sku/children.get.md
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
# `GET /article/{sku}/children`
|
||||||
|
|
||||||
|
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||||
|
|
||||||
|
List child articles of a father article
|
||||||
|
|
||||||
|
Returns variants/children linked to this father article.
|
||||||
|
|
||||||
|
## Path parameters
|
||||||
|
|
||||||
|
| Param | Required | Type | Description |
|
||||||
|
|-------|----------|------|-------------|
|
||||||
|
| `sku` | yes | string | Father article SKU |
|
||||||
|
|
||||||
|
## Response `200`
|
||||||
|
|
||||||
|
List of children
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"sku": "…",
|
||||||
|
"name": "…",
|
||||||
|
"fathersort": 1,
|
||||||
|
"attributeValueId": 1,
|
||||||
|
"attributeValue": "…"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Errors
|
||||||
|
|
||||||
|
| Status | Description |
|
||||||
|
|--------|-------------|
|
||||||
|
| 404 | Article not found |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||||
44
docs/api/routes/article/_sku/children.post.md
Normal file
44
docs/api/routes/article/_sku/children.post.md
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
# `POST /article/{sku}/children`
|
||||||
|
|
||||||
|
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||||
|
|
||||||
|
Add a child article to a father article
|
||||||
|
|
||||||
|
Automatically generates SKU as fatherSku-attributeValueId and assigns the variant attribute.
|
||||||
|
|
||||||
|
## Path parameters
|
||||||
|
|
||||||
|
| Param | Required | Type | Description |
|
||||||
|
|-------|----------|------|-------------|
|
||||||
|
| `sku` | yes | string | Father article SKU |
|
||||||
|
|
||||||
|
## Body (JSON)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"attributeValueId": 1,
|
||||||
|
"value": "…",
|
||||||
|
"name": "…"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Response `201`
|
||||||
|
|
||||||
|
Created child article
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"article": {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Errors
|
||||||
|
|
||||||
|
| Status | Description |
|
||||||
|
|--------|-------------|
|
||||||
|
| 400 | Father not configured as father or missing value |
|
||||||
|
| 409 | Child SKU already exists |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||||
35
docs/api/routes/article/_sku/children/_childSku.md
Normal file
35
docs/api/routes/article/_sku/children/_childSku.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# `DELETE /article/{sku}/children/{childSku}`
|
||||||
|
|
||||||
|
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||||
|
|
||||||
|
Remove a child article from a father article
|
||||||
|
|
||||||
|
Unlinks the child from the father (or deletes if deleteArticle query/body is true).
|
||||||
|
|
||||||
|
## Path parameters
|
||||||
|
|
||||||
|
| Param | Required | Type | Description |
|
||||||
|
|-------|----------|------|-------------|
|
||||||
|
| `sku` | yes | string | Father article SKU |
|
||||||
|
| `childSku` | yes | string | Child article SKU |
|
||||||
|
|
||||||
|
## Query parameters
|
||||||
|
|
||||||
|
| Param | Required | Type | Description |
|
||||||
|
|-------|----------|------|-------------|
|
||||||
|
| `deleteArticle` | no | boolean | If true, permanently deletes the child article instead of just unlinking |
|
||||||
|
|
||||||
|
## Response `200`
|
||||||
|
|
||||||
|
Child removed
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"deleted": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||||
43
docs/api/routes/article/_sku/father.md
Normal file
43
docs/api/routes/article/_sku/father.md
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# `POST /article/{sku}/father`
|
||||||
|
|
||||||
|
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||||
|
|
||||||
|
Toggle father mode for an article
|
||||||
|
|
||||||
|
Enables or disables father article status. Enabling requires specifying an attributeNameId; disabling requires the article to have zero children.
|
||||||
|
|
||||||
|
## Path parameters
|
||||||
|
|
||||||
|
| Param | Required | Type | Description |
|
||||||
|
|-------|----------|------|-------------|
|
||||||
|
| `sku` | yes | string | Article SKU |
|
||||||
|
|
||||||
|
## Body (JSON)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"isFather": true,
|
||||||
|
"attributeNameId": 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Response `200`
|
||||||
|
|
||||||
|
Updated article
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"article": {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Errors
|
||||||
|
|
||||||
|
| Status | Description |
|
||||||
|
|--------|-------------|
|
||||||
|
| 400 | Invalid input or article still has children |
|
||||||
|
| 404 | Article or attribute name not found |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||||
@@ -69,6 +69,15 @@ function articleErrorStatus(error) {
|
|||||||
if (error.message === 'Invalid weight') return 400;
|
if (error.message === 'Invalid weight') return 400;
|
||||||
if (error.message === 'Invalid track_stock') return 400;
|
if (error.message === 'Invalid track_stock') return 400;
|
||||||
if (error.message === 'Invalid categoryIds') return 400;
|
if (error.message === 'Invalid categoryIds') return 400;
|
||||||
|
if (error.message === 'Attribute name not found') return 404;
|
||||||
|
if (error.message === 'attributeNameId is required to become a father article') return 400;
|
||||||
|
if (error.message === 'A child article cannot become a father') return 400;
|
||||||
|
if (error.message === 'Cannot disable father mode on an article that still has children') return 400;
|
||||||
|
if (error.message === 'Article is not a father article') return 400;
|
||||||
|
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 === 'Father article not found') return 404;
|
||||||
if (error.message?.includes('already exists') || error.code === 'SQLITE_CONSTRAINT_UNIQUE') return 409;
|
if (error.message?.includes('already exists') || error.code === 'SQLITE_CONSTRAINT_UNIQUE') return 409;
|
||||||
return 500;
|
return 500;
|
||||||
}
|
}
|
||||||
@@ -1659,4 +1668,267 @@ export function register(app, basePath = '') {
|
|||||||
res.status(500).json({ error: error.message });
|
res.status(500).json({ error: error.message });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /article/{sku}/father:
|
||||||
|
* post:
|
||||||
|
* summary: Toggle father mode for an article
|
||||||
|
* description: Enables or disables father article status. Enabling requires specifying an attributeNameId; disabling requires the article to have zero children.
|
||||||
|
* tags:
|
||||||
|
* - Article
|
||||||
|
* security:
|
||||||
|
* - cookieAuth: []
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: sku
|
||||||
|
* required: true
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* description: Article SKU
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* required: [isFather]
|
||||||
|
* properties:
|
||||||
|
* isFather:
|
||||||
|
* type: boolean
|
||||||
|
* description: True to make article a father, false to revert to regular article
|
||||||
|
* attributeNameId:
|
||||||
|
* type: integer
|
||||||
|
* description: Required when isFather is true. The attributename id for variants.
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Updated article
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* article:
|
||||||
|
* $ref: '#/components/schemas/Article'
|
||||||
|
* 400:
|
||||||
|
* description: Invalid input or article still has children
|
||||||
|
* 404:
|
||||||
|
* description: Article or attribute name not found
|
||||||
|
*/
|
||||||
|
app.post(`${basePath}/article/:sku/father`, async (req, res) => {
|
||||||
|
const parsed = parseSku(req.params.sku);
|
||||||
|
if (parsed.error) return res.status(400).json({ error: parsed.error });
|
||||||
|
|
||||||
|
const isFather = req.body?.isFather;
|
||||||
|
if (typeof isFather !== 'boolean') {
|
||||||
|
return res.status(400).json({ error: 'isFather boolean is required' });
|
||||||
|
}
|
||||||
|
const attributeNameId = req.body?.attributeNameId ?? req.body?.fatherAttributeNameId;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await db.toggleFather(req.user.id, parsed.sku, {
|
||||||
|
isFather,
|
||||||
|
attributeNameId,
|
||||||
|
});
|
||||||
|
emitArticleSignal(req, parsed.sku);
|
||||||
|
emitArticlesSignal(req);
|
||||||
|
res.status(200).json(result);
|
||||||
|
} catch (error) {
|
||||||
|
const status = articleErrorStatus(error);
|
||||||
|
if (status === 500) console.error('Toggle father failed:', error);
|
||||||
|
res.status(status).json({ error: error.message });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /article/{sku}/children:
|
||||||
|
* get:
|
||||||
|
* summary: List child articles of a father article
|
||||||
|
* description: Returns variants/children linked to this father article.
|
||||||
|
* tags:
|
||||||
|
* - Article
|
||||||
|
* security:
|
||||||
|
* - cookieAuth: []
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: sku
|
||||||
|
* required: true
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* description: Father article SKU
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: List of children
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* children:
|
||||||
|
* type: array
|
||||||
|
* items:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* id:
|
||||||
|
* type: integer
|
||||||
|
* sku:
|
||||||
|
* type: string
|
||||||
|
* name:
|
||||||
|
* type: string
|
||||||
|
* fathersort:
|
||||||
|
* type: integer
|
||||||
|
* attributeValueId:
|
||||||
|
* type: integer
|
||||||
|
* attributeValue:
|
||||||
|
* type: string
|
||||||
|
* 404:
|
||||||
|
* description: Article not found
|
||||||
|
*/
|
||||||
|
app.get(`${basePath}/article/:sku/children`, async (req, res) => {
|
||||||
|
const parsed = parseSku(req.params.sku);
|
||||||
|
if (parsed.error) return res.status(400).json({ error: parsed.error });
|
||||||
|
|
||||||
|
try {
|
||||||
|
const children = await db.listChildren(req.user.id, parsed.sku);
|
||||||
|
res.status(200).json({ children });
|
||||||
|
} catch (error) {
|
||||||
|
const status = articleErrorStatus(error);
|
||||||
|
if (status === 500) console.error('List children failed:', error);
|
||||||
|
res.status(status).json({ error: error.message });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /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.
|
||||||
|
* tags:
|
||||||
|
* - Article
|
||||||
|
* security:
|
||||||
|
* - cookieAuth: []
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: sku
|
||||||
|
* required: true
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* description: Father article SKU
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* attributeValueId:
|
||||||
|
* type: integer
|
||||||
|
* description: ID of existing attribute value for the father's attribute
|
||||||
|
* value:
|
||||||
|
* type: string
|
||||||
|
* description: String value to find or create under the father's attribute
|
||||||
|
* name:
|
||||||
|
* type: string
|
||||||
|
* description: Optional custom variant name
|
||||||
|
* responses:
|
||||||
|
* 201:
|
||||||
|
* description: Created child article
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* article:
|
||||||
|
* $ref: '#/components/schemas/Article'
|
||||||
|
* 400:
|
||||||
|
* description: Father not configured as father or missing value
|
||||||
|
* 409:
|
||||||
|
* description: Child SKU already exists
|
||||||
|
*/
|
||||||
|
app.post(`${basePath}/article/:sku/children`, async (req, res) => {
|
||||||
|
const parsed = parseSku(req.params.sku);
|
||||||
|
if (parsed.error) return res.status(400).json({ error: parsed.error });
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await db.addChild(req.user.id, parsed.sku, req.body || {});
|
||||||
|
emitArticleSignal(req, parsed.sku);
|
||||||
|
if (result?.article?.sku) {
|
||||||
|
emitArticleSignal(req, result.article.sku);
|
||||||
|
}
|
||||||
|
emitArticlesSignal(req);
|
||||||
|
res.status(201).json(result);
|
||||||
|
} catch (error) {
|
||||||
|
const status = articleErrorStatus(error);
|
||||||
|
if (status === 500) console.error('Add child failed:', error);
|
||||||
|
res.status(status).json({ error: error.message });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /article/{sku}/children/{childSku}:
|
||||||
|
* delete:
|
||||||
|
* summary: Remove a child article from a father article
|
||||||
|
* description: Unlinks the child from the father (or deletes if deleteArticle query/body is true).
|
||||||
|
* tags:
|
||||||
|
* - Article
|
||||||
|
* security:
|
||||||
|
* - cookieAuth: []
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: sku
|
||||||
|
* required: true
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* description: Father article SKU
|
||||||
|
* - in: path
|
||||||
|
* name: childSku
|
||||||
|
* required: true
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* description: Child article SKU
|
||||||
|
* - in: query
|
||||||
|
* name: deleteArticle
|
||||||
|
* schema:
|
||||||
|
* type: boolean
|
||||||
|
* description: If true, permanently deletes the child article instead of just unlinking
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Child removed
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* success:
|
||||||
|
* type: boolean
|
||||||
|
* deleted:
|
||||||
|
* type: boolean
|
||||||
|
*/
|
||||||
|
app.delete(`${basePath}/article/:sku/children/:childSku`, async (req, res) => {
|
||||||
|
const parsed = parseSku(req.params.sku);
|
||||||
|
if (parsed.error) return res.status(400).json({ error: parsed.error });
|
||||||
|
|
||||||
|
const parsedChild = parseSku(req.params.childSku);
|
||||||
|
if (parsedChild.error) return res.status(400).json({ error: 'childSku is required' });
|
||||||
|
|
||||||
|
const deleteArticle = req.query.deleteArticle === 'true' || req.body?.deleteArticle === true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await db.removeChild(req.user.id, parsed.sku, parsedChild.sku, {
|
||||||
|
deleteArticle,
|
||||||
|
});
|
||||||
|
emitArticleSignal(req, parsed.sku);
|
||||||
|
emitArticleSignal(req, parsedChild.sku);
|
||||||
|
emitArticlesSignal(req);
|
||||||
|
res.status(200).json(result);
|
||||||
|
} catch (error) {
|
||||||
|
const status = articleErrorStatus(error);
|
||||||
|
if (status === 500) console.error('Remove child failed:', error);
|
||||||
|
res.status(status).json({ error: error.message });
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -79,3 +79,24 @@ export async function listExport(googleAuthId, categoryId) {
|
|||||||
const store = await getStore();
|
const store = await getStore();
|
||||||
return store.article.listExport(googleAuthId, categoryId);
|
return store.article.listExport(googleAuthId, categoryId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function toggleFather(googleAuthId, sku, options) {
|
||||||
|
const store = await getStore();
|
||||||
|
return store.article.toggleFather(googleAuthId, sku, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function addChild(googleAuthId, sku, options) {
|
||||||
|
const store = await getStore();
|
||||||
|
return store.article.addChild(googleAuthId, sku, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function removeChild(googleAuthId, sku, childSku, options) {
|
||||||
|
const store = await getStore();
|
||||||
|
return store.article.removeChild(googleAuthId, sku, childSku, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function listChildren(googleAuthId, sku) {
|
||||||
|
const store = await getStore();
|
||||||
|
return store.article.listChildren(googleAuthId, sku);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user