|
|
|
|
@@ -79,24 +79,24 @@ function articleErrorStatus(error) {
|
|
|
|
|
if (error.message === 'Invalid track_stock') 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?.includes('already used by an ancestor father')) return 400;
|
|
|
|
|
if (error.message === 'attributeNameId is required to become a parent article') return 400;
|
|
|
|
|
if (error.message?.includes('already used by an ancestor parent')) return 400;
|
|
|
|
|
if (error.message?.includes('cannot have attribute values for its variant attribute')) return 400;
|
|
|
|
|
if (error.message?.includes('A father article cannot have') || error.message?.includes('father article cannot have')) 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?.includes('A parent article cannot have') || error.message?.includes('parent article cannot have')) return 400;
|
|
|
|
|
if (error.message === 'Cannot disable parent mode on an article that still has children') return 400;
|
|
|
|
|
if (error.message === 'Article is not a parent 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 === 'Article already belongs to another father') return 409;
|
|
|
|
|
if (error.message === 'Attribute value not found or does not match parent attribute') return 400;
|
|
|
|
|
if (error.message === 'Child article does not belong to this parent') return 400;
|
|
|
|
|
if (error.message === 'Article already belongs to another parent') return 409;
|
|
|
|
|
if (error.message?.includes('sku is not allowed when creating a child article')) return 400;
|
|
|
|
|
if (error.message === 'sku is required' || error.message?.includes('sku is required')) return 400;
|
|
|
|
|
if (error.message === 'Article is already connected to a father article') return 400;
|
|
|
|
|
if (error.message === 'Article is already connected to a parent article') return 400;
|
|
|
|
|
if (error.message === 'An article cannot be a child of itself') 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 === 'Parent article not found') return 404;
|
|
|
|
|
if (
|
|
|
|
|
error.message?.includes('Stückliste') ||
|
|
|
|
|
error.message?.toLowerCase().includes('option') ||
|
|
|
|
|
@@ -766,7 +766,7 @@ export function register(app, basePath = '') {
|
|
|
|
|
* article:
|
|
|
|
|
* $ref: '#/components/schemas/ArticleDetail'
|
|
|
|
|
* 400:
|
|
|
|
|
* description: Invalid prices, POS customer group required, or father article cannot have prices
|
|
|
|
|
* description: Invalid prices, POS customer group required, or parent article cannot have prices
|
|
|
|
|
* content:
|
|
|
|
|
* application/json:
|
|
|
|
|
* schema:
|
|
|
|
|
@@ -1803,18 +1803,18 @@ export function register(app, basePath = '') {
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @openapi
|
|
|
|
|
* /article/{sku}/father:
|
|
|
|
|
* /article/{sku}/parent:
|
|
|
|
|
* post:
|
|
|
|
|
* summary: Toggle father mode for an article
|
|
|
|
|
* summary: Toggle parent mode for an article
|
|
|
|
|
* description: |
|
|
|
|
|
* Enables or disables father article status. Enabling requires specifying an
|
|
|
|
|
* Enables or disables parent article status. Enabling requires specifying an
|
|
|
|
|
* attributeNameId; disabling requires the article to have zero children.
|
|
|
|
|
*
|
|
|
|
|
* `attributeNameId` is **conditionally required**: it is optional in the schema
|
|
|
|
|
* because it is only required when `isFather` is `true`. Omitting it (or passing
|
|
|
|
|
* `0`/a negative value) together with `isFather: true` returns `400`
|
|
|
|
|
* `attributeNameId is required to become a father article`. It must not be sent
|
|
|
|
|
* when `isFather` is `false`.
|
|
|
|
|
* because it is only required when `isParent` is `true`. Omitting it (or passing
|
|
|
|
|
* `0`/a negative value) together with `isParent: true` returns `400`
|
|
|
|
|
* `attributeNameId is required to become a parent article`. It must not be sent
|
|
|
|
|
* when `isParent` is `false`.
|
|
|
|
|
* tags:
|
|
|
|
|
* - Article
|
|
|
|
|
* security:
|
|
|
|
|
@@ -1832,17 +1832,17 @@ export function register(app, basePath = '') {
|
|
|
|
|
* application/json:
|
|
|
|
|
* schema:
|
|
|
|
|
* type: object
|
|
|
|
|
* required: [isFather]
|
|
|
|
|
* required: [isParent]
|
|
|
|
|
* properties:
|
|
|
|
|
* isFather:
|
|
|
|
|
* isParent:
|
|
|
|
|
* type: boolean
|
|
|
|
|
* description: True to make article a father, false to revert to regular article
|
|
|
|
|
* description: True to make article a parent, false to revert to regular article
|
|
|
|
|
* attributeNameId:
|
|
|
|
|
* type: integer
|
|
|
|
|
* description: |
|
|
|
|
|
* **Conditionally required when `isFather` is `true`** (required iff isFather=true).
|
|
|
|
|
* **Conditionally required when `isParent` is `true`** (required iff isParent=true).
|
|
|
|
|
* The attributename id used for the article's variants. Omitting it while
|
|
|
|
|
* enabling father mode returns 400. Must be omitted when `isFather` is `false`.
|
|
|
|
|
* enabling parent mode returns 400. Must be omitted when `isParent` is `false`.
|
|
|
|
|
* responses:
|
|
|
|
|
* 200:
|
|
|
|
|
* description: Updated article
|
|
|
|
|
@@ -1855,25 +1855,25 @@ export function register(app, basePath = '') {
|
|
|
|
|
* $ref: '#/components/schemas/Article'
|
|
|
|
|
* 400:
|
|
|
|
|
* description: |
|
|
|
|
|
* Invalid input, `attributeNameId` missing while `isFather` is true, article still
|
|
|
|
|
* Invalid input, `attributeNameId` missing while `isParent` is true, article still
|
|
|
|
|
* has children, article has stock/suppliers/a Stückliste/options, or the attribute is
|
|
|
|
|
* already used by an ancestor father article.
|
|
|
|
|
* already used by an ancestor parent article.
|
|
|
|
|
* 404:
|
|
|
|
|
* description: Article or attribute name not found
|
|
|
|
|
*/
|
|
|
|
|
app.post(`${basePath}/article/:sku/father`, async (req, res) => {
|
|
|
|
|
app.post(`${basePath}/article/:sku/parent`, 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 isParent = req.body?.isParent;
|
|
|
|
|
if (typeof isParent !== 'boolean') {
|
|
|
|
|
return res.status(400).json({ error: 'isParent boolean is required' });
|
|
|
|
|
}
|
|
|
|
|
const attributeNameId = req.body?.attributeNameId ?? req.body?.fatherAttributeNameId;
|
|
|
|
|
const attributeNameId = req.body?.attributeNameId ?? req.body?.parentAttributeNameId;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const result = await db.toggleFather(req.user.id, parsed.sku, {
|
|
|
|
|
isFather,
|
|
|
|
|
const result = await db.toggleParent(req.user.id, parsed.sku, {
|
|
|
|
|
isParent,
|
|
|
|
|
attributeNameId,
|
|
|
|
|
});
|
|
|
|
|
emitArticleSignal(req, parsed.sku);
|
|
|
|
|
@@ -1881,7 +1881,7 @@ export function register(app, basePath = '') {
|
|
|
|
|
res.status(200).json(result);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
const status = articleErrorStatus(error);
|
|
|
|
|
if (status === 500) console.error('Toggle father failed:', error);
|
|
|
|
|
if (status === 500) console.error('Toggle parent failed:', error);
|
|
|
|
|
res.status(status).json({ error: error.message });
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
@@ -1890,8 +1890,8 @@ export function register(app, basePath = '') {
|
|
|
|
|
* @openapi
|
|
|
|
|
* /article/{sku}/children:
|
|
|
|
|
* get:
|
|
|
|
|
* summary: List child articles of a father article
|
|
|
|
|
* description: Returns variants/children linked to this father article.
|
|
|
|
|
* summary: List child articles of a parent article
|
|
|
|
|
* description: Returns variants/children linked to this parent article.
|
|
|
|
|
* tags:
|
|
|
|
|
* - Article
|
|
|
|
|
* security:
|
|
|
|
|
@@ -1902,7 +1902,7 @@ export function register(app, basePath = '') {
|
|
|
|
|
* required: true
|
|
|
|
|
* schema:
|
|
|
|
|
* type: string
|
|
|
|
|
* description: Father article SKU
|
|
|
|
|
* description: Parent article SKU
|
|
|
|
|
* responses:
|
|
|
|
|
* 200:
|
|
|
|
|
* description: List of children
|
|
|
|
|
@@ -1922,7 +1922,7 @@ export function register(app, basePath = '') {
|
|
|
|
|
* type: string
|
|
|
|
|
* name:
|
|
|
|
|
* type: string
|
|
|
|
|
* fathersort:
|
|
|
|
|
* parentsort:
|
|
|
|
|
* type: integer
|
|
|
|
|
* attributeValueId:
|
|
|
|
|
* type: integer
|
|
|
|
|
@@ -1949,8 +1949,8 @@ export function register(app, basePath = '') {
|
|
|
|
|
* @openapi
|
|
|
|
|
* /article/{sku}/children:
|
|
|
|
|
* post:
|
|
|
|
|
* summary: Create and attach a new child article to a father article
|
|
|
|
|
* description: Automatically generates SKU as fatherSku-nextFreeIndex and name from father name + value. Rejects a caller-supplied sku.
|
|
|
|
|
* summary: Create and attach a new child article to a parent article
|
|
|
|
|
* description: Automatically generates SKU as parentSku-nextFreeIndex and name from parent name + value. Rejects a caller-supplied sku.
|
|
|
|
|
* tags:
|
|
|
|
|
* - Article
|
|
|
|
|
* security:
|
|
|
|
|
@@ -1961,7 +1961,7 @@ export function register(app, basePath = '') {
|
|
|
|
|
* required: true
|
|
|
|
|
* schema:
|
|
|
|
|
* type: string
|
|
|
|
|
* description: Father article SKU
|
|
|
|
|
* description: Parent article SKU
|
|
|
|
|
* requestBody:
|
|
|
|
|
* required: true
|
|
|
|
|
* content:
|
|
|
|
|
@@ -1971,10 +1971,10 @@ export function register(app, basePath = '') {
|
|
|
|
|
* properties:
|
|
|
|
|
* attributeValueId:
|
|
|
|
|
* type: integer
|
|
|
|
|
* description: ID of existing attribute value for the father's attribute
|
|
|
|
|
* description: ID of existing attribute value for the parent's attribute
|
|
|
|
|
* value:
|
|
|
|
|
* type: string
|
|
|
|
|
* description: String value to find or create under the father's attribute
|
|
|
|
|
* description: String value to find or create under the parent's attribute
|
|
|
|
|
* name:
|
|
|
|
|
* type: string
|
|
|
|
|
* description: Optional custom variant name
|
|
|
|
|
@@ -1989,10 +1989,10 @@ export function register(app, basePath = '') {
|
|
|
|
|
* article:
|
|
|
|
|
* $ref: '#/components/schemas/Article'
|
|
|
|
|
* 400:
|
|
|
|
|
* description: Father not configured as father, missing value, duplicate variant, or sku was provided in body
|
|
|
|
|
* description: Parent not configured as parent, missing value, duplicate variant, or sku was provided in body
|
|
|
|
|
* put:
|
|
|
|
|
* summary: Attach an existing article as a child to a father article
|
|
|
|
|
* description: Attaches an existing article to this father article. Idempotent if already a child. Returns 409 if the article already belongs to another father.
|
|
|
|
|
* summary: Attach an existing article as a child to a parent article
|
|
|
|
|
* description: Attaches an existing article to this parent article. Idempotent if already a child. Returns 409 if the article already belongs to another parent.
|
|
|
|
|
* tags:
|
|
|
|
|
* - Article
|
|
|
|
|
* security:
|
|
|
|
|
@@ -2003,7 +2003,7 @@ export function register(app, basePath = '') {
|
|
|
|
|
* required: true
|
|
|
|
|
* schema:
|
|
|
|
|
* type: string
|
|
|
|
|
* description: Father article SKU
|
|
|
|
|
* description: Parent article SKU
|
|
|
|
|
* requestBody:
|
|
|
|
|
* required: true
|
|
|
|
|
* content:
|
|
|
|
|
@@ -2018,13 +2018,13 @@ export function register(app, basePath = '') {
|
|
|
|
|
* description: SKU of the existing article to attach as child
|
|
|
|
|
* attributeValueId:
|
|
|
|
|
* type: integer
|
|
|
|
|
* description: ID of existing attribute value for the father's attribute
|
|
|
|
|
* description: ID of existing attribute value for the parent's attribute
|
|
|
|
|
* value:
|
|
|
|
|
* type: string
|
|
|
|
|
* description: String value to find or create under the father's attribute
|
|
|
|
|
* description: String value to find or create under the parent's attribute
|
|
|
|
|
* reparent:
|
|
|
|
|
* type: boolean
|
|
|
|
|
* description: Whether to allow re-parenting if child already belongs to another father
|
|
|
|
|
* description: Whether to allow re-parenting if child already belongs to another parent
|
|
|
|
|
* responses:
|
|
|
|
|
* 200:
|
|
|
|
|
* description: Attached child article and list of children
|
|
|
|
|
@@ -2042,9 +2042,9 @@ export function register(app, basePath = '') {
|
|
|
|
|
* 400:
|
|
|
|
|
* description: Missing sku or attribute value, or invalid input
|
|
|
|
|
* 404:
|
|
|
|
|
* description: Father or child article not found
|
|
|
|
|
* description: Parent or child article not found
|
|
|
|
|
* 409:
|
|
|
|
|
* description: Article already belongs to another father, or variant value already exists
|
|
|
|
|
* description: Article already belongs to another parent, or variant value already exists
|
|
|
|
|
*/
|
|
|
|
|
app.post(`${basePath}/article/:sku/children`, async (req, res) => {
|
|
|
|
|
const parsed = parseSku(req.params.sku);
|
|
|
|
|
@@ -2099,8 +2099,8 @@ export function register(app, basePath = '') {
|
|
|
|
|
* @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).
|
|
|
|
|
* summary: Remove a child article from a parent article
|
|
|
|
|
* description: Unlinks the child from the parent (or deletes if deleteArticle query/body is true).
|
|
|
|
|
* tags:
|
|
|
|
|
* - Article
|
|
|
|
|
* security:
|
|
|
|
|
@@ -2111,7 +2111,7 @@ export function register(app, basePath = '') {
|
|
|
|
|
* required: true
|
|
|
|
|
* schema:
|
|
|
|
|
* type: string
|
|
|
|
|
* description: Father article SKU
|
|
|
|
|
* description: Parent article SKU
|
|
|
|
|
* - in: path
|
|
|
|
|
* name: childSku
|
|
|
|
|
* required: true
|
|
|
|
|
@@ -2122,7 +2122,7 @@ export function register(app, basePath = '') {
|
|
|
|
|
* name: deleteArticle
|
|
|
|
|
* schema:
|
|
|
|
|
* type: boolean
|
|
|
|
|
* description: If true, permanently deletes the child article (and cascades its entire descendant subtree if it is a father) instead of just unlinking
|
|
|
|
|
* description: If true, permanently deletes the child article (and cascades its entire descendant subtree if it is a parent) instead of just unlinking
|
|
|
|
|
* responses:
|
|
|
|
|
* 200:
|
|
|
|
|
* description: Child removed
|
|
|
|
|
@@ -2224,7 +2224,7 @@ export function register(app, basePath = '') {
|
|
|
|
|
* /article/{sku}/articlelist:
|
|
|
|
|
* put:
|
|
|
|
|
* summary: Set Stückliste (bundle items) for an article
|
|
|
|
|
* description: Configures the article as a Stückliste covering a list of count * article. A father article cannot be a Stückliste. Can be combined with options. Pass an empty array to remove the Stückliste.
|
|
|
|
|
* description: Configures the article as a Stückliste covering a list of count * article. A parent article cannot be a Stückliste. Can be combined with options. Pass an empty array to remove the Stückliste.
|
|
|
|
|
* tags:
|
|
|
|
|
* - Article
|
|
|
|
|
* security:
|
|
|
|
|
@@ -2271,7 +2271,7 @@ export function register(app, basePath = '') {
|
|
|
|
|
* items:
|
|
|
|
|
* type: object
|
|
|
|
|
* 400:
|
|
|
|
|
* description: Article is a father, has options, or contains itself
|
|
|
|
|
* description: Article is a parent, has options, or contains itself
|
|
|
|
|
* 404:
|
|
|
|
|
* description: Article or component article not found
|
|
|
|
|
*/
|
|
|
|
|
@@ -2362,7 +2362,7 @@ export function register(app, basePath = '') {
|
|
|
|
|
* /article/{sku}/optionslist:
|
|
|
|
|
* put:
|
|
|
|
|
* summary: Set options list for an article
|
|
|
|
|
* description: Configures options for an article. Some options can be mandated (come with the article in any case). A father article cannot have options. Can be combined with a Stückliste. Pass an empty array to remove options.
|
|
|
|
|
* description: Configures options for an article. Some options can be mandated (come with the article in any case). A parent article cannot have options. Can be combined with a Stückliste. Pass an empty array to remove options.
|
|
|
|
|
* tags:
|
|
|
|
|
* - Article
|
|
|
|
|
* security:
|
|
|
|
|
@@ -2412,7 +2412,7 @@ export function register(app, basePath = '') {
|
|
|
|
|
* items:
|
|
|
|
|
* type: object
|
|
|
|
|
* 400:
|
|
|
|
|
* description: Article is a father, a Stückliste, or contains itself
|
|
|
|
|
* description: Article is a parent, a Stückliste, or contains itself
|
|
|
|
|
* 404:
|
|
|
|
|
* description: Article or option article not found
|
|
|
|
|
*/
|
|
|
|
|
|